2

ValidateAntiForgeryToken は、PUT および削除要求に対して機能しますか、それとも ASP.NET Web API の投稿要求に対してのみ機能しますか? そうでない場合、それを安全にする最善の方法は何ですか?

4

2 に答える 2

5

アンチ CSRF は通常、Cookie と本文の両方のトークンを照合して、ブラウザー フォーム ポストなどの非 ajax 呼び出しで要求を検証することによって行われます。

ajax 呼び出しでは、カスタム ヘッダーにトークンを配置することをお勧めします。最新のASP.NET 2012.2 アップデートをインストールした場合。MVC プロジェクト ダイアログにスパ テンプレートがあり、SPA アプリで CSRF を防止する方法を示します。これは、サーバー側からヘッダー トークンを検証するためにテンプレートからコピーされたコードです。

public class ValidateHttpAntiForgeryTokenAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        HttpRequestMessage request = actionContext.ControllerContext.Request;

        try
        {
            if (IsAjaxRequest(request))
            {
                ValidateRequestHeader(request);
            }
            else
            {
                AntiForgery.Validate();
            }
        }
        catch (HttpAntiForgeryException e)
        {
            actionContext.Response = request.CreateErrorResponse(HttpStatusCode.Forbidden, e);
        }
    }

    private bool IsAjaxRequest(HttpRequestMessage request)
    {
        IEnumerable<string> xRequestedWithHeaders;
        if (request.Headers.TryGetValues("X-Requested-With", out xRequestedWithHeaders))
        {
            string headerValue = xRequestedWithHeaders.FirstOrDefault();
            if (!String.IsNullOrEmpty(headerValue))
            {
                return String.Equals(headerValue, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
            }
        }

        return false;
    }

    private void ValidateRequestHeader(HttpRequestMessage request)
    {
        string cookieToken = String.Empty;
        string formToken = String.Empty;

        IEnumerable<string> tokenHeaders;
        if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
        {
            string tokenValue = tokenHeaders.FirstOrDefault();
            if (!String.IsNullOrEmpty(tokenValue))
            {
                string[] tokens = tokenValue.Split(':');
                if (tokens.Length == 2)
                {
                    cookieToken = tokens[0].Trim();
                    formToken = tokens[1].Trim();
                }
            }
        }

        AntiForgery.Validate(cookieToken, formToken);
    }
}

クライアント側からは、ajax 呼び出しでヘッダーも設定する必要があります。これは todo.datacontext.js のコードです:

function ajaxRequest(type, url, data, dataType) { // Ajax helper
    var options = {
        dataType: dataType || "json",
        contentType: "application/json",
        cache: false,
        type: type,
        data: data ? data.toJson() : null
    };
    var antiForgeryToken = $("#antiForgeryToken").val();
    if (antiForgeryToken) {
        options.headers = {
            'RequestVerificationToken': antiForgeryToken
        }
    }
    return $.ajax(url, options);
}
于 2013-04-19T18:34:04.717 に答える
0

偽造防止トークンの検証を処理するアクション フィルター クラスを作成しました。

public class WebApiValidateJsonToken : System.Web.Http.Filters.ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext filterContext)
    {
        //get the base url or virtual directory of web app
        var virtualDirectory = filterContext.Request.Headers.GetValues("vd").First();

        //base 64 encode the virtual directory
        var encodedVirtualDirectory = Convert.ToBase64String(Encoding.UTF8.GetBytes(virtualDirectory));

        //set cookie name to look for to append '_' + base 64 encoded virtual directory to match how Asp.Net Html.AntiforgeryToken 
        //names the cookie that holds the token
        var cookieName = "__RequestVerificationToken" + (String.IsNullOrEmpty(encodedVirtualDirectory) ? "" : "_" + ReplacePadding(encodedVirtualDirectory));

        //get the formtoken created by the Html.AntiforgeryToken helper (hidden input element in view) value sent in ajax header
        var formtoken = filterContext.Request.Headers.GetValues("antiForgeryToken").First();

        //get the cookie token value with the name generated from above
        var cookietoken = filterContext.Request.Headers.GetCookies(cookieName).FirstOrDefault()[cookieName].Value;


        try
        {
            //Validate antiforgery token the old way because can't use ValidateAntiforgeryToken attribute with JSON content
            System.Web.Helpers.AntiForgery.Validate(cookietoken, formtoken);
            base.OnActionExecuting(filterContext);
        }
        catch
        {
            throw new ArgumentException("CSRF");
        }


    }

    //Supporting Method to strip base 64 '=' padding and replace with the number representation of padding
    public string ReplacePadding(string b64)
    {
        var count = b64.Count(x => x == '=');
        b64 = b64.Substring(0, b64.Length - count);
        return b64 + count.ToString();
    }
}

ビューでそれを実装する方法は次のとおりです。

baseUrl = '@Url.Content("~/")';

        $.ajaxSetup({
            headers: {
                antiForgeryToken: $('input[name="__RequestVerificationToken"]').val(),
                vd: baseUrl.substring(0, baseUrl.length - 1)
            }
        });



                $.ajax({
                    url: '@Url.Content("~/api/WebApiAction")',
                    data: JSON.stringify(paramObject),
                    contentType: "application/json",
                    type: 'PUT'
                })
                .done(function (data) {/*do stuff*/});
于 2015-04-13T20:48:02.957 に答える