REST APIs与微服务:关键差异
TypeScript CSRF保护指南:示例及如何启用
在安全领域,CSRF(跨站请求伪造)是最难缓解和阻止的漏洞之一。此类攻击不仅在网络上无处不在,而且其潜在损害也是无法估量的。
本文旨在为 JavaScript、TypeScript 和 Node.js 工程师提供 CSRF 防护的起点。我们将简要介绍什么是 CSRF,探讨一些 CSRF 攻击的示例,并最终提供一些针对 CSRF 攻击的缓解策略。
需要记住的是,尽管本文重点介绍 Node.js 开发堆栈,并且示例是用 JavaScript 编写的,但基本策略适用于任何技术堆栈。您不需要精通 Node.js 或 TypeScript。但是,需要对 JavaScript 有基本的了解。
让我们立即开始吧。
使用 Node.js 和 TypeScript 重新开始
好的,让我们准备简单的样板项目,以便您可以试用代码并跟随这篇文章。
首先,确保已安装 Node.js。您可以在 macOS 中运行以下命令来执行此操作:
curl "https://nodejs.org/dist/latest/node-${VERSION:-$(wget -qO- https://nodejs.org/dist/latest/ | sed -nE 's|.*>node-(.*)\.pkg</a>.*|\1|p')}.pkg" > "$HOME/Downloads/node-latest.pkg" && sudo installer -store -pkg "$HOME/Downloads/node-latest.pkg" -target "/"
或者,您可以使用 Homebrew 通过以下命令进行安装:
brew install nodejs
现在,创建一个 Node.js 项目非常简单。只需创建一个名为“nodejs_typescript_sample”的文件夹(您可以随意命名此文件夹)并导航到该文件夹。进入后,创建一个名为“app.js”的文件(我们建议您这样命名)并粘贴以下代码:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
完成后,您可以转到终端并使用以下命令运行代码:
node app.js
访问http://localhost:3000,您将看到一条消息“Hello World”。
很简单,对吧?
澄清 CSRF
简单来说,CSRF(也称为XSRF),顾名思义,是一种依赖用户权限通过劫持用户会话来获取其数据访问权限的攻击。
利用这种方法,攻击者可以欺骗用户以他们的名义提交恶意请求,从而规避我们平台的安全性。
CSRF 攻击之所以可能发生,主要有两个原因。
- 首先,CSRF 攻击利用了用户无法辨别合法 HTML 元素是否包含恶意代码的能力。
- 其次,由于这些攻击来自合法用户,我们设计的保护机制不起作用。因此,这让坏人得以误导用户进行自我破坏。
此外,恶意攻击者可以隐藏 HTML 元素,并通过聊天或电子邮件等渠道使用社交工程策略,从而产生重大影响。由于这些漏洞似乎来自普通用户的可信来源,因此这会劫持他们对日常所依赖的系统的信任。
CSRF 攻击示例
现在,让我们通过以下示例来探讨 CSRF 攻击如何劫持系统。
- 用户收到一封看似来自可信来源的电子邮件。假设攻击者模仿了银行机构的格式和外观,并设法掩盖了发件人的电子邮件,使其看起来足够合法。
- 我们的受害者,我们那位不懂技术的阿姨,看到了这封电子邮件,邮件中紧急提醒她点击一个链接来检查银行标记为可疑的异常交易。
- 然后我们的阿姨匆忙答应了,点击了链接,没有核实其来源的真实性。然后她被带到了银行网站。
- 该网站合法,没有任何欺诈迹象。它甚至显示为安全,并且 URL 与网站相符。
- 然后她选择丢弃该电子邮件或致电银行。
现在,这里可能发生无数事情。例如,当我们的受害者点击恶意链接时,目标 URL 可能会利用新的经过身份验证的会话(或者只是在登录时打开一个选项卡之类的简单操作)并对易受攻击的 Web 应用程序执行数据库更改。造成危害的可能性无穷无尽。
请记住,CSRF 的背后还有更多内容。遗憾的是,探究它如何利用网络协议中的漏洞的复杂性超出了本文的讨论范围。
但是,如果您想更深入地了解 CSRF 的海洋及其工作原理,我们建议您阅读我们的姊妹文章,其中对此进行了更详细的解释。
如何缓解 Node.js 和 TypeScript 中的 CSRF 漏洞
现在我们已经了解了捕获用户会话是多么轻松,让我们探索一些针对 CSRF 攻击的缓解措施。
路由结构
我们需要做的第一件事是重新考虑我们网站的路由结构的设计。
CSRF 攻击利用接受执行状态更改的 GET 请求的系统。这种模式已经是一种糟糕的做法,您应该在所有情况下都避免它们。
幸运的是,在 Express 中解决这个问题相对简单。您需要做的就是更改路由文件(通常称为“index.js”),并将应用程序的操作设置为接收 POST 或 PUT,而不是 GET 以进行状态更改。
当然,这一变化确保您遵循 HTTP 协议指南。
//router.get('/posts/create', sessionController.validateSession, postsController.postsCreate);
router.post('/posts/create', sessionController.validateSession, postsController.postsCreate);
最终你会得到类似下面的结果:
请注意,所有状态改变请求都不是 GET。
请记住,这种方法无法保护我们免受 JavaScript 自动提交 POST 的表单标签的攻击。
此外,攻击者可以调整他们的漏洞以适应 JavaScript Ajax 请求并提交实现其目标所需的任何协议或参数。
动作确认
建议所有开发人员在所有关键状态改变操作中 实现确认机制。
在提交之间实现中间步骤,要求用户确认其操作,大大减少了 CSRF 攻击的范围。
然而,在需要频繁更改的系统中,一些用户可能会发现这个多步骤的过程很麻烦和乏味,因此请在适当的时候使用它。
此类基于设计的安全功能在重要的管理系统和账户管理门户中随处可见。
CSRF 令牌
最后,我们可以实施的最有效的缓解策略是使用 CSRF 令牌来验证来自客户端的每个请求。
这些令牌通过将用户会话链接到服务器生成的令牌来工作,服务器根据请求验证这些令牌。
令牌在所有表单中都以隐藏字段的形式存在。因此,当客户端继续提交表单时,它包含一个验证凭证,表明用户有意执行此操作。
为了在 Node.js 中实现 CSRF 令牌,我们可以使用“ csurf ”模块来创建和验证令牌。
const cookieParser = require('cookie-parser'); // CSRF Cookie parsing
const bodyParser = require('body-parser'); // CSRF Body parsing
var csrf = require('csurf');
/**
* App Variables
*/
const app = express();
// Middlewares
var csrfProtect = csrf({ cookie: true })
app.get('/form', csrfProtect, function(req, res) {
// Generate a tocken and send it to the view
res.render('send', { csrfToken: req.csrfToken() })
})
app.post('/posts/create', parseForm, csrfProtect, function(req, res) {
res.send('data is being processed')
})
必须将此更改应用于主 app.js 类文件,使其看起来像下面这样:
请注意,我们在这里添加了路由代码,但您可以将其放在单独的路由类“index.js”文件中。
完成此操作后,您可以修改所有请求和响应路由以在需要时使用令牌。
此外,您必须在应用程序的所有表单中添加隐藏字段。
以下是一个简单表单的示例:
<form action="/posts/create" method="POST">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
Title: <input type="text" name="title">
Text: <input type="text" name="text">
<button type="submit">Submit</button>
</form>
可持续安全
实施和维护适当的安全措施是一些只有在需要时才会重视的虚无价值。但不幸的是,大多数团队都很难让上级相信这些措施的重要性。
相反,当今时代,复杂的攻击越来越普遍。因此,很难不证明投资于足够的安全措施所提供的保障和安心是合理的。
值得庆幸的是,Node.js 等现代平台使保持高安全标准变得更加容易和轻松。这样,您就可以专注于重要的事情:为用户带来价值。
文章来源:TypeScript CSRF Protection Guide: Examples and How to Enable