防伪标记(AntiForgeryToken)是如何工作的?

26

我正在尝试防止跨站请求伪造(CSRF),有两种情况:

  1. 从另一个网站进行POST请求,启用了AntiForgeryToken后失败。
  2. 我尝试从我的“恶意”JavaScript(在另一个网站上运行)首先获取页面的 GET 请求, 解析并提取 RequestVerificationToken,然后执行 POST 请求。这也失败了,但我不清楚原因是什么?

请问有人能够解释为什么吗?


这个网站有一些有用的信息和细节:使用ASP.NET MVC的AntiForgeryToken()助手防止跨站请求伪造(CSRF) - tmorell
这里有解释:https://levelup.gitconnected.com/simulating-a-csrf-attack-part-1-5ec8b0f8b152 - David Klempfner
2个回答

79

这是一份关于CSRF的好教程:

http://youtu.be/vrjgD0azkCw

简单来说,您登录银行网站并在机器上存放了银行的cookie,以便进行身份验证。每次您请求(即从)yourbank.com加载页面时,浏览器会将cookie发送到Web服务器,服务器上的代码会检查cookie以确保您已经进行身份验证。很棒。

然而,当cookie尚未过期时,您检查电子邮件并打开一个尼日利亚王子寄给您的链接。您点击它(谁能抵制),但链接却将您带到以下URL:

http://yourbank.com/transfer.aspx?amt=1000000&from=myAccount&to=princeAccount

因为您在银行已经进行了身份验证(通过cookie),所以银行认为您实际上正在要求转账,所以就会执行。

这显然是一个有点牵强的例子,但它清楚地传达了要点。更现实的情况是,该链接可能会提交一个请求,在论坛网站上更改您的电子邮件地址,以便他们可以获取到您的访问权限。

现在,回答您具体的问题:

一种解决这个问题的方法(Ruby和.NET等使用的方法)是包含一个防伪标记。基本上,当你请求一个页面时,服务器会包含一个带有加密值的隐藏字段。当你提交表单时,网站会查看cookie以确保你已经认证,但它还会查看浏览器发送的加密值并确保它是有效的。加密令牌实际上将是与您的账户相关联的会话ID。因此,服务器会看到cookie,将您识别为用户123,然后检查加密表单字段令牌,解密该值并确保未加密的值与您的会话或用户ID相匹配。如果匹配,则知道可以继续进行。

发送链接的尼日利亚王子不会知道您的会话ID,即使他知道,他也无法使用与网站相同的密钥和算法进行加密。

这就是方法。一次又一次地阻止尼日利亚王子通过防伪标记行骗。

(这里没有对尼日利亚或尼日利亚人有任何偏见。我相信他们是可爱的人。只是他们的王子有时会表现得有些糟糕。)


这样也可以防止网络爬虫吗?我的意思是,如果你有一个表单,并且有人模拟输入的提交,以获取结果...使用我的应用程序作为他们的服务。AntiForgeryToken是否能像尼日利亚骗子那样防止这种情况发生? - Romias
我认为它并不能防止网络爬虫。令牌并不能阻止页面被查看。它只是防止未经意请求的人或者说没有请求过该页面的人查看该页面。 - Trevor
你的链接示例使用了GET请求。但是,提交一个表单后,通常会使用POST请求来引用它。 - symbiont

7

出于安全考虑,您不能使用AJAX从另一个域检索内容。

因此,其他网站无法获取您的令牌。


所以,基本上,POST可以跨域工作(因此您需要AntyForgeryToken来防止“盲目”POST),但GET本质上不行。对吗? - emirc
@emirc:错了。你可以发送任何类型的跨域请求,但是你无法读取回复。 - SLaks
哦,谢谢。我明白了。因此建议不要在GET中更改任何数据,例如GET应该是只读的...非常感谢!!! - emirc
3
在跨域安全方面,POST和GET之间并没有区别。反伪造令牌的目的是在发送请求之前需要读取响应。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接