Security Best Practices
When to use this skill
-
New project: consider security from the start
-
Security audit: inspect and fix vulnerabilities
-
Public API: harden APIs accessible externally
-
Compliance: comply with GDPR, PCI-DSS, etc.
Instructions
Step 1: Enforce HTTPS and security headers
Express.js security middleware:
import express from 'express'; import helmet from 'helmet'; import rateLimit from 'express-rate-limit';
const app = express();
// Helmet: automatically set security headers app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'", "https://trusted-cdn.com"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], connectSrc: ["'self'", "https://api.example.com"], fontSrc: ["'self'", "https:", "data:"], objectSrc: ["'none'"], mediaSrc: ["'self'"], frameSrc: ["'none'"], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } }));
// Enforce HTTPS
app.use((req, res, next) => {
if (process.env.NODE_ENV === 'production' && !req.secure) {
return res.redirect(301, https://${req.headers.host}${req.url});
}
next();
});
// Rate limiting (DDoS prevention) const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // max 100 requests per IP message: 'Too many requests from this IP, please try again later.', standardHeaders: true, legacyHeaders: false, });
app.use('/api/', limiter);
// Stricter for auth endpoints const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5, // only 5 times per 15 minutes skipSuccessfulRequests: true // do not count successful requests });
app.use('/api/auth/login', authLimiter);
Step 2: Input validation (SQL Injection, XSS prevention)
Joi validation:
import Joi from 'joi';
const userSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).pattern(/^(?=.[A-Z])(?=.[a-z])(?=.\d)(?=.[@$!%?&])[A-Za-z\d@$!%?&]/).required(), name: Joi.string().min(2).max(50).required() });
app.post('/api/users', async (req, res) => { // 1. Validate input const { error, value } = userSchema.validate(req.body);
if (error) { return res.status(400).json({ error: error.details[0].message }); }
// 2. Prevent SQL Injection: Parameterized Queries
// ❌ Bad example
// db.query(SELECT * FROM users WHERE email = '${email}');
// ✅ Good example const user = await db.query('SELECT * FROM users WHERE email = ?', [value.email]);
// 3. Prevent XSS: Output Encoding // React/Vue escape automatically; otherwise use a library import DOMPurify from 'isomorphic-dompurify'; const sanitized = DOMPurify.sanitize(userInput);
res.json({ user: sanitized }); });
Step 3: Prevent CSRF
CSRF Token:
import csrf from 'csurf'; import cookieParser from 'cookie-parser';
app.use(cookieParser());
// CSRF protection const csrfProtection = csrf({ cookie: true });
// Provide CSRF token app.get('/api/csrf-token', csrfProtection, (req, res) => { res.json({ csrfToken: req.csrfToken() }); });
// Validate CSRF on all POST/PUT/DELETE requests app.post('/api/*', csrfProtection, (req, res, next) => { next(); });
// Use on the client // fetch('/api/users', { // method: 'POST', // headers: { // 'CSRF-Token': csrfToken // }, // body: JSON.stringify(data) // });
Step 4: Manage secrets
.env (never commit):
Database
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT
ACCESS_TOKEN_SECRET=your-super-secret-access-token-key-min-32-chars REFRESH_TOKEN_SECRET=your-super-secret-refresh-token-key-min-32-chars
API Keys
STRIPE_SECRET_KEY=sk_test_xxx SENDGRID_API_KEY=SG.xxx
Kubernetes Secrets:
apiVersion: v1 kind: Secret metadata: name: myapp-secrets type: Opaque stringData: database-url: postgresql://user:password@postgres:5432/mydb jwt-secret: your-jwt-secret
// Read from environment variables const dbUrl = process.env.DATABASE_URL; if (!dbUrl) { throw new Error('DATABASE_URL environment variable is required'); }
Step 5: Secure API authentication
JWT + Refresh Token Rotation:
// Short-lived access token (15 minutes) const accessToken = jwt.sign({ userId }, ACCESS_SECRET, { expiresIn: '15m' });
// Long-lived refresh token (7 days), store in DB const refreshToken = jwt.sign({ userId }, REFRESH_SECRET, { expiresIn: '7d' }); await db.refreshToken.create({ userId, token: refreshToken, expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) });
// Refresh token rotation: re-issue on each use app.post('/api/auth/refresh', async (req, res) => { const { refreshToken } = req.body;
const payload = jwt.verify(refreshToken, REFRESH_SECRET);
// Invalidate existing token await db.refreshToken.delete({ where: { token: refreshToken } });
// Issue new tokens const newAccessToken = jwt.sign({ userId: payload.userId }, ACCESS_SECRET, { expiresIn: '15m' }); const newRefreshToken = jwt.sign({ userId: payload.userId }, REFRESH_SECRET, { expiresIn: '7d' });
await db.refreshToken.create({ userId: payload.userId, token: newRefreshToken, expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) });
res.json({ accessToken: newAccessToken, refreshToken: newRefreshToken }); });
Constraints
Required rules (MUST)
-
HTTPS Only: HTTPS required in production
-
Separate secrets: manage via environment variables; never hardcode in code
-
Input Validation: validate all user input
-
Parameterized Queries: prevent SQL Injection
-
Rate Limiting: DDoS prevention
Prohibited items (MUST NOT)
-
No eval(): code injection risk
-
No direct innerHTML: XSS risk
-
No committing secrets: never commit .env files
OWASP Top 10 checklist
- A01: Broken Access Control - RBAC, authorization checks
- A02: Cryptographic Failures - HTTPS, encryption
- A03: Injection - Parameterized Queries, Input Validation
- A04: Insecure Design - Security by Design
- A05: Security Misconfiguration - Helmet, change default passwords
- A06: Vulnerable Components - npm audit, regular updates
- A07: Authentication Failures - strong auth, MFA
- A08: Data Integrity Failures - signature validation, CSRF prevention
- A09: Logging Failures - security event logging
- A10: SSRF - validate outbound requests
Best practices
-
Principle of Least Privilege: grant minimal privileges
-
Defense in Depth: layered security
-
Security Audits: regular security reviews
References
-
OWASP Top 10
-
helmet.js
-
Security Checklist
Metadata
Version
-
Current version: 1.0.0
-
Last updated: 2025-01-01
-
Compatible platforms: Claude, ChatGPT, Gemini
Related skills
-
authentication-setup
-
deployment
Tags
#security #OWASP #HTTPS #CORS #XSS #SQL-injection #CSRF #infrastructure
Examples
Example 1: Basic usage
Example 2: Advanced usage