logo

Thông báo

Icon
Error

Chia sẻ
Tùy chọn
Xem
Xem bài viết cuối
Offline admin  
#1 Đã gửi : 19/03/2017 lúc 12:08:59(UTC)
admin

Danh hiệu: Administration

Chức danh:

Nhóm: Administrators
Gia nhập: 23-07-2013(UTC)
Bài viết: 6,117
Man
Viet Nam
Đến từ: Vietnam

Cảm ơn: 10 lần
Được cảm ơn: 2 lần trong 2 bài viết

The jQuery Piece

Now we need jQuery to grab this CSRF token and use it in our requests. Due to the fancy new jQuery prefilters, this is actually a tiny little chunk of code:

Mã:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    var verificationToken = $("meta[name='__RequestVerificationToken']").attr('content');
    if (verificationToken) {
        jqXHR.setRequestHeader("X-Request-Verification-Token", verificationToken);
    }
});

or

Mã:
// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:         if (options.contentType.indexOf('application/json') === 0) {             // Add the token to the URL, because we can't add it to the JSON data:             options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();         } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {             // Append to the data string:             options.data += (options.data ? "&" : "") + token.serialize();         }     } });

Source : https://gist.github.com/scottrippey/3428114

or

Mã:
$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || event.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});

Very clean, and we don’t have to mess with any of our requests (you could technically do this if you used ajaxSetup’s “beforeSend” option). 

Note:

jQuery Ajax script doesn't add a Content-Type

In other words, all things you have to do is ensure that the "__RequestVerificationToken" input is included in the POST request. The other half of the information (i.e. the token in the user's cookie) is already sent automatically with an AJAX POST request, e.g

Mã:
$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: { 
            "__RequestVerificationToken":
            $("input[name=__RequestVerificationToken]").val() 
        },
        success: function (response) {
            // ....
        }
    });
});

The Backend Piece

Now that we have this verification token getting passed in the header, we just need to verify this token somewhere. The first thing that I did was to copy the ValidateAntiForgeryTokenAttribute class.

Inside of the ValidateAntiForgeryTokenAttribute there is a line that looks like this:

Mã:
string formValue = context.Request.Form[fieldName];

All we need to do is to grab the value from the header instead of the field:

Mã:
string formValue = 
    context.Request.Headers[EpicAntiForgeryData.GetAntiForgeryTokenHeaderName()];

Now we can let the class do the rest of the work.

And Finally…

Now all you have to do is put your new AjaxValidateAntiForgeryToken attribute on your controller actions that you want to validate. When your Ajax event fires, jQuery will append the token to the call then when it hits your controller action, the attribute plucks the value out of the header and the cookie, then it does its magic. You just have to keep in mind that you can’t use the same classes for posting forms regularly anymore, since the header won’t get appended to a non-ajax post.

Download Sample Files

Solution for global valdiation by using Http Header instead of modifying form collection:

It is nice and concise and forces you to check all of your HttpPosts, not just some of them.

It uses HTTP headers instead of trying to modify the form collection.

Client

Mã:
var token = $('[name=__RequestVerificationToken]').val();
 
$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: { '__RequestVerificationToken': token },
    contentType: 'application/json; charset=utf-8',
    data: { title: 'This is my title', contents: 'These are my contents' },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});

The important part of the JS above is the headers: { "__RequestVerificationToken": token }. This means that you can decorate your base controller with this new ValidateAntiForgeryTokenOnAllPosts attribute, and then all forms in your application will no longer work until you put @Html.AntiForgeryToken() in your form.

Server

A generic attribute is written to decorate a controller class. It is used to validate POST actions and work with ajax posts where you put the anti forgery token in the headers for the request. The attribute class looks like this:

Mã:
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        var request = filterContext.HttpContext.Request;
 
        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
 
                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value 
                    : null;
 
                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Source : codethinked.com

Ai đang xem chủ đề này?
OceanSpiders 2.0
Di chuyển  
Bạn không thể tạo chủ đề mới trong diễn đàn này.
Bạn không thể trả lời chủ đề trong diễn đàn này.
Bạn không thể xóa bài của bạn trong diễn đàn này.
Bạn không thể sửa bài của bạn trong diễn đàn này.
Bạn không thể tạo bình chọn trong diễn đàn này.
Bạn không thể bỏ phiếu bình chọn trong diễn đàn này.

| Cung cấp bởi YAF.NET 2.2.4.14 | YAF.NET © 2003-2021, Yet Another Forum.NET
Thời gian xử lý trang này hết 1.127 giây.