NodeJS全栈开发面试题讲解——P6安全与鉴权
✅ 6.1 如何防止 SQL 注入 / XSS / CSRF?
面试官您好,Web 安全三大经典问题分别从不同层面入手:
🔸 SQL 注入(Server端)
原理:恶意用户将 SQL 注入查询语句拼接,导致数据泄露或破坏。
防御手段:
-
使用 ORM / 预编译语句(PreparedStatement)
-
如 Sequelize / Prisma / TypeORM 都默认使用参数化查询
-
-
不拼接 SQL 字符串
-
坚决杜绝字符串拼接构造查询
-
-
对用户输入做严格校验(如白名单、正则)
✅ 示例(Sequelize ORM):
User.findOne({ where: { username: req.body.username } }); // 安全
🔸 XSS(跨站脚本攻击)
原理:用户输入恶意脚本插入页面,在其他用户浏览时触发执行。
防御手段:
-
前端输出内容必须做转义(如 DOMPurify、Vue/React 默认做)
-
后端返回的数据也可二次 HTML encode
-
设置 CSP(内容安全策略)响应头:
Content-Security-Policy: default-src 'self'
🔸 CSRF(跨站请求伪造)
原理:攻击者诱导用户点击链接,悄悄向另一个站点发起请求。
防御手段:
-
使用 SameSite Cookie 策略(推荐 SameSite=Strict)
-
使用 CSRF Token 校验(如
csurf
中间件) -
对敏感操作用 POST,并验证 Referer 头来源
✅ 6.2 JWT 如何签发与验证?如何防止伪造?
JWT 是一种轻量的无状态认证方案,我在 NestJS 项目中用得很多。
🧩 JWT 签发过程:
-
用户登录成功后,服务端使用 私钥(或对称密钥) 生成 token:
const token = jwt.sign({ uid: user.id }, SECRET_KEY, { expiresIn: '2h' });
-
客户端将 token 存储于:
-
安全性优先:HttpOnly Cookie
-
灵活性优先:localStorage(要防 XSS)
-
🧩 验证 token:
后端中间件提取请求头中的 token 并使用相同密钥解码:
jwt.verify(token, SECRET_KEY);
❗防止伪造方法:
-
密钥不能泄露,必须使用 非对称加密(如 RS256) 或强对称密钥
-
建议使用 JWT 的 签发者(iss)和用途(aud) 字段限制滥用
-
设置合理的过期时间(短 token + 刷新机制)
✅ 6.3 登录接口如何防止暴力破解?加密算法用什么?
登录接口是攻击高发点,我从「加密、频率限制、验证码」三方面防护:
🔒 密码加密:
-
使用 bcrypt 加密(推荐 10 ~ 12 轮 salt):
const hash = await bcrypt.hash(password, 10);
const isMatch = await bcrypt.compare(inputPassword, hash);
-
bcrypt 是基于 Blowfish 的算法,具备慢哈希特性,抗暴力破解。
🚨 防止暴力破解:
-
IP / 用户名 尝试次数限制:如 5 分钟内登录失败 5 次封号
-
可结合 Redis 实现计数
-
-
登录接口接入验证码(如图形验证码、滑动验证)
-
接入行为分析 / 登录地判断(如风控中台)
✅ 6.4 如何对文件上传做安全校验?
文件上传是黑客最容易钻空子的地方,需要严格限制上传内容和行为。
🛡️ 安全措施:
风险类型 | 对策 |
---|---|
恶意脚本文件 | 限制 MIME 类型(白名单)、校验扩展名和真实类型 |
木马图片 | 使用 file-type 或 mime 判断内容头部 |
大文件拖垮服务器 | 限制上传大小(如 5MB) |
路径穿越攻击 | 不允许用户自定义文件路径;统一保存在 sandbox |
文件名注入 | 生成唯一名(如 UUID),避免原始文件名冲突 |
✅ 示例(NestJS 文件上传验证):
@UseInterceptors(FileInterceptor('file', {fileFilter(req, file, cb) {const isImage = file.mimetype.startsWith('image/');cb(null, isImage);},limits: { fileSize: 5 * 1024 * 1024 }, // 限 5MB
}))
✅ 6.5 如何加密用户密码?用什么算法?
用户密码必须做 不可逆加密(单向散列)并加盐。
推荐算法:bcrypt(或 argon2)
-
bcrypt 是加盐 + 慢哈希算法(抗彩虹表 + 抗暴力破解)
-
NestJS 和 Express 项目中推荐使用
bcryptjs
或bcrypt
模块
加密流程:
const saltRounds = 10;
const hashedPwd = await bcrypt.hash(password, saltRounds);
-
登录时使用
compare
方法比对:
const isMatch = await bcrypt.compare(inputPassword, storedHash);
其他备选算法(了解即可):
算法 | 特点 |
---|---|
SHA256 | 不加盐容易被反查,已不推荐 |
Argon2 | 更安全但较新,适合新系统使用 |
PBKDF2 | 可以加盐、加轮次,银行业常用 |
✅ 总结回顾
编号 | 问题 | 要点简述 |
---|---|---|
6.1 | SQL/XSS/CSRF 防护 | ORM 防注入、DOM转义防 XSS、CSRF Token + SameSite |
6.2 | JWT 签发与校验 | 签名加密、有效期、对称/非对称加密、避免暴露密钥 |
6.3 | 登录暴破防护 | bcrypt 加密、IP 限制、验证码、行为识别 |
6.4 | 文件上传安全 | 检查 MIME 类型、文件大小、存储路径唯一、过滤木马 |
6.5 | 密码加密算法选择 | 推荐 bcrypt / argon2,使用盐值,严禁存储明文密码 |