json 在HTTP GET中使用MVC3的AntiForgeryToken避免Javascript CSRF漏洞

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4914994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 17:44:25  来源:igfitidea点击:

Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability

jsonasp.net-mvc-3csrfantiforgerytoken

提问by goodguys_activate

In regards to this Haacked blog, I'm hesitant to implement the proposed anti-JSON GET hiHymaning solutions since

关于这个 Haacked 博客,我很犹豫要不要实施提议的反 JSON GET 劫持解决方案,因为

  1. The recommended solutions to mitigating JSON hiHymaning involve non-REST-full JSON POSTs to GET data

  2. The alternate solution (object wrapping) causes problems with 3rd party controls I don't have source-code access to.

  3. I can't find a community-vetted implementation that implements the Alternative Solution (listed below) on how to compose the security token, or securely deliver it within the webpage. I also won't claim to be enough of an expert to roll my own implementation.

  4. Referrer headers can't be relied upon

  1. 减轻 JSON 劫持的推荐解决方案涉及非 REST-full JSON POST 以获取数据

  2. 替代解决方案(对象包装)会导致我无法访问源代码的第 3 方控件出现问题。

  3. 我找不到一个经过社区的实现,它实现了关于如何编写安全令牌或在网页中安全地交付它的替代解决方案(如下所列)。我也不会声称自己是足够的专家来推出我自己的实现。

  4. 不能依赖引用标头

Background

背景

This blogdescribes a CSRF issue regarding JSON HiHymaning and recommends using JSON POSTs to GET data. Since using a HTTP POST to GET data isn't very REST-full, I'd looking for a more RESTfull solution that enables REST actions per session, or per page.

这篇博客描述了一个关于 JSON 劫持的 CSRF 问题,并建议使用 JSON POST 来获取数据。由于使用 HTTP POST 来获取数据不是非常完整的 REST,我正在寻找一个更完整的解决方案,该解决方案支持每个会话或每个页面的 REST 操作。

Another mitigation technique is to wrap JSON data in an object as described here. I'm afraid this may just delay the issue, until another technique is found.

另一种缓解技术是将 JSON 数据包装在一个对象中,如此处所述。恐怕这可能只会延迟问题,直到找到另一种技术。

Alternative Implementation

替代实现

To me, it seems natural to extend the use ASP.NET MVC's AntiForgeryTokenwith jQuery HTTP GETs for my JSON.

对我来说,将ASP.NET MVC 的 AntiForgeryToken与 jQuery HTTP GETs的使用扩展到我的 JSON似乎很自然。

For example if I GET some sensitive data, according to the Haacked link above, the following code is vulnerable:

例如,如果我获取一些敏感数据,根据上面的 Haacked 链接,以下代码容易受到攻击:

$.getJSON('[url]', { [parameters] }, function(json) {
    // callback function code
});

I agree that it isn't RESTfull to GET data using the recommended POST workaround. My thought is to send a validation token in the URL. That way the CSRF-style attacker won't know the complete URL. Cached, or not cached, they won't be able to get the data.

我同意使用推荐的 POST 解决方法来获取数据不是 RESTfull。我的想法是在 URL 中发送一个验证令牌。这样,CSRF 风格的攻击者就不会知道完整的 URL。缓存或未缓存,他们将无法获取数据。

Below are two examples of how a JSON GET query could be done. I'm not sure what implementation is most effective, but may guess that the first one is safer from errant proxies caching this data, thus making it vulnerable to an attacker.

以下是如何完成 JSON GET 查询的两个示例。我不确定哪种实现是最有效的,但可能会猜测第一个实现更安全,避免错误代理缓存此数据,从而使其容易受到攻击者的攻击。

http://localhost:54607/Home/AdminBalances/ENCODEDTOKEN-TOKEN-HERE

http://localhost:54607/Home/AdminBalances/ENCODEDTOKEN-TOKEN-HERE

or

或者

http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE

http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE

... which might as well be MVC3's AntiForgeryToken, or a variant (see swt) thereof. This token would be set as an inline value on whatever URL format is chosen above.

...这也可能是 MVC3 的 AntiForgeryToken 或其变体(请参阅 swt)。此标记将被设置为上面选择的任何 URL 格式的内联值。

Sample questions that prevent me from rolling my own solution

