Secure coding standards
JavaScript, as a dynamic, weakly typed scripting language, can easily lead to security vulnerabilities due to non-standard coding practices during development. Adhering to secure coding standards can effectively reduce potential risks and improve code quality and application security.
Variable Declaration and Scope Control
Always use const
and let
instead of var
to declare variables, avoiding hoisting and global pollution. For constants that need protection, use Object.freeze()
for deep freezing:
// Unsafe practice
var apiKey = '12345';
// Safe practice
const CONFIG = Object.freeze({
API_KEY: '12345',
MAX_RETRY: 3
});
// Attempts to modify will fail silently
CONFIG.API_KEY = 'hack'; // Throws an error in strict mode
Avoid declaring global variables within function scope by using IIFE to encapsulate sensitive operations:
(function() {
const secretToken = generateToken();
// Secure scope operations
})();
Input Validation and Sanitization
Treat all external inputs as untrusted data. Use strict validation libraries like Joi or Yup:
import * as yup from 'yup';
const userSchema = yup.object().shape({
username: yup.string()
.required()
.matches(/^[a-zA-Z0-9_]+$/, 'Only alphanumeric characters and underscores allowed'),
age: yup.number()
.integer()
.min(13)
.max(120)
});
// Validation example
try {
await userSchema.validate({
username: "admin'--",
age: "25"
});
} catch (err) {
console.error('Validation failed:', err.errors);
}
For DOM operations, always escape dynamic content:
function safeHTML(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
document.getElementById('output').innerHTML = safeHTML(userInput);
Secure Communication and Data Handling
Use HTTPS and avoid storing sensitive information on the frontend. For necessary API keys, consider using HttpOnly Cookies:
// Unsafe
localStorage.setItem('auth_token', 'Bearer xyz');
// Relatively safe
fetch('/api/login', {
method: 'POST',
credentials: 'include', // Works with backend HttpOnly Cookies
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ /* data */ })
});
For encrypting sensitive data, use the Web Crypto API instead of custom algorithms:
async function hashPassword(password) {
const encoder = new TextEncoder();
const data = encoder.encode(password + process.env.SALT);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
Preventing XSS Attacks
Modern frameworks like React/Vue provide basic protection, but dangerous scenarios still require attention:
// Dangerous operation example in React
function UnsafeComponent({ userInput }) {
// Wrong approach
return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
// Correct approach
return <div>{userInput}</div>; // Automatic escaping
}
When dynamically creating scripts, use textContent
instead of innerHTML
:
const script = document.createElement('script');
script.textContent = 'console.log("Safe execution")';
document.body.appendChild(script);
Preventing CSRF Attacks
Implement CSRF token mechanisms and integrate them with frameworks:
// Frontend token retrieval
let csrfToken = document.querySelector('meta[name="csrf-token"]').content;
// Include token in requests
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({ amount: 100 })
});
Dependency Management Security
Regularly use npm audit
to check dependencies and lock versions:
{
"dependencies": {
"lodash": "4.17.21", // Fixed version
"react": "^18.2.0" // Allow patch updates
}
}
Use Content Security Policy (CSP) for enhanced protection:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com;">
Error Handling and Logging
Avoid exposing sensitive information in error messages:
try {
await criticalOperation();
} catch (err) {
// Unsafe
console.error(`Operation failed: ${err.stack}`);
// Safe approach
console.error('Operation failed: System error');
sendToMonitoring({
errorCode: 'E500',
timestamp: Date.now()
});
}
Performance and Memory Safety
Avoid common memory leak patterns:
// Event listener leaks
window.addEventListener('resize', heavyCalculation);
// Correct approach
const debouncedCalc = debounce(heavyCalculation, 200);
window.addEventListener('resize', debouncedCalc);
// Cleanup on component unmount
window.removeEventListener('resize', debouncedCalc);
Use streaming APIs for handling large files:
async function processFile(file) {
const stream = file.stream();
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Process data in chunks
}
}
Secure Practices with Modern APIs
Use structuredClone
instead of JSON.parse(JSON.stringify())
for deep copying:
const original = new Set([1, 2, new Map([[3, 4]])]);
const copy = structuredClone(original); // Preserves reference relationships
Validate message sources in Worker communication:
// worker.js
self.onmessage = (event) => {
if (event.origin !== window.location.origin) return;
// Safely handle messages
};
Enhancing Type Safety
Even with JavaScript, consider type checking:
// Use JSDoc to enhance type safety
/**
* @param {string} url
* @param {{ method?: string, body?: object }} options
* @returns {Promise<{ data: any, status: number }>}
*/
async function safeFetch(url, options = {}) {
// Implementation
}
Browser Storage Standards
Differentiate storage usage for different scenarios:
// Session-level data
sessionStorage.setItem('temp_data', JSON.stringify({ tabState: 'active' }));
// Long-term preferences
localStorage.setItem('user_prefs', JSON.stringify({
theme: 'dark',
fontSize: 14
}));
// Sensitive data
const secureStore = {
set(key, value) {
crypto.subtle.encrypt(/* encryption parameters */)
.then(ciphertext => {
localStorage.setItem(key, ciphertext);
});
}
};
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn