保护你的 Node.js 应用免受跨站请求伪造
《保护您的 Node.js 应用程序免受跨站点请求伪造》最初于 2018 年 1 月在Twilio 博客上发布。
跨站请求伪造(CSRF/XSRF ,简称C-Surf)是Web应用程序常见的一种典型攻击方式。攻击者利用这些攻击在应用程序中以用户的名义执行请求,而用户却浑然不知。让我们来看看他们是如何实现这一攻击的,以及我们如何保护我们的应用程序免受此类威胁。
让我们谈谈理论
在预防 CSRF 攻击之前,我们需要了解它们的工作原理。通常,这些攻击针对的是使用基于表单提交(例如POST
请求)和基于 Cookie 的身份验证的 Web 应用程序的功能。
攻击者在其恶意页面中放置一个隐藏表单,该表单会自动POST
向您的页面端点发出请求。然后,浏览器会自动将存储在该页面的所有 Cookie 随请求一起发送。例如,如果用户已登录当前会话,攻击者就可以在用户不知情的情况下,以登录用户的名义发送消息。攻击者无需访问页面的 Cookie 即可实现此目的。
我们可以通过使用 CSRF 令牌来保护自己免受此类攻击。其原理是,当浏览器从服务器获取页面时,它会将一个随机生成的字符串作为 CSRF 令牌以 Cookie 的形式发送。之后,当您的页面执行 POST 请求时,它会将 CSRF 令牌以 Cookie 的形式发送,或者以其他方式发送,例如通过正文中的参数或 HTTP 标头(例如X-CSRF-Token
)。
攻击者将无法使用隐藏表单重现相同的行为,因为他们无法访问 cookie 来检索值并将其与恶意 POST 请求一起发送。
这个概念几乎可以在任何 Web 应用程序中实现,但让我们看看如何在Express应用程序中实现它。
准备好董事会
首先,我们需要一个应用程序来了解 CSRF 漏洞的实际运作方式,以及如何进行防御。如果您已经有一个Express应用程序,请按照以下步骤操作。或者,您也可以按照以下步骤设置我们的演示应用程序。
在开始之前,请确保你已经安装了 [Node.js]( https://nodejs.org ] 和npm或其他包管理器。通过在终端中运行以下命令来启动新项目:
mkdir csrf-demo
cd csrf-demo
npm init -y
npm install express body-parser --save
接下来创建一个名为的新文件index.js
并将以下代码放入其中:
const express = require('express');
const bodyParser = require('body-parser');
const PORT = process.env.PORT || 3000;
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.get('/', (req, res) => {
res.send(`
<h1>Hello World</h1>
<form action="/entry" method="POST">
<div>
<label for="message">Enter a message</label>
<input id="message" name="message" type="text" />
</div>
<input type="submit" value="Submit" />
</form>
`);
});
app.post('/entry', (req, res) => {
console.log(`Message received: ${req.body.message}`);
res.send(`Message received: ${req.body.message}`);
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`);
});
通过运行以下命令启动应用程序:
node .
访问http://localhost:3000,您将看到Hello World
下面一个小表格。
危险水域
当前服务器有两个端点。一个是访问http://localhost:3000/ 时显示的主页。另一个是http://localhost:3000/entryPOST
上的端点。当我们填写表单并点击“提交”时,我们会向这个端点发出请求。POST
尝试在表单中输入一些文本并点击提交。你应该会看到返回的消息,并且它应该会记录到你正在运行的服务器的控制台中。
不幸的是,攻击者能够在其页面上执行相同的请求。为了模拟这种情况,我们在Glitch 的一个页面上实现了相同的表单。访问csrf-attack.glitch.me,输入消息并点击提交。其行为与在页面上提交表单相同localhost
。它会传输消息以及已设置的任何 Cookie。
在这种情况下,我们创建了一个用户可以自行提交的表单,但它可能是一个隐藏的表单,会自动提交恶意内容。让我们看看如何保护我们的页面免受此类攻击。
去csurf
有多个模块可以帮助你在应用程序中实现 CSRF 令牌。其中之一是csurf 。运行以下命令安装该模块以及cookie-parser依赖项:
npm install cookie-parser csurf --save
这两个模块都是中间件,可以在 Express 中改变请求的行为。我们已经使用它body-parser
来解析请求POST
体以检索消息。此外,我们还将使用它来检查_csrf
令牌。cookie-parser
中间件将检查令牌是否在 Cookie 中可用,并通过检查令牌是否同时存在于 Cookie 和请求体中且两者匹配,csurf
自动保护任何POST
、PUT
、PATCH
或操作。DELETE
_csrf
将以下代码添加到您的index.js
文件中以配置中间件:
const express = require('express');
const bodyParser = require('body-parser');
const csurf = require('csurf');
const cookieParser = require('cookie-parser');
const PORT = process.env.PORT || 3000;
const app = express();
const csrfMiddleware = csurf({
cookie: true
});
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(csrfMiddleware);
app.get('/', (req, res) => {
res.send(`
<h1>Hello World</h1>
<form action="/entry" method="POST">
<div>
<label for="message">Enter a message</label>
<input id="message" name="message" type="text" />
</div>
<input type="submit" value="Submit" />
<input type="hidden" name="_csrf" value="${req.csrfToken()}" />
</form>
`);
});
app.post('/entry', (req, res) => {
console.log(`Message received: ${req.body.message}`);
res.send(`CSRF token used: ${req.body._csrf}, Message received: ${req.body.message}`);
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`);
});
重启服务器并访问http://localhost:3000。在输入框中输入一些文本,然后点击Submit
。你应该会看到控制台中出现一条消息,并在浏览器中看到类似下面的欢迎消息:
现在切换回Glitch 的演示页面并在那里输入一条消息。点击提交后,您会看到请求失败,并且该消息不会显示在控制台中。cookie_csrf
已传输,但是页面在正文中发送的值POST
与_csrf
值不同。因此,该请求被中间件阻止csurf
,我们成功保护了自己免受 CSRF 攻击。
下一步是什么?
我们已经了解了如何轻松地将 CSRF 令牌集成到基于 Node.js 且代码为服务端渲染的应用程序中。然而,将 CSRF 令牌与您的前端框架和库结合使用也同样简单。由于我们将令牌作为 Cookie 发送,因此您可以轻松读取它,并将其作为标头随异步请求一起发送。事实上,AngularHttpClient
已经内置了此功能。
要了解如何保护 Node.js 应用程序,请务必查看我的博客文章“保护您的 Express 应用程序”。此外,您还应该查看OWASP 页面,因为它涵盖了广泛的安全相关主题。
如果您有任何问题或任何其他有用的工具来提高 Node.js Web 应用程序的安全性,请随时联系我:
- 🐦推特:@dkundel
- 📧邮箱:dkundel@twilio.com
- 🐙🐱GitHub:dkundel
《保护您的 Node.js 应用程序免受跨站点请求伪造》最初于 2018 年 1 月在Twilio 博客上发布。
文章来源:https://dev.to/dkundel/protect-your-nodejs-app-from-cross-site-request-forgery--46b9