JavaScript Security Best Practices
Protect your JavaScript applications from XSS, CSRF, injection attacks, and other common security vulnerabilities.
Cross-Site Scripting (XSS)
XSS is the most common web vulnerability. Never trust user input.
Preventing XSS
``javascript
// BAD: Direct HTML insertion
element.innerHTML = userInput; // XSS vulnerability!
// GOOD: Use textContent for plain text element.textContent = userInput;
// GOOD: Sanitize HTML if you must render it import DOMPurify from 'dompurify'; element.innerHTML = DOMPurify.sanitize(userInput);
// GOOD: Use template literals with encoding
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
`
Content Security Policy
`html
`
Avoiding eval() and Similar
`javascript
// BAD: Never use these with user input
eval(userInput);
new Function(userInput);
setTimeout(userInput, 1000);
// GOOD: Use JSON.parse for data const data = JSON.parse(jsonString);
// GOOD: Use safe alternatives
const fn = () => { /* predefined logic */ };
setTimeout(fn, 1000);
`
Secure Data Handling
`javascript
// Validate and sanitize all input
function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email) && email.length <= 254;
}
// Don't store sensitive data in localStorage // BAD localStorage.setItem('token', authToken); // Accessible to XSS
// BETTER: Use httpOnly cookies (server-side)
// Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=Strict
`
API Security
`javascript
// Always validate on the server side too
// Use HTTPS for all API calls
// Implement rate limiting
// Use CORS properly
const response = await fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken, // CSRF protection
},
credentials: 'same-origin',
body: JSON.stringify(data)
});
`
Dependency Security
`bash
# Audit your dependencies regularly
npm audit
npm audit fix
# Use lockfiles
# Keep dependencies updated
npx npm-check-updates
`
Prototype Pollution Prevention
`javascript
// BAD: Deep merge without protection
function merge(target, source) {
for (const key in source) {
if (typeof source[key] === 'object') {
merge(target[key], source[key]); // Prototype pollution!
} else {
target[key] = source[key];
}
}
}
// GOOD: Check for dangerous keys
function safeMerge(target, source) {
for (const key of Object.keys(source)) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue; // Skip dangerous keys
}
if (typeof source[key] === 'object' && source[key] !== null) {
target[key] = safeMerge(target[key] || {}, source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
`
Summary
Security is not optional. Sanitize all user input, avoid eval()`, use Content Security Policy, keep dependencies updated, validate on both client and server, and use HTTPS everywhere.