TL;DR — 应用安全速查
应用安全工程涵盖从设计到部署的全流程。使用参数化查询防止 SQLi,CSP 防止 XSS,SameSite Cookie + CSRF Token 防止 CSRF。密码使用 bcrypt/Argon2id 哈希,JWT 使用 RS256/EdDSA 签名。密钥存储在 Vault 或云密钥管理器中,不提交代码仓库。设置 HSTS、X-Frame-Options、X-Content-Type-Options 等安全头。在 CI/CD 中集成 SAST、DAST、依赖扫描和容器扫描,实现 DevSecOps。
核心要点
- 始终使用参数化查询——永远不要将用户输入拼接到 SQL 中。
- 实施 CSP 头和输出编码以防止 XSS 攻击。
- 认证(AuthN)和授权(AuthZ)必须作为独立的可组合层实现。
- 使用 Vault 或云密钥管理器管理密钥——永远不提交到版本控制。
- 在 CI/CD 每次运行中集成 SAST、依赖扫描和容器镜像扫描。
- 对所有 API 端点实施速率限制、输入验证和 CORS 白名单。
- 静态数据使用 AES-256-GCM 加密,传输数据使用 TLS 1.3。
- 安全是持续过程,不是一次性检查——将安全债务与技术债务一起追踪。
应用安全工程不仅仅是修补漏洞——它是将安全思维融入软件开发全生命周期的系统方法。从威胁建模到安全编码、从密钥管理到 CI/CD 安全集成,本指南涵盖了构建安全应用程序所需的一切。无论您是全栈开发者、后端工程师还是 DevOps 工程师,掌握这些安全实践对于保护用户数据和业务至关重要。
OWASP Top 10 概览(2021 版)
OWASP Top 10 是最广泛认可的 Web 应用安全风险排名。2021 版反映了现代威胁格局,新增了不安全设计、软件和数据完整性失败、SSRF 三个类别。
| 编号 | 名称 | 关键防御 |
|---|---|---|
| A01 | 访问控制失效 | 最小权限、RBAC、服务端校验 |
| A02 | 加密失败 | TLS 1.3、AES-256-GCM、密钥轮换 |
| A03 | 注入 | 参数化查询、输入验证、WAF |
| A04 | 不安全设计 | 威胁建模、安全设计模式 |
| A05 | 安全配置错误 | 安全基线、自动化配置审计 |
| A06 | 易受攻击和过时组件 | 依赖扫描、SCA、自动补丁 |
| A07 | 身份认证和鉴别失败 | MFA、速率限制、安全会话管理 |
| A08 | 软件和数据完整性失败 | 签名验证、安全 CI/CD 管道 |
| A09 | 安全日志和监控失败 | 结构化日志、告警、SIEM |
| A10 | 服务端请求伪造 | URL 白名单、网络隔离 |
认证与授权(AuthN / AuthZ)
认证验证用户身份,授权决定用户能做什么。二者必须作为独立层实现,以便灵活组合和审计。
密码安全
// Password hashing with bcrypt (Node.js)
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12;
async function hashPassword(plaintext: string): Promise<string> {
return bcrypt.hash(plaintext, SALT_ROUNDS);
}
async function verifyPassword(
plaintext: string,
hash: string
): Promise<boolean> {
return bcrypt.compare(plaintext, hash);
}
// Password policy enforcement
function validatePassword(pw: string): string[] {
const errors: string[] = [];
if (pw.length < 12) errors.push('Min 12 characters');
if (!/[A-Z]/.test(pw)) errors.push('Need uppercase');
if (!/[0-9]/.test(pw)) errors.push('Need digit');
if (!/[^A-Za-z0-9]/.test(pw)) errors.push('Need special char');
return errors;
}JWT 安全实践
// JWT with RS256 (asymmetric — recommended)
import jwt from 'jsonwebtoken';
import fs from 'fs';
const privateKey = fs.readFileSync('./keys/private.pem');
const publicKey = fs.readFileSync('./keys/public.pem');
function signToken(payload: object): string {
return jwt.sign(payload, privateKey, {
algorithm: 'RS256',
expiresIn: '15m', // Short-lived access tokens
issuer: 'myapp.com',
audience: 'myapp-api',
});
}
function verifyToken(token: string): jwt.JwtPayload {
return jwt.verify(token, publicKey, {
algorithms: ['RS256'], // CRITICAL: whitelist algorithms
issuer: 'myapp.com',
audience: 'myapp-api',
}) as jwt.JwtPayload;
}JWT 安全要点:始终白名单签名算法(禁用 "none"),使用短期访问令牌 + 长期刷新令牌,验证 issuer、audience 和 expiration,将刷新令牌存储在 HttpOnly cookie 中。
OAuth 2.0 / OIDC 流程
| 流程 | 适用场景 | 安全注意 |
|---|---|---|
| Authorization Code + PKCE | SPA、移动应用、服务端应用 | 推荐用于所有客户端 |
| Client Credentials | 服务间通信 (M2M) | 仅限受信服务端 |
| Device Code | 无浏览器设备 (CLI, IoT) | 短期轮询码 |
| Implicit (Legacy) | 已弃用 | 不安全——改用 PKCE |
RBAC 与 ABAC 授权模型
// RBAC middleware example (Express.js)
type Role = 'admin' | 'editor' | 'viewer';
const permissions: Record<Role, string[]> = {
admin: ['read', 'write', 'delete', 'manage_users'],
editor: ['read', 'write'],
viewer: ['read'],
};
function requirePermission(permission: string) {
return (req: Request, res: Response, next: NextFunction) => {
const userRole = req.user?.role as Role;
if (!permissions[userRole]?.includes(permission)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
// Usage
app.delete('/api/posts/:id',
authenticate,
requirePermission('delete'),
deletePostHandler
);输入验证与数据清洗
所有用户输入都是不可信的。验证应在服务端强制执行(客户端验证仅为用户体验),并遵循白名单优于黑名单的原则。
// Zod schema validation (TypeScript)
import { z } from 'zod';
const CreateUserSchema = z.object({
email: z.string().email().max(254),
name: z.string().min(1).max(100)
.regex(/^[a-zA-Z\s\-']+$/), // Whitelist chars
age: z.number().int().min(13).max(150),
role: z.enum(['user', 'editor']), // Enum whitelist
bio: z.string().max(500).optional(),
});
// In route handler
app.post('/api/users', (req, res) => {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: 'Validation failed',
details: result.error.flatten(),
});
}
// result.data is typed and validated
createUser(result.data);
});输入验证清单
- 验证类型、长度、范围和格式
- 使用白名单(允许列表)而非黑名单
- 验证 Content-Type 头
- 对 HTML 输出进行上下文感知编码
- 规范化 Unicode 后再验证
- 限制文件上传类型、大小和存储位置
- 服务端验证不可被绕过——客户端验证仅为辅助
XSS 防护(跨站脚本攻击)
XSS 攻击通过在页面中注入恶意脚本来窃取 cookie、劫持会话或重定向用户。防护需要输出编码和 CSP 的多层防御。
// Context-aware output encoding
import DOMPurify from 'dompurify';
// HTML context — sanitize user-generated HTML
const safeHTML = DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p'],
ALLOWED_ATTR: ['href'],
});
// JavaScript context — NEVER interpolate into JS
// BAD: <script>var x = "\${userInput}";</script>
// GOOD: Pass data via data attributes or JSON
// URL context — validate scheme
function isSafeUrl(url: string): boolean {
try {
const parsed = new URL(url);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
}CSRF 防护(跨站请求伪造)
CSRF 攻击诱导已认证用户执行非预期操作。现代防护结合 SameSite Cookie 和 CSRF Token 实现双重保护。
// Express.js CSRF protection setup
import csrf from 'csurf';
import cookieParser from 'cookie-parser';
app.use(cookieParser());
// Cookie settings for session
app.use(session({
cookie: {
httpOnly: true, // No JS access
secure: true, // HTTPS only
sameSite: 'lax', // CSRF protection layer 1
maxAge: 3600000, // 1 hour
},
// ... session store config
}));
// CSRF token middleware (layer 2)
const csrfProtection = csrf({ cookie: true });
app.use(csrfProtection);
// Provide token to client
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
// Token auto-validated on POST/PUT/DELETE
app.post('/transfer', (req, res) => {
// csrfProtection already verified the token
processTransfer(req.body);
});SQL 注入防护
SQL 注入允许攻击者执行任意数据库查询。唯一可靠的防护是参数化查询——永远不要字符串拼接。
// VULNERABLE — never do this
const query = `SELECT * FROM users WHERE id = \${userId}`;
// SAFE — parameterized query (node-postgres)
const { rows } = await pool.query(
'SELECT * FROM users WHERE id = $1 AND org_id = $2',
[userId, orgId]
);
// SAFE — ORM (Prisma)
const user = await prisma.user.findUnique({
where: { id: userId },
select: { id: true, name: true, email: true },
});
// SAFE — Query builder (Knex)
const users = await knex('users')
.where({ org_id: orgId })
.andWhere('created_at', '>', since)
.select('id', 'name', 'email');数据库安全加固
- 最小权限原则——应用账户只授予必要权限
- 只读副本用于报表查询
- 启用查询日志和慢查询告警
- 网络隔离——数据库不暴露到公网
- 加密连接(require SSL/TLS)
密钥与凭证管理
泄露的密钥是最常见的安全事件之一。GitHub 每天检测到数千个泄露的密钥。正确的密钥管理是安全基础设施的核心。
# .gitignore — MUST include these
.env
.env.*
*.pem
*.key
*.p12
credentials.json
service-account.json
# Pre-commit hook for secret detection
# Install: pip install detect-secrets
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']密钥管理方案对比
| 方案 | 类型 | 适用场景 |
|---|---|---|
| HashiCorp Vault | 自托管/云 | 大型组织、动态密钥 |
| AWS Secrets Manager | 云原生 | AWS 生态系统 |
| GCP Secret Manager | 云原生 | GCP 生态系统 |
| Azure Key Vault | 云原生 | Azure 生态系统 |
| SOPS + Age | 文件加密 | GitOps、小团队 |
| Doppler | SaaS | 多环境密钥同步 |
// Fetching secrets at runtime (Node.js + AWS)
import { SecretsManagerClient,
GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManagerClient({ region: 'us-east-1' });
async function getSecret(name: string): Promise<string> {
const cmd = new GetSecretValueCommand({
SecretId: name,
});
const resp = await client.send(cmd);
return resp.SecretString ?? '';
}
// Usage — never hardcode secrets
const dbPassword = await getSecret('prod/db/password');依赖扫描与 SCA
软件供应链攻击日益增多。每个依赖都是潜在的攻击面。自动化依赖扫描应在每次 CI 构建中运行。
# npm audit — built-in Node.js
npm audit --production
npm audit fix
# Snyk — comprehensive SCA
npx snyk test
npx snyk monitor # continuous monitoring
# pip-audit — Python
pip-audit --require-hashes
# cargo audit — Rust
cargo install cargo-audit
cargo audit
# Trivy — container + filesystem
trivy fs --severity HIGH,CRITICAL .
trivy image myapp:latest供应链安全策略
- 锁定依赖版本(package-lock.json, yarn.lock)
- 启用 Dependabot 或 Renovate 自动更新
- 审查新依赖的维护状态和安全历史
- 使用 Socket.dev 检测可疑包行为
- 考虑私有注册表(Verdaccio, Artifactory)
- 验证包签名(npm provenance, sigstore)
内容安全策略(CSP)
CSP 是防止 XSS 最有效的 HTTP 头之一。它指定浏览器允许加载哪些资源来源,从根本上限制脚本注入的影响。
# Strict CSP — recommended starting point
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM}';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.myapp.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
# Nonce-based CSP in Express.js
import crypto from 'crypto';
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.cspNonce = nonce;
res.setHeader('Content-Security-Policy',
`default-src 'self'; ` +
`script-src 'self' 'nonce-\${nonce}'; ` +
`style-src 'self' 'unsafe-inline'; ` +
`img-src 'self' data: https:;`
);
next();
});CORS 跨域资源共享
CORS 控制哪些外部域可以访问您的 API。配置不当的 CORS 策略是常见的安全漏洞。
// Secure CORS configuration (Express.js)
import cors from 'cors';
// NEVER use: cors({ origin: '*' }) for authenticated APIs
const allowedOrigins = [
'https://myapp.com',
'https://admin.myapp.com',
];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // Allow cookies
maxAge: 86400, // Preflight cache: 24h
}));API 安全
API 是现代应用的核心攻击面。安全的 API 需要认证、授权、速率限制、输入验证和适当的错误处理。
// Rate limiting with sliding window (Express)
import rateLimit from 'express-rate-limit';
// Global rate limit
const globalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
standardHeaders: true,
legacyHeaders: false,
});
// Strict limit for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 5 attempts per 15 min
skipSuccessfulRequests: true,
});
app.use('/api/', globalLimiter);
app.use('/api/auth/login', authLimiter);
app.use('/api/auth/register', authLimiter);API 安全清单
| 层面 | 措施 | 工具/方法 |
|---|---|---|
| 认证 | OAuth 2.0 / JWT | Auth0, Clerk, Keycloak |
| 授权 | RBAC / ABAC | Casbin, OPA, Cedar |
| 速率限制 | 滑动窗口 / 令牌桶 | express-rate-limit, Redis |
| 输入验证 | Schema 验证 | Zod, Joi, AJV |
| 请求限制 | 负载大小、查询深度 | body-parser, graphql-depth-limit |
| 日志审计 | 结构化日志 | Winston, Pino, ELK |
加密:静态与传输
加密保护数据免受未授权访问。传输加密(TLS)保护网络通信,静态加密保护存储的数据。两者都是合规要求(GDPR、HIPAA、PCI DSS)的基础。
传输加密(TLS)
# Nginx TLS 1.3 configuration
server {
listen 443 ssl http2;
server_name myapp.com;
ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:
ECDHE-RSA-AES128-GCM-SHA256:
ECDHE-ECDSA-AES256-GCM-SHA384:
ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS — force HTTPS for 2 years
add_header Strict-Transport-Security
"max-age=63072000; includeSubDomains; preload" always;
}静态加密
// AES-256-GCM encryption (Node.js)
import crypto from 'crypto';
const ALGORITHM = 'aes-256-gcm';
interface EncryptedData {
iv: string;
tag: string;
ciphertext: string;
}
function encrypt(plaintext: string, key: Buffer): EncryptedData {
const iv = crypto.randomBytes(12); // 96-bit IV for GCM
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
let ciphertext = cipher.update(plaintext, 'utf8', 'hex');
ciphertext += cipher.final('hex');
return {
iv: iv.toString('hex'),
tag: cipher.getAuthTag().toString('hex'),
ciphertext,
};
}
function decrypt(data: EncryptedData, key: Buffer): string {
const decipher = crypto.createDecipheriv(
ALGORITHM, key,
Buffer.from(data.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(data.tag, 'hex'));
let plaintext = decipher.update(data.ciphertext, 'hex', 'utf8');
plaintext += decipher.final('utf8');
return plaintext;
}| 场景 | 推荐算法 | 注意事项 |
|---|---|---|
| 密码哈希 | Argon2id / bcrypt | 不可逆,带盐 |
| 对称加密 | AES-256-GCM | 认证加密,防篡改 |
| 非对称加密 | RSA-OAEP / X25519 | 密钥交换、数字签名 |
| 数据完整性 | HMAC-SHA256 | 验证未被篡改 |
| 令牌签名 | EdDSA / RS256 | JWT、API 签名 |
安全头配置
安全头是最简单但最有效的防御手段之一。正确配置的安全头可以防止大量常见攻击。
// Comprehensive security headers middleware
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
frameAncestors: ["'none'"],
},
},
hsts: {
maxAge: 63072000, // 2 years
includeSubDomains: true,
preload: true,
},
referrerPolicy: {
policy: 'strict-origin-when-cross-origin',
},
}));
// Additional headers not covered by Helmet
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'camera=(), microphone=(), geolocation=()');
res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');
next();
});安全头参考表
| 头名称 | 推荐值 | 防护 |
|---|---|---|
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | 降级攻击、中间人 |
| Content-Security-Policy | 见上方 CSP 章节 | XSS, 数据注入 |
| X-Content-Type-Options | nosniff | MIME 类型嗅探 |
| X-Frame-Options | DENY | 点击劫持 |
| Referrer-Policy | strict-origin-when-cross-origin | 信息泄露 |
| Permissions-Policy | camera=(), microphone=(), geolocation=() | 功能滥用 |
| Cache-Control | no-store (sensitive pages) | 缓存中毒、数据泄露 |
DevSecOps CI/CD 集成
DevSecOps 将安全检查嵌入开发流程的每个阶段,实现"左移安全"——尽早发现并修复漏洞,成本最低。
# GitHub Actions — security pipeline
name: Security Pipeline
on: [push, pull_request]
jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: trufflesecurity/trufflehog@main
with:
extra_args: --only-verified
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/owasp-top-ten
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm audit --audit-level=high
- uses: snyk/actions/node@master
env:
SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }}
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t myapp:test .
- uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:test
severity: HIGH,CRITICAL
exit-code: 1DevSecOps 工具链
| 阶段 | 工具 | 检查内容 |
|---|---|---|
| 提交前 | detect-secrets, git-secrets, truffleHog | 密钥泄露检测 |
| 静态分析 | Semgrep, CodeQL, SonarQube | 代码漏洞模式 |
| 依赖扫描 | Snyk, npm audit, Dependabot | 已知 CVE 漏洞 |
| 容器扫描 | Trivy, Grype, Snyk Container | 镜像漏洞和配置 |
| IaC 扫描 | Checkov, tfsec, KICS | 基础设施配置错误 |
| 动态测试 | OWASP ZAP, Burp Suite, Nuclei | 运行时漏洞 |
安全架构模式
零信任架构
零信任的核心原则是"永不信任,始终验证"。每个请求都必须经过认证、授权和加密,无论来源是内部还是外部。
- 微分段——服务之间使用 mTLS 通信
- 每次请求都验证身份和权限
- 最小权限访问——仅授予必要的权限
- 持续监控和日志——假设已被入侵
威胁建模(STRIDE)
| 威胁 | 含义 | 缓解措施 |
|---|---|---|
| Spoofing | 冒充身份 | 强认证、MFA |
| Tampering | 篡改数据 | 完整性校验、签名 |
| Repudiation | 否认操作 | 审计日志、不可否认性 |
| Info Disclosure | 信息泄露 | 加密、访问控制 |
| DoS | 拒绝服务 | 速率限制、CDN、弹性伸缩 |
| Elevation | 权限提升 | RBAC、最小权限 |
安全日志与监控
没有日志和监控,安全事件无法被检测和响应。结构化日志和实时告警是安全运营的基础。
// Structured security logging (Pino)
import pino from 'pino';
const logger = pino({
level: 'info',
redact: ['req.headers.authorization',
'req.headers.cookie',
'body.password'], // Never log secrets
});
// Security event logging
function logSecurityEvent(event: {
type: string;
userId?: string;
ip: string;
details: string;
severity: 'low' | 'medium' | 'high' | 'critical';
}) {
logger.warn({
securityEvent: true,
...event,
timestamp: new Date().toISOString(),
});
}
// Example: log failed authentication
logSecurityEvent({
type: 'AUTH_FAILURE',
ip: req.ip,
details: 'Invalid credentials for user@example.com',
severity: 'medium',
});总结:构建安全文化
应用安全不是一次性任务,而是持续的工程实践。从 OWASP Top 10 的基础防护到 DevSecOps 的自动化集成,每一层安全措施都为整体防御增加了深度。将安全视为功能而非负担——投入安全的时间将在防止数据泄露和维护用户信任方面带来巨大回报。
关键行动清单:1) 立即启用安全头;2) 审计所有 SQL 查询确认使用参数化;3) 配置 CSP;4) 在 CI 中添加依赖扫描;5) 实施密钥管理方案;6) 定期进行威胁建模和渗透测试。安全是旅程,不是终点。
常见问题
What is the OWASP Top 10 and why does it matter?
The OWASP Top 10 is a regularly updated list of the most critical web application security risks published by the Open Web Application Security Project. It matters because it represents a broad consensus on the most dangerous flaws. Many compliance frameworks (PCI DSS, SOC 2, ISO 27001) reference OWASP as a baseline standard. Addressing the Top 10 significantly reduces your attack surface.
What is the difference between authentication and authorization?
Authentication (AuthN) verifies identity — confirming that a user is who they claim to be through credentials like passwords, tokens, or biometrics. Authorization (AuthZ) determines permissions — what an authenticated user is allowed to do. Authentication answers "who are you?" while authorization answers "what can you access?" Both are required for secure systems, and they should be implemented as separate, composable layers.
How do I prevent SQL injection in modern applications?
Use parameterized queries or prepared statements exclusively — never concatenate user input into SQL strings. ORMs like Prisma, SQLAlchemy, and ActiveRecord use parameterized queries by default. Additionally, apply the principle of least privilege to database accounts, validate and sanitize all inputs, and use a Web Application Firewall (WAF) as an additional defense layer. Regular code reviews and SAST tools can catch injection vulnerabilities early.
What is Content Security Policy (CSP) and how do I implement it?
Content Security Policy is an HTTP response header that controls which resources a browser is allowed to load for a page. A strict CSP prevents XSS by blocking inline scripts and restricting script sources. Start with Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; and tighten from there. Use nonce-based or hash-based CSP for inline scripts instead of 'unsafe-inline'. Report violations with report-uri or report-to directives.
How should I manage secrets like API keys and database passwords?
Never store secrets in source code, environment files committed to version control, or client-side code. Use a dedicated secrets manager such as HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault. For local development, use .env files that are gitignored. In CI/CD, use pipeline-level secret variables. Rotate secrets regularly, audit access, and use short-lived tokens where possible. Pre-commit hooks with tools like git-secrets or truffleHog can prevent accidental commits of credentials.
What security headers should every web application set?
Essential security headers include: Strict-Transport-Security (HSTS) to enforce HTTPS; Content-Security-Policy to prevent XSS; X-Content-Type-Options: nosniff to prevent MIME-type sniffing; X-Frame-Options: DENY or SAMEORIGIN to prevent clickjacking; Referrer-Policy: strict-origin-when-cross-origin to limit referrer leakage; Permissions-Policy to disable unnecessary browser features; and Cache-Control: no-store for sensitive pages. Use securityheaders.com to audit your configuration.
How do I secure REST APIs against common attacks?
Secure REST APIs by implementing proper authentication (OAuth 2.0, JWT with RS256), rate limiting per endpoint and per user, input validation on all parameters, CORS whitelisting, request size limits, and pagination for list endpoints. Use API keys for identification (not authentication), validate Content-Type headers, return minimal error information to clients, log all access attempts, and version your API to maintain backward compatibility during security updates.
How do I integrate security into a CI/CD pipeline (DevSecOps)?
DevSecOps integrates security checks into every stage of CI/CD. In the commit stage, run pre-commit hooks for secret detection (git-secrets, truffleHog). In the build stage, run SAST tools (Semgrep, CodeQL, SonarQube) and dependency scanning (npm audit, Snyk, Dependabot). In the test stage, run DAST tools (OWASP ZAP, Burp Suite) against staging environments. In the deploy stage, scan container images (Trivy, Grype) and validate Infrastructure as Code (Checkov, tfsec). Fail the pipeline on critical findings and track security debt alongside technical debt.