SECURITY, HEADERS & ENCRYPTION CHEATSHEET
An offline search dashboard outlining OWASP security remediations, secure HTTP response header syntaxes, cryptographic APIs, and secure application practices.
OWASP Top 10 Safeguards5 ENTRIES
Ensure raw input is never concatenated into SQL strings. Use parameterized queries/prepared statements.
db.query('SELECT * FROM users WHERE id = ?', [userId])// Safe:
const query = 'SELECT * FROM users WHERE id = ?';
await connection.execute(query, [req.query.id]);Using template literals: `SELECT * FROM users WHERE id = ${req.query.id}`, which exposes database schemas directly to injection payloads.
Escape all untrusted data before rendering it in the HTML DOM, or use libraries that do it automatically.
text.replace(/&/g, '&').replace(/</g, '<')const cleanInput = DOMPurify.sanitize(userInput);
document.getElementById('output').innerHTML = cleanInput;Using dangerouslySetInnerHTML or innerHTML directly on raw inputs from search query parameters or user profiles.
Insecure Direct Object Reference / Broken Object Level Authorization. Never trust user-provided IDs without verifying ownership.
if (resource.ownerId !== currentUser.id) throw new UnauthorizedError();// Safe:
const document = await Document.findById(req.params.id);
if (!document || document.ownerId !== req.user.id) {
return res.status(403).send('Access denied');
}Relying on client-side route guards or URL obfuscation to protect access to private files or sensitive data records.
Sanitize and validate user-supplied URLs against an allowlist before making requests from the backend server.
if (!allowedDomains.includes(parsedUrl.hostname)) throw new Error('Untrusted domain');// Safe:
const targetUrl = new URL(req.body.url);
const allowedHosts = ['api.partner.com', 'images.partner.com'];
if (!allowedHosts.includes(targetUrl.hostname)) {
throw new Error('Forbidden Destination');
}
await axios.get(targetUrl.href);Making raw HTTP fetch calls to user-submitted URLs directly, enabling attackers to probe internal loopback services like localhost/metadata.
Ensure JWT tokens are verified using robust cryptography keys and expiration checks on the server.
jwt.verify(token, secretKey, { algorithms: ['HS256'] })// Safe:
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'],
issuer: 'my-app-auth'
});Using jwt.decode() instead of jwt.verify(), which extracts header payload fields without checking if the token signature is valid.
HTTP Security Headers5 ENTRIES
Restricts resources (such as JavaScript, CSS, Images) that the browser is allowed to load for a given page.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.comres.setHeader(
'Content-Security-Policy',
"default-src 'self'; img-src 'self' data:; script-src 'self'"
);Using 'unsafe-inline' or '*' in CSP directives, which completely defeats the anti-XSS features of CSP.
Forces browser connections to happen securely over HTTPS instead of HTTP.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadres.setHeader(
'Strict-Transport-Security',
'max-age=63072000; includeSubDomains; preload'
);Enabling HSTS with a short max-age duration or without testing subdomains, potentially locking out users from legacy HTTP APIs.
Prevents clickjacking attacks by dictating whether pages can be embedded within frame tags on external websites.
X-Frame-Options: DENY | SAMEORIGINres.setHeader('X-Frame-Options', 'SAMEORIGIN');Neglecting to declare X-Frame-Options (or using CSP frame-ancestors), enabling bad actors to overlay transparent clickable layers on your page.
Forces the browser to respect content-type headers, preventing MIME-type sniffing vulnerabilities.
X-Content-Type-Options: nosniffres.setHeader('X-Content-Type-Options', 'nosniff');Forgetting to set 'nosniff', which allows browsers to execute uploaded user text/HTML assets as scripts.
Controls how much reference metadata (such as paths or search queries) is sent when navigating to external websites.
Referrer-Policy: no-referrer | same-origin | strict-origin-when-cross-originres.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');Using Referrer-Policy 'unsafe-url', which leaks sensitive query tokens (e.g. password-reset links) to external analytics scripts.
Hashing & Cryptography4 ENTRIES
Never store plain text passwords. Use standard slow hashing functions like bcrypt or Argon2 with high cost factors.
bcrypt.hash(password, saltRounds)const hash = await bcrypt.hash(rawPassword, 12);
const matches = await bcrypt.compare(inputPassword, hash);Using fast hashing algorithms like MD5, SHA-1, or SHA-256 for passwords, which are easily cracked via dictionary attacks or GPUs.
Use Advanced Encryption Standard (AES) with Galois/Counter Mode (GCM) for authenticated encryption/decryption of private text.
crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data)const iv = crypto.getRandomValues(new Uint8Array(12));
const cipher = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
aesKey,
textEncoder.encode(secretData)
);Reusing Initialization Vectors (IVs) or using insecure encryption modes like AES-ECB, which leak patterns in encrypted data.
Use anti-CSRF tokens or enforce strict SameSite attributes on cookies to prevent cross-site request forgery attacks.
Set-Cookie: session=xyz; SameSite=Lax; Secure; HttpOnlyres.cookie('sessionId', token, {
httpOnly: true,
secure: true,
sameSite: 'lax'
});Leaving SameSite as 'None' without adding CSRF tokens, allowing cross-site clicks to make state-changing GET/POST requests silently.
Always use cryptographically secure pseudorandom number generators (CSPRNG) for sensitive keys, IDs, or tokens.
crypto.randomBytes(size) | crypto.getRandomValues(typedArray)// Node.js:
const token = crypto.randomBytes(32).toString('hex');
// Browser Web Crypto:
const array = new Uint32Array(10);
window.crypto.getRandomValues(array);Using Math.random() to generate session IDs, passwords, or salts, which are mathematically predictable and easily reverse-engineered.
API Security & Rate Limiting2 ENTRIES
Limit the number of requests a client can make in a given timeframe to prevent DoS attacks and brute-force logins.
rateLimit({ windowMs: 15 * 60 * 1000, limit: 100 })const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per window
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);Rate-limiting using local server memory in stateless cluster environments, which allows clients to bypass limits by hit-testing different instances.
Restrict client-side cross-origin access to your APIs. Maintain a strict allowlist of origins instead of allowing any domain.
Access-Control-Allow-Origin: https://trustedapp.comconst corsOptions = {
origin: ['https://opendevhub.com', 'https://admin.opendevhub.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true
};
app.use(cors(corsOptions));Setting 'Access-Control-Allow-Origin: *' combined with 'Access-Control-Allow-Credentials: true', which is an invalid and highly insecure CORS policy.