如果我在一个页面中添加多个表单,是不是需要在每个表单中添加单独的防伪令牌?
Posted
技术标签:
【中文标题】如果我在一个页面中添加多个表单,是不是需要在每个表单中添加单独的防伪令牌?【英文标题】:If I add multiple forms in a single page, do I need to add separate Anti-Forgery Tokens in each form?如果我在一个页面中添加多个表单,是否需要在每个表单中添加单独的防伪令牌? 【发布时间】:2011-08-18 18:45:21 【问题描述】:如果答案是肯定的,那么 ASP.NET MVC 将如何找出哪个令牌链接到哪个表单以及如何验证它?
我已经看到它为每个表单创建了两个单独的标记。
【问题讨论】:
【参考方案1】:在这种情况下,您无需执行任何特定操作。 ASP.NET MVC 将简单地为所有表单重用相同的值,因此它不需要知道哪个表单发送了请求来验证它。只需在每个表单中添加一个 html.AntiForgeryToken()
并使用 [ValidateAntiForgeryToken]
属性装饰您发布到的每个控制器操作,您应该就可以了。
【讨论】:
是的,当我有表单时,我正在使用 AjaxForm 插件(它将表单转换为 ajax 请求)但有时我没有表单;触发发布请求的普通链接。为此,我想我会在母版页中添加一个 antiforgerytoken 并将其用于所有 ajax。谢谢 发布的答案不正确“ASP.NET MVC 将简单地为所有表单重用相同的值,因此它不需要知道哪个表单发送了请求来验证它。”我在一个页面上有多个表单,并且为每个表单调用了 Html.AntiForgeryToken() 并且每个表单都创建了一个唯一的值——我遇到了“提供的防伪令牌是针对不同的基于声明的用户而不是当前用户。" 我确认 DJA 报告的内容,我处于相同的情况:我有三种形式,它们都有不同的 requestverificationtoken 并且也与 cookie 中的值不同,我的 ajax 发布请求被拒绝带有 401 未经授权的响应代码...请提供更深入的解释? 我和@DJA 和@SouhaiebBesbes 有同样的问题。同一页面上的两个表单,每个表单都有一个Html.AntiForgeryToken()
,生成两个不同的令牌,然后一个(或两个?)不匹配单个 cookie。有人找到解决方案了吗?
我又来了。这里有一个解决方案,尽管存在一些安全问题:***.com/a/22479124/593779【参考方案2】:
有一篇很棒的文章here 我指出了一些重要的部分。
简而言之, 如果可以从请求的 cookie 集合中反序列化令牌,它将重用该令牌而不是生成新令牌。如果 cookie 集合中不存在令牌,它将实例化一个新的“AntiForgeryToken”实例并随机生成一个新的 16 字节数组来表示该令牌。
public AntiForgeryToken GetCookieToken(HttpContextBase httpContext)
HttpCookie cookie = httpContext.Request.Cookies[this._config.CookieName];
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
return (AntiForgeryToken) null;
return this._serializer.Deserialize(cookie.Value);
在生成第一个令牌并将其保存到 cookie 集合后,所有后续对辅助方法“Html.AntiForgeryToken()”的调用都将遵循相同的步骤并重用 cookie 集合中的现有令牌 而不是生成新值。
由于它是一个会话 cookie,这意味着防伪令牌的值在浏览器会话期间仅生成一次,并在所有后续调用中重复使用。
那么,如果隐藏字段值重复使用相同的标记,为什么它们会彼此不同呢?
因此,虽然加密的值可能看起来不同,但解密的值是相同的。
byte[] one = MachineKey45CryptoSystem.Instance.Unprotect("iAdQj5D0qrMuTggD8WpnOZPlVOfHg_qmPIEjnULAYd1h56cV2cL51rcaY8_UgxQbav5_6KTAtyE52ir1X6GmaS9ZPgw1");
byte[] two = MachineKey45CryptoSystem.Instance.Unprotect("Shvi8Bxe6-a8zfCfDGnxkaC-IETsbjkR9iIylwn-2VRWQ-GtQkdowdFw1biU7dN3j-xPJZHYQPe-hNfWspYjy_ZcCCY1");
byte[] three = MachineKey45CryptoSystem.Instance.Unprotect("ZhaVFngUMLo88jmTIx___BTWlYFyKh1GalwEeffRl0-o3Gu7_m98k6aQjO7IysZIdXxVx6TqL6QIfX19Uwq3Ia6dghA1");
比较所有三个字节数组会发现它们是相同的。
【讨论】:
这应该是公认的答案。它不仅在技术上是准确的,而且还有链接和示例说明为什么它是准确的。以上是关于如果我在一个页面中添加多个表单,是不是需要在每个表单中添加单独的防伪令牌?的主要内容,如果未能解决你的问题,请参考以下文章
如何知道是不是选中了表单中的多个复选框并将值插入数据库表c#