当你的应用处理 敏感金融交易、用户隐私数据 和 关键业务逻辑 时,安全威胁成为头号天敌。本期我们将为 NestJS 应用打造完整的防御体系,构建坚不可摧的安全堡垒。
一、安全威胁全景图:现代 Web 应用的8大风险
graph TD
A[SQL注入] -->|攻击数据库| B[数据泄漏]
C[XSS跨站脚本] -->|窃取用户凭证| D[账户劫持]
E[CSRF] -->|伪造交易| F[资金损失]
G[暴力破解] -->|弱密码入侵| H[权限越权]
I[信息泄露] -->|暴露敏感数据| J[商业损失]根据 OWASP Top 10 最新威胁报告,以下攻击占比最高:
- 访问控制失效 (34%)
- 加密机制缺失 (28%)
- 注入攻击 (21%)
- 不安全的配置 (14%)
二、加固基础:HTTPS 全球加密
1. 自动启用 HTTPS
// main.ts
import * as fs from 'fs';
async function bootstrap() {
const httpsOptions = {
key: fs.readFileSync('./secrets/private-key.pem'),
cert: fs.readFileSync('./secrets/certificate.pem'),
};
const app = await NestFactory.create(AppModule, {
httpsOptions,
});
// 生产环境强制HTTPS
if (process.env.NODE_ENV === 'production') {
app.use((req, res, next) => {
if (!req.secure) {
return res.redirect(301, `https://${req.headers.host}${req.url}`);
}
next();
});
}
}2. HSTS 超文本安全协议
app.use(
helmet.hsts({
maxAge: 15552000, // 180天有效期
includeSubDomains: true,
preload: true,
})
);三、认证防线:JWT 安全深度实践
1. JWT 攻击面防护
| 威胁类型 | 防御策略 | NestJS实现 |
|---|---|---|
| 令牌篡改 | 强签名算法 (RS256) | secretOrPrivateKey |
| 重放攻击 | JTI唯一标识符 + 短期令牌 | jwtid + expiresIn |
| 令牌泄露 | 刷新令牌机制 + 令牌吊销 | 黑名单验证 |
2. JWT 安全增强实现
// auth.service.ts
import { JwtService } from '@nestjs/jwt';
import * as crypto from 'crypto';
@Injectable()
export class AuthService {
constructor(
private jwtService: JwtService,
private redis: RedisService
) {}
// 生成带唯一ID的令牌
createAccessToken(payload: UserPayload) {
const jti = crypto.randomUUID();
const token = this.jwtService.sign(
{...payload, jti},
{ algorithm: 'RS256' } // 使用非对称加密
);
// 存储令牌ID(短期缓存)
this.redis.set(`token:${jti}`, 'valid', 'EX', 60*15); // 15分钟
return token;
}
// 验证令牌的有效性
async verifyToken(token: string) {
try {
const payload = this.jwtService.verify(token);
// 检查令牌是否被吊销
const exists = await this.redis.get(`token:${payload.jti}`);
if (!exists) throw new UnauthorizedException('令牌无效');
return payload;
} catch (e) {
throw new UnauthorizedException('令牌验证失败');
}
}
}3. 刷新令牌方案
@Post('refresh-token')
async refreshToken(@Body() { refresh_token }: RefreshTokenDto) {
// 验证刷新令牌有效性
const payload = this.jwtService.verify(refresh_token, {
algorithms: ['RS256'],
});
// 检查令牌是否被使用过
const used = await this.redis.get(`refresh_used:${payload.jti}`);
if (used) {
// 检测到重放攻击,立即吊销所有令牌
await this.revokeUserTokens(payload.sub);
throw new ForbiddenException('安全事件:检测到异常活动');
}
// 标记刷新令牌已使用
await this.redis.set(`refresh_used:${payload.jti}`, 1, 'EX', 86400); // 24小时
// 签发新访问令牌
return {
access_token: this.createAccessToken({ sub: payload.sub }),
refresh_token: this.createRefreshToken(payload.sub),
};
}四、前端攻击防御:XSS 与 CSRF 防护
1. Helmet 强化 HTTP 头部
// main.ts
import * as helmet from 'helmet';
app.use(helmet());最佳防护组合:
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "trusted.cdn.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "image.cdn.com"],
connectSrc: ["'self'", "api.example.com"],
reportUri: '/csp-violation-report',
},
},
referrerPolicy: { policy: 'same-origin' },
frameguard: { action: 'deny' },
hsts: { maxAge: 15552000 },
noSniff: true,
xssFilter: true,
})
);2. CSRF Token 双重验证
// 启用 CSRF 防护
import * as csurf from 'csurf';
app.use(cookieParser());
app.use(csurf({ cookie: true }));
// 前端配置
@Module({
imports: [
ConfigModule.forRoot({
csrf: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'strict',
domain: 'yourdomain.com',
},
}),
],
})
export class SecurityModule {}五、访问控制网关:速率限制与 IP 过滤
1. 请求限流防御 DDoS
// 安装依赖
npm install --save @nestjs/throttler
// app.module.ts
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
@Module({
imports: [
ThrottlerModule.forRoot({
ttl: 60, // 限流时间窗口(秒)
limit: 100, // 允许请求次数
ignoreUserAgents: [/(nestify|googlebot)/i], // 搜索引擎白名单
}),
],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard, // 全局启用
},
],
})2. 动态 IP 黑名单
// 黑名单守卫
@Injectable()
export class IpFilterGuard implements CanActivate {
constructor(
private ipBlacklist: Set<string>,
@Inject('REQUEST') private req: Request // 使用请求作用域
) {}
canActivate(): boolean {
const clientIp = this.req.headers['x-forwarded-for'] ||
this.req.socket.remoteAddress;
if (this.ipBlacklist.has(clientIp)) {
throw new ForbiddenException('访问被拒绝');
}
return true;
}
}
// 动态添加恶意IP
@Post('report/attack')
reportAttack(@Body() data: AttackReport) {
this.ipBlacklistService.add(data.attackerIp);
this.logger.warn(`检测到攻击IP:${data.attackerIp}`);
}六、输入验证防火墙:抵御注入攻击
1. SQL 注入防御方案
// 参数化查询防御SQL注入
@Injectable()
export class UserRepository {
async findUser(username: string) {
return this.dataSource.query(
`SELECT * FROM users WHERE username = $1`,
[username] // 使用参数化查询
);
}
}
// 禁止动态拼接查询
// ❌ 危险写法:`SELECT * FROM users WHERE role = '${role}'`2. XSS 输入消毒引擎
// pipes/xss-sanitize.pipe.ts
import * as sanitizeHtml from 'sanitize-html';
export class XssSanitizePipe implements PipeTransform {
transform(value: any) {
return sanitizeHtml(value, {
allowedTags: [],
allowedAttributes: {},
});
}
}
// 控制器应用
@Post('comment')
createComment(@Body('content', new XssSanitizePipe()) content: string) {
// 已被消毒的内容
}七、敏感数据保护:全链路加密方案
1. 传输加密配置
# crypto.config.ts
export default registerAs('crypto', () => ({
algorithm: 'aes-256-gcm',
key: process.env.CRYPTO_KEY,
ivLength: 16, // 初始向量长度
}));2. 端到端数据加密
// lib/crypto.ts
import crypto from 'crypto';
import * as config from './crypto.config';
export function encrypt(text: string): string {
const iv = crypto.randomBytes(config.ivLength);
const cipher = crypto.createCipheriv(
config.algorithm,
Buffer.from(config.key),
iv
);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return `${iv.toString('hex')}:${encrypted}`;
}
export function decrypt(encryptedText: string): string {
const [ivHex, encrypted] = encryptedText.split(':');
const iv = Buffer.from(ivHex, 'hex');
const decipher = crypto.createDecipheriv(
config.algorithm,
Buffer.from(config.key),
iv
);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}3. 安全审计日志加密
// audit-log.service.ts
import { encrypt } from './lib/crypto';
@Injectable()
export class AuditLogService {
async logSecurityEvent(event: SecurityEvent) {
const encrypted = encrypt(JSON.stringify({
...event,
timestamp: new Date(),
}));
await this.repo.saveEncryptedLog(encrypted);
}
}八、金融级安全实战:银行交易系统防护
1. 安全架构设计
graph TD
A[客户端] -->|HTTPS+证书锁定| B[API网关]
B -->|JWE加密| C[用户服务]
C -->|双重认证| D[交易系统]
D -->|加密队列| E[清算系统]
E -->|硬件加密模块| F[银行核心]2. 交易防篡改实现
@Post('transfer')
@UseInterceptors(SignatureInterceptor)
async transferFunds(
@Body() transferDto: TransferDto,
@CurrentUser() user: User,
) {
// 1. 验证交易签名
const isValid = crypto.verify(
'sha256',
Buffer.from(transferDto.contract),
user.publicKey,
Buffer.from(transferDto.signature, 'base64')
);
if (!isValid) throw new ForbiddenException('非法交易');
// 2. 交易密码验证
if (!await argon2.verify(user.transactionKey, transferDto.password)) {
this.audit.logSecurityEvent({
event: 'TRANSACTION_PWD_FAIL',
userId: user.id,
ip: request.ip,
});
throw new UnauthorizedException('交易密码错误');
}
// 3. 大额交易额外验证
if (transferDto.amount > 50000) {
const verificationCode = await this.smsService.sendOTP(user.phone);
this.transactionCache.set(user.id, verificationCode, 300); // 5分钟有效
throw new PaymentAuthException('需要短信验证');
}
}3. 全链路安全事件监控
// 全局安全事件拦截器
@Injectable()
export class SecurityInterceptor implements NestInterceptor {
constructor(
private audit: AuditLogService,
private threatIntel: ThreatIntelligenceService
) {}
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest();
// 检查IP信誉
const riskScore = this.threatIntel.checkIp(request.ip);
if (riskScore > 7) {
throw new ForbiddenException('高风险来源');
}
return next.handle().pipe(
tap(() => {
// 记录安全事件
this.audit.logRequest(request);
}),
catchError(error => {
// 异常类型分类记录
this.audit.logSecurityEvent({
event: 'API_ERROR',
path: request.path,
status: error.getStatus(),
});
throw error;
})
);
}
}九、自动化安全检测流水线
1. 依赖安全扫描
# 安装安全扫描工具
npm install -g auditjs
# 集成到CI流水线
- name: Dependency Scan
run: |
auditjs
if grep -l "Critical vulnerabilities" auditjs-report.html; then
exit 1
fi2. 容器安全扫描
# 使用Trivy扫描镜像
docker scan --severity=HIGH your-image:latest3. SAST静态扫描
- name: SAST Code Scan
uses: shiftleft/sast-scan@v2
with:
type: "nest"
fail: true十、避坑指南:安全实现陷阱
❌ 错误1:日志泄露敏感信息
// 错误:打印完整请求体
console.log(`支付请求:${JSON.stringify(req.body)}`);
// 正确:过滤敏感字段
const { password, cvv, ...safeData } = req.body;
this.logger.log(safeData);❌ 错误2:错误的加密方式
// 错误:使用弱加密算法
crypto.createCipher('aes128', key) // 不再安全!
// 正确:使用AEAD模式
crypto.createCipheriv('aes-256-gcm', key, iv)❌ 错误3:缺乏异常边界
// 错误:暴露系统信息
res.status(500).json({ error: e.stack })
// 正确:标准化错误返回
{
"errorCode": "SYS500",
"message": "系统错误,请稍后再试"
}十一、安全测试实验室
Burp Suite 攻击模拟
- SQL注入测试:
GET /users?id=1' OR 1=1-- - XSS测试:
POST /comment {"content": "<script>alert(1)</script>"} - CSRF测试: 模拟构造表单
POST /transfer - 速率检测: Gatling 模拟1000请求/秒
渗透测试结果报告
| 测试项目 | 结果 | 风险等级 | 解决方案 |
|---|---|---|---|
| SQL注入 | ⚪ 通过 | 安全 | 无需处理 |
| XSS攻击 | 🔴 未阻挡 | 高风险 | 启用消毒管道 |
| CSRF防护 | ⚠️ 部分通过 | 中风险 | 强化Token校验 |
| JWT令牌失效 | 🔴 未实现 | 高风险 | 添加黑名单机制 |
十二、下期预告:性能调优大师
《百万并发下的 NestJS 性能调优》 将揭示:
➠ Node.js 底层的性能陷阱
➠ 内存管理优化策略
➠ I/O 密集场景优化方案
➠ 集群模式下的扩展
➠ 实战:压力测试与优化指标
安全挑战:
✍️ 在本地搭建安全实验室,发现并修复应用中的一个安全漏洞并分享过程!
通过本期全面加固,你已掌握金融级安全能力:
✅ HTTPS全站加密 + HSTS策略
✅ 增强型JWT认证架构
✅ XSS与CSRF多重防护
✅ 速率限制与IP过滤
✅ 注入攻击防御方案
✅ 全链路数据加密
✅ 安全审计与日志监控
✅ 自动化安全检测流水线
架构价值:这些安全技能可直接应用于银行系统、支付网关、医疗系统等高安全要求场景,满足GDPR、PCI DSS等国际安全标准。
相关推荐
- NestJS 从入门到精通 11:综合实战 - 构建知乎风格的全栈社区平台(下) 2025-06-24
- NestJS 从入门到精通 10:综合实战 - 构建知乎风格的全栈社区平台(上) 2025-06-24
- NestJS 从入门到精通 09:性能调优大师 - 百万并发下的极致优化策略 2025-06-24
- NestJS 从入门到精通 07:配置管理与部署实战 - 多环境与容器化方案 2025-06-24
- NestJS 从入门到精通 06:GraphQL 现代 API 开发 - 解决 RESTful 之痛 2025-06-24
评论0
暂时没有评论