Node.js 是一个强大且流行的构建 Web 应用程序的环境。然而,与任何 Web 技术一样,它容易受到安全威胁,常见的包括 XSS、CSRF 和 SQL 注入。了解这些漏洞并实施强大的防御对于任何 Node.js 开发人员都至关重要。
跨站脚本 (XSS)
XSS 攻击涉及将恶意脚本注入其他用户查看的网页中,而这些脚本可以窃取用户数据、模拟用户执行操作并危及用户数据安全。常见的解决办法:
- 转义用户输入
- 内容安全策略 (CSP)
- 验证和清理输入
转义用户输入
在将用户输入呈现在页面上之前,始终转义用户输入,可以使用 escape-html 等库来完成。
ini
const escapeHtml = require("escape-html");
// example values
const desc = "I <b>think</b> this is good.";
const fullName = 'John "Johnny" Smith';
// example passing in text into a html attribute
console.dir('<input name="full_name" value="' + escapeHtml(fullName) + '">');
// -> '<input name="full_name" value="John "Johnny" Smith">'
// example passing in text in html body
console.dir('<textarea name="desc">' + escapeHtml(desc) + "</textarea>");
// -> '<textarea name="desc">I <b>think</b> this is good.</textarea>'
内容安全策略 (CSP)
实施 CSP Headers 以限制浏览器运行未经授权的脚本,可以使用 helmet 库来完成。
javascript
import express from "express";
import helmet from "helmet";
const app = express();
// Use Helmet!
app.use(helmet());
app.get("/", (req, res) => {
res.send("Hello world!");
});
app.listen(8000);
验证和清理输入
使用库 express-validator 来验证和清理输入数据。
javascript
const { body, validationResult } = require("express-validator");
app.post("/comment", [body("comment").trim().escape()], (req, res) => {
// handle the request
});
跨站请求伪造 (CSRF)
CSRF 攻击诱骗用户提交恶意请求,它们对于根据用户输入执行状态更改操作的应用程序尤其危险。常见的解决办法:
- 使用 CSRF 令牌
- 同站点 Cookie 规则
使用 CSRF 令牌
库 tiny-csrf 支持在客户端加密 cookie 以防止恶意攻击者查看。但使用这个库并不意味着解决了所有 CSRF 带来的安全隐患, 如果有非常强烈的安全需求(例如大规模生产应用程序、敏感信息、发出许多后端请求的单页应用程序),请参阅 OWASP 安全 并实施更严格的安全性。
php
const csurf = require("tiny-csrf");
const express = require("express");
const session = require("express-session");
let app = express();
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser("cookie-parser-secret"));
app.use(session({ secret: "keyboard cat" }));
// order matters: above three must come first
app.use(csurf("123456789iamasecret987654321look"));
同站点 Cookie 规则
使用库 express-session 设置 cookie 的 SameSite 属性,以防止浏览器随跨站点请求一起发送 cookie。
php
const session = require("express-session");
app.use(session({ cookie: { sameSite: "strict" } }));
SQL 注入
SQL注入涉及通过用户输入插入或操纵SQL查询,从而允许攻击者访问或修改数据库信息。常见的解决办法:
- 使用参数化查询
- 使用 ORM/ODM 库
使用参数化查询
在应用开发中避免将用户输入直接插入到 SQL 查询中,使用参数化查询来分离 SQL 逻辑和用户输入。
ini
const mysql = require("mysql");
const connection = mysql.createConnection(/* config */);
const userInput = "user input";
connection.query(
"SELECT * FROM users WHERE id = ?",
[userInput],
(error, results) => {
// handle results
}
);
使用 ORM/ODM 库
使用 ORM(对象关系映射)或 ODM(对象文档映射)库,如 Sequelize 或 Mongoose,它们本质上处理参数化查询。
ini
const User = require("./models/user");
User.findAll({ where: { username: req.body.username } });
其他安全措施
- 定期更新依赖项:定期更新依赖项以修补已知漏洞。
- 日志记录和监控:实施日志记录和监控以快速检测和响应可疑活动。
- HTTPS:使用 HTTPS 加密传输中的数据。
- 安全 Headers:利用
X-Frame-Options
和X-Content-Type-Options
等 HTTP 头来增强安全性。
总结
在 Node.js 开发中,安全永远不应该是事后才想到的。通过了解和减轻 XSS、CSRF 和 SQL 注入等风险,可以构建更强大、更安全的应用程序。