充分的数据保护和用户保密是网页开发者的主要责任。因此,在构建 API 终端时,确保最高可能的安全性至关重要。
应用程序安全是客户端和服务器开发者共同的责任,一方的疏忽可能会造成灾难性后果。统计数据显示,2023 年的数据泄露导致全球超过 800 万个数据记录暴露。
在本文中,我将重点介绍 API 安全的关键领域,其中包括数据验证。这个概念对帮助您保护 API 免受通过恶意用户数据进行的网络攻击非常重要。这个教程非常适合所有后端开发者,无论经验多少。
为了能够跟随本教程,这里有一些先决条件:
- Node.js 知识
- npm 和包安装知识
有了这些准备,让我们开始吧。
(本文内容参考:java567.com)
数据验证是如何工作的?
首先,什么是数据验证?数据验证简单来说就是确保来自外部来源的数据在进行进一步数据处理之前的准确性和可靠性。
这是 Web API 安全的关键组成部分,因为它对于防止网络注入攻击、SQL 攻击和 NoSQL 攻击至关重要。要了解更多信息,您可以查看此链接。
请注意,数据验证不仅仅需要在以下后端操作中进行:
- 用户登录和注册
- 响应查询
- 更新服务器数据库
所有这些都可能被恶意黑客利用,以获取对服务器数据库的访问权限,并获取敏感用户详细信息,甚至通过格式化整个数据库来制造混乱。
流行的数据验证工具
到目前为止,有很多工具可以帮助程序员在 API 开发中实现高效的数据验证。
它们帮助您避免重新发明验证数据的长正则表达式代码的轮子。它们提供了大量功能,包括错误处理和验证定制功能。
其中一些工具包括:
- Joi
- Zod
- Yup
- AJv
- Valibot
- Validator.js
- Superstruct
为了进一步阐明这些工具,我们将比较上述最受欢迎的数据验证工具中的一些。
数据验证工具的优缺点
为了进一步让您了解这些 JavaScript 验证工具,我将重点介绍其中三种流行的 JavaScript 验证工具的一些优缺点。
Joi
优点
- 拥有强大的、庞大的用户社区和开发支持
- 具有处理复杂验证的内置功能
缺点
- 其语法相当冗长
Zod
优点
- 与 TypeScript 项目轻松兼容
- 具有高效的错误处理能力
缺点
- 不支持异步验证。
Yup
优点
- 主要使用声明性语法设置其验证工具,从而赋予其简单性
- 具有可比较的快速性能。
缺点
- 不提供自定义功能
- 其处理复杂验证的能力有限
为了本教程的目的,我们将使用 Joi 作为我们的数据验证工具。
简介 Joi
Joi 是一个简单高效的基于 JavaScript 的数据验证工具,它基于模式类型配置。
它具有用于验证各种形式数据出现的内置功能,但不限于布尔值、字符串、函数和区间。它还可以处理复杂的验证操作。
此外,它提供了最小化的缓存功能。有关该工具的更多信息可以在此处找到。
如何设置 Joi
在本节中,我们将在本地环境中设置 Joi。要安装 Joi,请通过命令行导航到代码文件夹,并运行以下命令:
npm i joi
应该显示安装成功的消息。完成后,我们可以演示在我们的演示 API 中使用 Joi 验证用户注册的强大功能。
演示项目
在这个项目中,您将使用 Joi 来验证从客户端接收到的用于在服务器上注册的输入。可以在这里找到用于 Node.js 应用程序的用户注册功能的默认代码。
继续将已安装的 Joi 包导入到您的代码中:
const Joi = require("joi");
在编写我们的注册控制器之前,我们将在代码文件中初始化 Joi 库:
const SignUpSchema = Joi.object({});
在这个项目中,我们将验证从客户端接收到的 email、password 和 username 参数。
const SignUpSchema = Joi.object({
email: Joi.string().email({
minDomainSegments: 2,
tlds: {
allow: ['com', 'net']
}
}),
username: Joi.string().alphanum().min(3).max(15).required(),
password: Joi.string().min(8).required()
});
email 参数对象确保电子邮件地址是一个字符串,并且域站点限制为 .com 和 .net,不允许其他形式的域。
对于 username 参数,它确保它是一个包含字母和数字的字符串,最小字符数为 3,最大字符数为 15。required 函数确保必须满足这些条件,否则整个请求将无法通过验证。
password 参数确保提供的密码是以字符串格式提供的,最小字符数为 8,并且也是必需的。
要将其应用到我们的端点中,我们将其包含在控制器函数中:
const { error, value } = SignUpSchema.validate(req.body, { abortEarly: false });
if (error) {
res.status(400).json(error.details);
return;
}
此函数在将用户详细信息插入数据库之前执行。模式尝试验证接收到的输入,然后如果成功验证,继续到数据库。
abortEarly 功能包括以允许评估所有参数。如果有任何错误,所有错误都将显示出来。
以上内容也可以在登录控制器函数中复制。您还可以查看 Joi 使用其他复杂验证选项的文档。
项目的最终代码如下所示:
const jwt = require("jsonwebtoken");
const userSchema = require("../Schema/User");
const Joi = require("joi");
const bcrypt = require("bcrypt");
const { createNewColumn, checkRecordsExists, insertRecord } = require('../utils/sqlSchemaFunction');
const generateAccessToken = (use) => {
return jwt.sign({ userID: use }, process.env.JWT, { expiresIn: "1d" });
}
const SignUpSchema = Joi.object({
email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } }),
username: Joi.string().alphanum().min(3).max(15).required(),
password: Joi.string().min(8).required()
});
const loginSchema = Joi.object({
email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } }),
password: Joi.string().min(8).required()
});
const register = async (req, res) => {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
res.status(400).json("Please supply the email or password");
return;
}
const { error, value } = SignUpSchema.validate(req.body, { abortEarly: false });
if (error) {
res.status(400).json(error.details);
return;
}
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
const user = {
username: req.body.username,
email: email,
password: hashedPassword
};
try {
const userAlreadyExists = await checkRecordsExists("users", "email", email);
if (userAlreadyExists) {
res.status(400).json("Email must be unique");
} else {
await insertRecord("users", user);
res.status(200).json("User created successfully");
}
} catch (err) {
res.status(500).json({ err: err.message });
}
};
module.exports = { register };
在 Postman 中进行 API 测试
确保代码遵循我们定义的模式,结果是成功执行的。
结论
至此,教程已经结束。希望您已经了解了数据验证、各种数据验证工具以及数据验证最佳实践。
(本文内容参考:java567.com)