分享

在ASP.NET Web API中防止跨站点请求伪造(CSRF)攻击

 ThinkTank_引擎 2017-09-21

定义

跨站点请求伪造(CSRF)是一种攻击方式,恶意站点向用户当前登录的易受攻击的站点发送请求。

以下是CSRF攻击的示例:

  1. 用户登录www.,使用表单验证。
  2. 服务器认证用户。服务器的响应包括一个认证cookie。
  3. 没有注销,用户访问恶意网站。此恶意网站包含以下HTML表单:

    复制代码
    1 <h1>You Are a Winner!</h1>
    2   <form action="http:///api/account" method="post">
    3     <input type="hidden" name="Transaction" value="withdraw" />
    4     <input type="hidden" name="Amount" value="1000000" />
    5   <input type="submit" value="Click Me"/>
    6 </form>
    复制代码

     

    请注意,表单的Action是Post到易受攻击的网站,而不是恶意网站。这是CSRF的“跨站点”部分。

  4. 用户点击提交按钮。浏览器包含请求的身份验证cookie。
  5. 请求在具有用户身份验证上下文的服务器上运行,并且可以执行允许经过身份验证的用户执行的任何操作。

虽然此示例需要用户单击表单按钮,但是恶意页面可以轻松运行自动提交表单的脚本。此外,使用SSL不会阻止CSRF攻击,因为恶意站点可以发送“https://”请求。

通常,针对使用Cookie进行身份验证的网站可能会发生CSRF攻击,因为浏览器会将所有相关的Cookie发送到目标网站。然而,CSRF攻击并不仅限于利用Cookie。例如,BasicDigest身份验证也很脆弱。用户使用“Basic”或“Digest”身份验证登录后。浏览器自动发送凭证直到会话结束。

防伪令牌(Anti-Forgery Tokens)

为了帮助防止CSRF攻击,ASP.NET MVC使用防伪令牌(Anti-Forgery Tokens),也称为请求验证令牌

  1. 客户端请求包含表单的HTML页面。
  2. 服务器在响应中包含两个令牌。一个令牌作为一个cookie发送。另一个放置在隐藏的表单字段中。令牌随机生成,使对手无法猜测值。
  3. 当客户端提交表单时,它必须将两个令牌发送回服务器。客户端将Cookie令牌作为cookie发送,并在表单数据中发送表单令牌。(浏览器客户端在用户提交表单时自动执行此操作。)
  4. 如果请求不包含这两个令牌,则服务器不允许该请求。

以下是具有隐藏表单令牌的HTML表单的示例:

<form action="/Home/Test" method="post">
    <input name="__RequestVerificationToken" type="hidden"   
           value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />    
    <input type="submit" value="Submit" />
</form>

防伪令牌的工作原因是恶意页面无法读取用户的令牌,因为同源策略。(同源策略可以防止两个不同站点上托管的文件访问对方的内容,所以在前面的例子中,恶意页面可以发送请求到,但不能读取响应。)

为了防止CSRF攻击,请使用任何身份验证协议的防伪令牌,浏览器在用户登录后默认发送凭据,包括基于cookie的身份验证协议,如表单身份验证以及基本和摘要身份验证等协议。

您应该为任何非安全方法(POST,PUT,DELETE)要求防伪令牌。另外,确保安全的方法(GET,HEAD)没有任何副作用。此外,如果您启用跨域支持(如CORS或JSONP),则甚至安全的方法(如GET)也可能容易受到CSRF攻击的攻击,从而允许攻击者读取潜在的敏感数据。

ASP.NET MVC中的防伪令牌

要将防伪令牌添加到Razor页面,请使用HtmlHelper.AntiForgeryToken帮助方法:

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()
}

此方法添加隐藏表单字段,并设置cookie令牌。

Anti-CSRF 和 AJAX

表单令牌可能是AJAX请求的一个问题,因为AJAX请求可能会发送JSON数据,而不是HTML表单数据。一个解决方案是将Token发送到自定义HTTP标头。以下代码使用Razor语法生成令牌,然后将令牌添加到AJAX请求。令牌通过调用AntiForgery.GetTokens在服务器端生成。

复制代码
<script>
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }

    $.ajax("api/values", {
        type: "post",
        contentType: "application/json",
        data: {  }, // JSON data goes here
        dataType: "json",
        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        }
    });
</script>
复制代码

处理请求时,从请求头中提取令牌。然后调用AntiForgery.Validate方法来验证令牌。如果令牌无效,该验证方法将引发异常。

复制代码
void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}
复制代码

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多