阻止我推出自己的解决方案的示例问题

  1. What URL format (above) would you use to validate the JSON GET (slash, questionmark, etc) Will a proxy respond to http://localhost:54607/Home/AdminBalanceswith http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HEREdata?

  2. How would you deliver that encoded token to the webpage? Inline, or as a page variable?

  3. How would you compose the token? Built in AntiforgeryToken, or by some other means?

  4. The AntiForgeryToken uses a cookie. Would a backing cookie be used/needed in this case? HTTP Only? What about SSL in conjunction with HTTP Only?

  5. How would you set your cache headers? Anything special for the Google Web Accelerator (for example)

  6. What are the implications of just making the JSON request SSL?

  7. Should the returned JSON array still be wrapped in an object just for safety's sake?

  8. How will this solution interop with Microsoft's proposed templating and databindingfeatures

  1. 你会用什么URL格式(上图),以验证JSON GET(斜杠,问号等)意愿代理响应HTTP://本地主机:54607 /首页/ AdminBalancesHTTP://本地主机:54607 /首页/ AdminBalances? ENCODEDTOKEN-TOKEN-HERE数据?

  2. 您将如何将该编码令牌传送到网页?内联,还是作为页面变量?

  3. 您将如何编写令牌?内置 AntiforgeryToken 还是通过其他方式?

  4. AntiForgeryToken 使用 cookie。在这种情况下会使用/需要支持 cookie 吗?仅 HTTP?SSL 与 HTTP Only 结合如何?

  5. 您将如何设置缓存标头?Google Web Accelerator 的任何特殊内容(例如)

  6. 仅发出 JSON 请求 SSL 的含义是什么?

  7. 为了安全起见,返回的 JSON 数组是否仍应包含在对象中?

  8. 此解决方案将如何与 Microsoft 提议的模板和数据绑定功能互操作

The questions above are the reasons I'm not forging ahead and doing this myself. Not to mention there likely more questions I haven't thought of, and yet are a risk.

上面的问题是我没有前进并自己做这件事的原因。更不用说可能还有更多我没有想到的问题,但仍然存在风险。

采纳答案by m0sa

The Asp.net MVC AntiForgeryToken won't work through HTTP GET, because it relies on cookies which rely on HTTP POST (it uses the "Double Submit Cookies" technique described in the OWASP XSRF Prevention Cheat Sheet). You can also additionally protect the cookies sent to the client by setting the as httponly, so they cannot be spoofed via a script.

Asp.net MVC AntiForgeryToken 不能通过 HTTP GET 工作,因为它依赖于依赖于 HTTP POST 的 cookie(它使用OWASP XSRF预防备忘单中描述的“双重提交 Cookies”技术)。您还可以通过将 cookie 设置为httponly来额外保护发送到客户端的cookie,因此它们不能被脚本欺骗。

In this documentyou can find various techniques that can be used to prevent XSRF. It seems the you described would fall into the Approach 1. But we have a problem on how to retrieve the session on the server when using Ajax HTTP GET request since the cookies are not sent with the request. So you would also have to add a session identifier to you action's URL (aka. cookieless sessions, which are easier to hiHyman). So in order to perform an attack the attacker would only need to know the correct URL to perform the GET request.

本文档中,您可以找到可用于防止 XSRF 的各种技术。您描述的似乎属于方法 1。但是我们在使用 Ajax HTTP GET 请求时如何检索服务器上的会话存在问题,因为 cookie 不随请求一起发送。因此,您还必须将会话标识符添加到您的操作 URL(也就是无 cookie 会话,更容易劫持)。因此,为了执行攻击,攻击者只需要知道执行 GET 请求的正确 URL。

Perhaps a good solution would be to store the session data using some key from the users SSL certificate (for example the certs thumb-print). This way only the owner of the SSL certificate could access his session. This way you don't need to use cookies and you don't need to send session identifiers via query string parameters.

也许一个好的解决方案是使用来自用户 SSL 证书的一些密钥(例如证书指纹)来存储会话数据。这样,只有 SSL 证书的所有者才能访问他的会话。这样您就不需要使用 cookie,也不需要通过查询字符串参数发送会话标识符。

Anyway, you will need to roll out your own XSRF protection if you don't want to use HTTP POST in Asp.net MVC.

无论如何,如果您不想在 Asp.net MVC 中使用 HTTP POST,您将需要推出自己的 XSRF 保护。

回答by Marko

I came to this problem and the solution was not so trivial however there is a fantastic blog to get you started this can be used with get and post ajax.

我遇到了这个问题,解决方案并不是那么简单,但是有一个很棒的博客可以帮助您入门,它可以与 get 和 post ajax 一起使用。

http://johan.driessen.se/posts/Updated-Anti-XSRF-Validation-for-ASP.NET-MVC-4-RC

http://johan.driessen.se/posts/Updated-Anti-XSRF-Validation-for-ASP.NET-MVC-4-RC

If you place the following in the global name space all your post/gets can take advantage having an anti forgery token and you don't have to modify your ajax calls. Create an input element in a common page.

如果您将以下内容放在全局命名空间中,您的所有帖子/获取都可以利用具有防伪标记的优势,并且您不必修改您的 ajax 调用。在公共页面中创建输入元素。

<form id="__AjaxAntiForgeryForm" action="#" method="post">@Html.AntiForgeryToken()</form>

The following javascript will read the anti forgery tokken and add it to the request header.

以下 javascript 将读取防伪令牌并将其添加到请求标头中。

// Wire up the global jQuery ajaxSend event handler.
$(document).ajaxSend(namespace.ajax.globalSendHandler);

// <summary>
// Global handler for all ajax send events.
// </summary>
namespace.ajax.globalSendHandler = function (event, xhr, ajaxOptions) {
    // Add the anti forgery token
    xhr.setRequestHeader('__RequestVerificationToken', $("#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]").val());
};