1.3 请求验证与过滤
- 输入验证:必填项、格式校验、类型校验。
- 防护机制:防止 SQL 注入、XSS、CSRF 攻击等。
- 身份验证:Session、JWT、OAuth、API 密钥等。
请求验证与过滤是确保应用安全性和数据完整性的重要环节。通过在后端对请求数据进行验证,可以防止非法或恶意请求对系统的破坏。这个过程包括对输入数据的验证、防护机制的引入以及身份验证的实现。具体内容如下:
1. 输入验证:确保请求数据的完整性和合法性
输入验证是指对用户提交的数据进行检查,确保其符合预期的格式、类型和要求。常见的输入验证方式包括:
- 必填项验证:确保请求中必需的字段没有缺失。
- 格式校验:验证输入数据的格式是否正确(如邮箱、电话号码、日期等)。
- 类型校验:确保输入数据的类型正确(例如数字、字符串、日期等)。
- 长度验证:限制字符串或数组的长度,防止过长的输入(如密码长度限制)。
- 范围验证:对数值型数据进行范围限制(如年龄不得小于 0 或大于 100)。
示例:
const Joi = require("joi"); // 使用 Joi 库进行验证
const schema = Joi.object({
username: Joi.string().min(3).max(30).required(), // 用户名必填且长度为3-30字符
password: Joi.string().min(6).required(), // 密码必填且最少6个字符
email: Joi.string().email().required(), // 验证邮箱格式
age: Joi.number().integer().min(18).max(100), // 年龄必须是18-100之间的整数
});
const { error, value } = schema.validate(req.body);
if (error) {
return res.status(400).send(error.details);
}
2. 防护机制:防止常见攻击
防护机制是指采取措施防止常见的安全攻击。常见的攻击方式包括 SQL 注入、XSS 攻击、CSRF 攻击等。防护措施包括以下几种:
SQL 注入(SQL Injection):
SQL 注入是攻击者通过在输入中插入恶意 SQL 代码,绕过身份验证或修改数据库内容。防止 SQL 注入的主要方法是:
- 使用 预编译语句(Prepared Statements),避免直接将用户输入拼接到 SQL 查询中。
- 对用户输入进行 过滤和转义,特别是对于数据库查询。
防止 SQL 注入的示例:
// 使用 MongoDB 的 Mongoose 防止 SQL 注入
const User = mongoose.model("User", UserSchema);
User.find({ username: req.body.username }).then((user) => {
if (user) {
res.send("User found");
}
});
XSS 攻击(Cross-Site Scripting):
XSS 攻击是通过在输入中插入恶意的 JavaScript 代码,利用浏览器漏洞来窃取数据或执行未授权操作。防止 XSS 攻击的方法:
- 转义输出:确保所有用户输入的数据在呈现时被安全转义。
- 使用 内容安全策略(Content Security Policy,CSP)来防止恶意脚本执行。
- 使用 HTML 编码库,比如
sanitize-html
来过滤潜在的危险字符。
防止 XSS 攻击的示例:
const sanitize = require("sanitize-html");
// 过滤输入中的恶意 HTML 标签
const safeInput = sanitize(req.body.input);
CSRF 攻击(Cross-Site Request Forgery):
CSRF 攻击是指攻击者伪造用户的请求,利用用户已经认证的状态在不知情的情况下执行恶意操作。防止 CSRF 攻击的方法:
- 使用 CSRF Token:在每个请求中生成唯一的令牌,服务器检查令牌的有效性。
- 使用 SameSite Cookies:防止跨站点请求伪造。
防止 CSRF 攻击的示例:
// 使用 CSRF Token 中间件
const csrf = require("csurf");
const csrfProtection = csrf({ cookie: true });
app.post("/submit", csrfProtection, (req, res) => {
// 验证 csrfToken
res.send("CSRF Token is valid");
});
3. 身份验证:确保用户身份的真实性
身份验证是指确认请求者身份是否合法。常见的身份验证方法包括:
Session:
基于服务器端存储的会话信息来管理用户状态。用户登录时,服务器会生成一个 Session ID,并将其存储在服务器中,同时返回给用户,并通过浏览器的 Cookie 保存在客户端。后续的请求会携带该 Session ID 来进行身份验证。
- 优点:易于实现和管理。
- 缺点:依赖服务器端存储,可能导致性能问题。
JWT(JSON Web Token):
JWT 是一种无状态的身份验证机制,客户端保存一个包含用户身份信息的加密令牌(Token)。每次请求时,客户端都会将该 Token 作为 Authorization 头部传给服务器,服务器验证 Token 的合法性并根据其内容识别用户身份。
- 优点:无状态,不需要在服务器端存储会话信息,适用于分布式系统。
- 缺点:Token 存在泄露风险,需要妥善保护。
OAuth:
OAuth 是一种授权机制,允许第三方应用代表用户访问其资源,而不需要用户提供用户名和密码。常用于社交登录(例如使用 Google、Facebook 账号登录)。
- 优点:提高安全性和便捷性,用户无需暴露账户密码。
- 缺点:实现较为复杂。
API 密钥:
API 密钥是客户端与服务器之间共享的密钥,通常用于在 API 请求中进行身份验证和授权。每个客户端都有唯一的密钥,服务器通过验证该密钥来确认请求的合法性。
- 优点:简单易用。
- 缺点:如果密钥泄露,可能会导致安全问题。
示例:使用 JWT 进行身份验证:
const jwt = require("jsonwebtoken");
// 生成 JWT
const token = jwt.sign({ userId: user._id }, "secretKey", { expiresIn: "1h" });
// 验证 JWT
jwt.verify(token, "secretKey", (err, decoded) => {
if (err) {
res.status(403).send("Token is invalid or expired");
} else {
req.userId = decoded.userId;
next();
}
});
总结
- 输入验证:确保用户输入符合预期格式、类型、长度等要求。
- 防护机制:防止 SQL 注入、XSS、CSRF 等常见攻击,提升应用的安全性。
- 身份验证:通过 Session、JWT、OAuth、API 密钥等方式,验证用户身份的真实性,防止非法访问。
这些措施共同帮助构建安全、可靠的应用程序,保护系统免受攻击和数据泄漏风险。