Node.js 的 5 个常见服务器漏洞
在本文中,我们将讨论一些常见的服务器漏洞,并提供一些有关如何缓解这些漏洞的提示。
介绍
Node.js是一个强大且广泛使用的 JavaScript 运行时环境,用于构建服务器端应用程序。然而,与任何其他软件一样,Node 也有自己的一组漏洞,如果处理不当,可能会导致安全问题。请注意,这些漏洞并不是Node 所独有的,它们可以在每种后端编程语言中找到。
本文将探讨 5 个常见漏洞:
- 注入攻击
- 跨站脚本 (XSS)
- 拒绝服务 (DoS)
- 不正确的身份验证和授权
- 不安全的直接对象引用
1. 注入漏洞
节点应用程序容易受到注入攻击,例如SQL 注入、NoSQL 注入和命令注入。
当攻击者将恶意代码输入到易受攻击的应用程序并且该应用程序执行该代码时,就会发生此类攻击。
当不受信任的数据连接到 SQL 查询中时,注入漏洞可能是 SQL 注入。攻击者可以将恶意代码注入查询中,然后数据库可以执行该查询。
以下代码容易受到SQL注入:
ini
const express = require("express");
const app = express();
const mysql = require("mysql");
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "password",
database: "test",
});
app.get("/user", (req, res) => {
const id = req.query.id;
const query = `SELECT * FROM users WHERE id = ${id}`;
connection.query(query, (error, results) => {
if (error) {
throw error;
}
res.send(results);
});
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
在上面的示例中,id
查询字符串中的参数直接连接到 SQL 查询中。如果攻击者传递 的恶意值(id
例如 ),则1 OR 1=1
生成的查询将为SELECT * FROM users WHERE id = 1 OR 1=1
,这将返回users
表中的所有记录。哎呀!
为了防止此类漏洞,在使用数据库时验证用户输入并使用参数化查询非常重要 。在上面的示例中,这可以通过使用准备好的语句并将值绑定id
到查询来完成,如下所示:
ini
app.get("/user", (req, res) => {
const id = req.query.id;
const query = "SELECT * FROM users WHERE id = ?";
connection.query(query, [id], (error, results) => {
if (error) {
throw error;
}
res.send(results);
});
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
2. 跨站脚本(XSS)漏洞
XSS 攻击允许攻击者将恶意脚本注入其他用户查看的网页中。这可能会导致敏感信息被盗,例如登录凭据或其他敏感数据。为了防止 XSS 攻击,在将其发送到客户端之前清理所有用户生成的数据并对其进行验证非常重要。
以下是易受 XSS 攻击的易受攻击的代码示例:
ini
const express = require("express");
const app = express();
app.get("/", (req, res) => {
const name = req.query.name;
res.send(`<h1>Hello, ${name}</h1>`);
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
查询字符串中的参数name
直接包含在 HTML 响应中。如果攻击者要传递 的恶意值(name
例如 ),则<script>alert('XSS')</script>
生成的 HTML 将包含攻击者的恶意脚本。
如果您想尝试一下,请创建一个名为 的文件夹xss
。移至该文件夹并键入npm init -y
,然后键入npm i express
。创建一个名为的文件index.js
并粘贴上面的代码。运行文件 ( node index.js
) 后,导航到浏览器并访问localhost:3000
。要查看 XSS 攻击的实际情况,只需将您想要的代码添加到查询中,如下所示:
localhost:3000/?name=<script>alert('XSS')</script>
您应该看到一条警报消息:
为了防止此类漏洞,我们可以使用诸如escape-html
.
ini
const express = require("express");
const app = express();
const escapeHtml = require("escape-html");
app.get("/", (req, res) => {
const name = escapeHtml(req.query.name);
res.send(`<h1>Hello, ${name}</h1>`);
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
如果再次测试查询,您将看到不同的结果:
3. 拒绝服务 (DoS) 漏洞
DoS 攻击旨在使服务器过载并导致其崩溃。这可以通过多种方法来完成,例如向服务器发送大量请求或用数据淹没服务器。这可能会导致公司损失大量资金(如果攻击成功,每小时损失 20,000 美元)。
为了防止 DoS 攻击,实施速率限制、使用适当的错误处理并拥有强大的基础设施非常重要。
以下是一些容易受到 DoS 攻击的易受攻击的代码的示例:
javascript
const express = require("express");
const app = express();
app.get("/", (req, res) => {
// Do a resource-intensive operation
while (true) {}
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
在此示例中,服务器容易受到 DoS 攻击,因为它无法正确处理传入请求。如果攻击者向端点发送大量请求,服务器将在尝试执行无限循环时变得无响应。
为了防止此类漏洞,正确处理和验证传入请求并限制单个请求可以消耗的资源量非常重要。在上面的示例中,这可以通过使用中间件来限制最大请求数来完成。我们可以使用一个很好的包来为我们处理这个问题,express-rate-limit
并像这样使用它:
ini
const express = require("express");
const app = express();
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: "Too many requests, please try again later",
});
app.use(limiter);
app.get("/", (req, res) => {
res.send("Hello, World!");
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
4. 不当的认证和授权
不正确的身份验证和授权可能会导致未经授权访问敏感数据,从而导致盗窃或损坏。为了防止这种情况,实施正确的身份验证和授权方法非常重要,例如使用安全密码和双因素身份验证。
以下是容易受到不正确身份验证的代码示例:
ini
const express = require("express");
const app = express();
app.get("/secret", (req, res) => {
res.send("This is a secret page!");
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
在此示例中,/secret
端点没有得到适当的保护,任何知道 URL 的人都可以访问它。
为了防止此类漏洞,正确实施和强制执行身份验证机制非常重要。在上面的示例中,这可以使用身份验证中间件来完成,如下所示:
ini
const express = require("express");
const app = express();
const checkAuth = (req, res, next) => {
if (!req.session.user) {
return res.status(401).send("Unauthorized");
}
next();
};
app.get("/secret", checkAuth, (req, res) => {
res.send("This is a secret page!");
});
app.listen(3000, () => {
console.log("Example app listening on port 3000!");
});
在此示例中,checkAuth
中间件用于在访问/secret
端点之前检查用户是否经过身份验证。如果用户未通过身份验证,中间件将返回401 Unauthorized
响应。
5. 不安全的直接对象引用
就像不正确的授权一样,在不安全的直接对象引用中,攻击者可以直接访问和操作对象,绕过预期的安全控制。以下是 Node.js 中此类漏洞的示例:
ini
const express = require("express");
const app = express();
const users = [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Doe" },
];
app.get("/user/:id", function (req, res) {
let user = users.find((user) => user.id == req.params.id);
if (!user) {
res.status(404).send("User not found");
return;
}
res.send(user);
});
app.listen(3000);
在上面的示例中,代码users
根据id
URL 中传递的参数(例如/user/1
)从数组中检索用户。这是不安全的直接对象引用的典型示例,因为攻击者可能会操纵id
URL 中的参数来访问其他用户的数据。为了缓解此漏洞,代码应检查正在检索的用户是否有权由当前用户访问。
结论
总之,Node.js 是一项强大且广泛使用的技术,但了解潜在的漏洞也很重要。通过遵循最佳实践并采取主动措施,您可以确保 Node 应用程序的安全并保护敏感数据。请随意在您的计算机上运行代码片段并进行试验。