Docs
21.1-Security-Fundamentals
21.1 Security Fundamentals
Overview
Web security is critical for protecting users and data. This section covers the most common JavaScript security vulnerabilities and how to prevent them.
The Security Landscape
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Web Application Threats β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ β
β β Attacker β β
β ββββββββ¬ββββββββ β
β β β
β ββββββββββββββββββββββββΌβββββββββββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β XSS β β CSRF β β Injection β β
β β Cross-Site β β Request β β Attacks β β
β β Scripting β β Forgery β β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β β β
β ββββββββββββββββββββββββΌβββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββ β
β β Your Application β β
β β βββββββββββββββββββββββ β β
β β β User Data β β β
β β β Sessions β β β
β β β Credentials β β β
β β βββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Cross-Site Scripting (XSS)
XSS Attack Types
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β XSS Attack Types β
βββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Type β Description β
βββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Stored XSS β Malicious script stored in database, served to all users β
β β Example: Comment with <script> tag stored in forum β
βββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Reflected β Script in URL parameter reflected in page response β
β XSS β Example: Search query displayed without escaping β
βββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β DOM-based β Client-side script modifies DOM unsafely β
β XSS β Example: innerHTML with user input β
βββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
XSS Attack Flow
Stored XSS:
ββββββββββββ POST /comment ββββββββββββββββ
β Attacker β ββββββββββββββββββββΊ β Server β
β β <script>evil()</ β β
ββββββββββββ script> β Stores in β
β Database β
ββββββββ¬ββββββββ
β
βΌ
ββββββββββββ GET /comments ββββββββββββββββ
β Victim β ββββββββββββββββββββ β Server β
β β Returns page with β β
β Browser β malicious script ββββββββββββββββ
β executes β
β script! β
ββββββββββββ
XSS Prevention
// β VULNERABLE - Direct HTML insertion
element.innerHTML = userInput;
// β SAFE - Use textContent for text
element.textContent = userInput;
// β SAFE - Escape HTML entities
function escapeHTML(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
// β SAFE - Use DOM APIs
const link = document.createElement('a');
link.href = sanitizedUrl;
link.textContent = userText;
container.appendChild(link);
Cross-Site Request Forgery (CSRF)
CSRF Attack Flow
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CSRF Attack Flow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. User logs into Bank.com
ββββββββββββ βββββββββββββββ
β User β βββββββΊ β Bank.com β
β β βββββββ β (logged in) β
ββββββββββββ Cookie βββββββββββββββ
2. User visits malicious site
ββββββββββββ βββββββββββββββ
β User β βββββββΊ β Evil.com β
β β β Contains: β
ββββββββββββ β <img src= β
β "bank.com/ β
β transfer? β
β to=hacker β
β &amt=1000">β
ββββββββ¬βββββββ
β
3. Browser auto-sends cookie β
ββββββββββββ β βββββββββββββββ
β Browser β ββββββββββββββββββΊ β Bank.com β
β (victim) β GET /transfer?... β Thinks it's β
ββββββββββββ + session cookie β the user! β
βββββββββββββββ
CSRF Prevention
// Server generates CSRF token
const csrfToken = crypto.randomBytes(32).toString('hex');
// Store in session and embed in forms
// HTML Form
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="{{csrfToken}}">
<input type="text" name="amount">
<button>Transfer</button>
</form>
// Fetch with CSRF token
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({ amount: 100 })
});
// Server validation
function validateCSRF(req, res, next) {
const token = req.headers['x-csrf-token'] || req.body.csrf_token;
if (!token || token !== req.session.csrfToken) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
next();
}
Content Security Policy (CSP)
CSP Header Configuration
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Content Security Policy Directives β
ββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Directive β Purpose β
ββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β default-src β Default fallback for other directives β
β script-src β Valid sources for JavaScript β
β style-src β Valid sources for stylesheets β
β img-src β Valid sources for images β
β connect-src β Valid sources for fetch, XHR, WebSocket β
β font-src β Valid sources for fonts β
β frame-src β Valid sources for iframes β
β object-src β Valid sources for plugins β
β report-uri β URL to send CSP violation reports β
ββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CSP Examples
// Strict CSP (recommended for new projects)
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
// Using nonces for inline scripts
<script nonce="abc123">
// This script is allowed
console.log('Allowed by CSP');
</script>
<script>
// This script is BLOCKED by CSP
// No nonce attribute
</script>
Injection Attacks
Types of Injection
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Injection Attack Types β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Type β Example & Prevention β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β SQL Injection β Input: "1 OR 1=1" breaks query logic β
β β Fix: Use parameterized queries β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β NoSQL Injection β Input: {"$gt": ""} bypasses filters β
β β Fix: Validate input types, sanitize β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Command Inject β Input: "; rm -rf /" executes system commands β
β β Fix: Avoid shell, use safe APIs β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Code Injection β Input to eval() executes arbitrary code β
β β Fix: Never eval() user input β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Path Traversal β Input: "../../../etc/passwd" accesses files β
β β Fix: Validate, normalize, restrict paths β
ββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Injection Prevention
// β SQL Injection vulnerable
const query = `SELECT * FROM users WHERE id = ${userId}`;
// β Parameterized query (safe)
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);
// β Command injection vulnerable
exec(`echo ${userInput}`);
// β Safe alternative
spawn('echo', [userInput], { shell: false });
// β Code injection vulnerable
eval(userCode);
new Function(userCode)();
// β Safe alternative: use sandbox or avoid entirely
const vm = require('vm');
const sandbox = { result: null };
vm.createContext(sandbox);
vm.runInContext('result = 1 + 1', sandbox, { timeout: 100 });
Security Headers
Essential Security Headers
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Essential Security Headers β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Header β Purpose β
ββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Strict-Transport-Securityβ Force HTTPS connections β
β X-Content-Type-Options β Prevent MIME type sniffing β
β X-Frame-Options β Prevent clickjacking β
β X-XSS-Protection β Enable browser XSS filter (legacy) β
β Referrer-Policy β Control referrer information β
β Permissions-Policy β Control browser features β
β Content-Security-Policy β Control resource loading β
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββ
Express.js Security Headers
const helmet = require('helmet');
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-abc123'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
hsts: {
maxAge: 31536000, // 1 year
includeSubDomains: true,
preload: true,
},
frameguard: { action: 'deny' },
noSniff: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
})
);
Client-Side Security
Secure Cookie Configuration
// Setting secure cookies
document.cookie = 'session=abc123; Secure; HttpOnly; SameSite=Strict';
// Cookie attributes explained:
// Secure - Only sent over HTTPS
// HttpOnly - Not accessible via JavaScript (prevents XSS theft)
// SameSite - Prevents CSRF
// - Strict: Never sent cross-site
// - Lax: Sent on top-level navigation
// - None: Always sent (requires Secure)
Secure Storage
// β Don't store sensitive data in localStorage
localStorage.setItem('authToken', token); // Vulnerable to XSS
// β Use HttpOnly cookies for auth tokens
// Set by server:
Set-Cookie: authToken=abc123; HttpOnly; Secure; SameSite=Strict
// For less sensitive data, encrypt before storing
async function encryptAndStore(key, data, encryptionKey) {
const encrypted = await encrypt(data, encryptionKey);
sessionStorage.setItem(key, encrypted);
}
async function retrieveAndDecrypt(key, encryptionKey) {
const encrypted = sessionStorage.getItem(key);
return await decrypt(encrypted, encryptionKey);
}
Security Checklist
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Security Checklist β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β XSS Prevention: β
β β‘ Never use innerHTML with user input β
β β‘ Escape all output by default β
β β‘ Implement Content Security Policy β
β β‘ Use textContent instead of innerHTML where possible β
β β
β CSRF Prevention: β
β β‘ Implement CSRF tokens for state-changing operations β
β β‘ Use SameSite cookies β
β β‘ Verify Origin/Referer headers β
β β
β Injection Prevention: β
β β‘ Use parameterized queries β
β β‘ Validate and sanitize all input β
β β‘ Never use eval() with user input β
β β‘ Avoid shell commands with user input β
β β
β Authentication: β
β β‘ Use HTTPS everywhere β
β β‘ Implement secure password hashing (bcrypt) β
β β‘ Use HttpOnly, Secure cookies β
β β‘ Implement rate limiting β
β β
β Headers: β
β β‘ Enable HSTS β
β β‘ Set X-Content-Type-Options: nosniff β
β β‘ Set X-Frame-Options or CSP frame-ancestors β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Takeaways
- β’Trust no input - All user input is potentially malicious
- β’Escape all output - Context-aware encoding is essential
- β’Defense in depth - Multiple layers of security
- β’Principle of least privilege - Minimal permissions needed
- β’Keep dependencies updated - Security patches are critical
- β’Monitor and log - Detect attacks early
- β’Security headers - Use them all
Files in This Section
- β’
README.md- This documentation - β’
examples.js- Security vulnerability demonstrations - β’
exercises.js- Security practice exercises