security-best-practices by supercent-io/skills-template
npx skills add https://github.com/supercent-io/skills-template --skill security-best-practicesExpress.js 安全中间件:
import express from 'express';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
const app = express();
// Helmet:自动设置安全头部
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
}
}));
// 强制使用 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();
});
// 速率限制(DDoS 防护)
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
max: 100, // 每个 IP 最多 100 个请求
message: '来自此 IP 的请求过多,请稍后再试。',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
// 对认证端点更严格
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 每 15 分钟仅 5 次
skipSuccessfulRequests: true // 不计算成功的请求
});
app.use('/api/auth/login', authLimiter);
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
Joi 验证:
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. 验证输入
const { error, value } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
// 2. 防止 SQL 注入:参数化查询
// ❌ 错误示例
// db.query(`SELECT * FROM users WHERE email = '${email}'`);
// ✅ 正确示例
const user = await db.query('SELECT * FROM users WHERE email = ?', [value.email]);
// 3. 防止 XSS:输出编码
// React/Vue 会自动转义;否则请使用库
import DOMPurify from 'isomorphic-dompurify';
const sanitized = DOMPurify.sanitize(userInput);
res.json({ user: sanitized });
});
CSRF 令牌:
import csrf from 'csurf';
import cookieParser from 'cookie-parser';
app.use(cookieParser());
// CSRF 防护
const csrfProtection = csrf({ cookie: true });
// 提供 CSRF 令牌
app.get('/api/csrf-token', csrfProtection, (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
// 在所有 POST/PUT/DELETE 请求上验证 CSRF
app.post('/api/*', csrfProtection, (req, res, next) => {
next();
});
// 在客户端使用
// fetch('/api/users', {
// method: 'POST',
// headers: {
// 'CSRF-Token': csrfToken
// },
// body: JSON.stringify(data)
// });
.env(切勿提交):
# 数据库
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 密钥
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
// 从环境变量读取
const dbUrl = process.env.DATABASE_URL;
if (!dbUrl) {
throw new Error('DATABASE_URL environment variable is required');
}
JWT + 刷新令牌轮换:
// 短期访问令牌(15 分钟)
const accessToken = jwt.sign({ userId }, ACCESS_SECRET, { expiresIn: '15m' });
// 长期刷新令牌(7 天),存储在数据库中
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)
});
// 刷新令牌轮换:每次使用时重新签发
app.post('/api/auth/refresh', async (req, res) => {
const { refreshToken } = req.body;
const payload = jwt.verify(refreshToken, REFRESH_SECRET);
// 使现有令牌失效
await db.refreshToken.delete({ where: { token: refreshToken } });
// 签发新令牌
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 });
});
- [ ] A01:失效的访问控制 - RBAC、授权检查
- [ ] A02:加密机制失效 - HTTPS、加密
- [ ] A03:注入 - 参数化查询、输入验证
- [ ] A04:不安全设计 - 安全设计
- [ ] A05:安全配置错误 - Helmet、更改默认密码
- [ ] A06:易受攻击的组件 - npm audit、定期更新
- [ ] A07:身份认证和授权错误 - 强认证、MFA
- [ ] A08:数据完整性失效 - 签名验证、CSRF 防护
- [ ] A09:日志记录和监控不足 - 安全事件日志记录
- [ ] A10:服务端请求伪造 - 验证出站请求
#security #OWASP #HTTPS #CORS #XSS #SQL-injection #CSRF #infrastructure
每周安装次数
14.1K
代码仓库
GitHub 星标数
88
首次出现
2026 年 1 月 24 日
安全审计
已安装于
codex13.9K
gemini-cli13.8K
opencode13.8K
cursor13.8K
github-copilot13.8K
amp13.8K
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);
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 });
});
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)
// });
.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');
}
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 });
});
- [ ] 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
#security #OWASP #HTTPS #CORS #XSS #SQL-injection #CSRF #infrastructure
Weekly Installs
14.1K
Repository
GitHub Stars
88
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex13.9K
gemini-cli13.8K
opencode13.8K
cursor13.8K
github-copilot13.8K
amp13.8K
Linux云主机安全托管指南:从SSH加固到HTTPS部署
33,600 周安装