Pertanyaan jQuery Ajax memanggil dan Html.AntiForgeryToken ()


Saya telah menerapkan di aplikasi saya mitigasi Serangan CSRF mengikuti informasi yang saya baca di beberapa posting blog di internet. Khususnya posting ini telah menjadi penggerak implementasi saya

Pada dasarnya artikel dan rekomendasi tersebut mengatakan bahwa untuk mencegah serangan CSRF, siapa pun harus menerapkan kode berikut:

1) Tambahkan [ValidateAntiForgeryToken] pada setiap tindakan yang menerima kata kerja POST Http

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}

2) Tambahkan <%= Html.AntiForgeryToken() %> pembantu di dalam formulir yang mengirimkan data ke server

<div style="text-align:right; padding: 8px;">
    <%= Html.AntiForgeryToken() %>
    <input type="submit" id="btnSave" value="Save" />
</div>

Pokoknya di beberapa bagian aplikasi saya, saya melakukan Ajax POSTs dengan jQuery ke server tanpa memiliki bentuk apa pun. Ini terjadi misalnya ketika saya membiarkan pengguna mengklik gambar untuk melakukan tindakan tertentu.

Misalkan saya memiliki meja dengan daftar kegiatan. Saya memiliki gambar pada kolom tabel yang mengatakan "Tandai kegiatan sebagai selesai" dan ketika pengguna mengklik pada kegiatan itu saya melakukan POST Ajax seperti pada contoh berikut:

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

Bagaimana saya bisa menggunakan <%= Html.AntiForgeryToken() %> dalam kasus-kasus ini? Apakah saya harus menyertakan panggilan pembantu di dalam parameter data panggilan Ajax?

Maaf untuk posting panjang dan terima kasih banyak untuk membantu

EDIT:

Sesuai jayrdub jawaban yang saya gunakan dengan cara berikut

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});

180
2017-11-02 00:39


asal


Jawaban:


Saya menggunakan fungsi js sederhana seperti ini

AddAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

Karena setiap formulir di halaman akan memiliki nilai yang sama untuk token, cukup letakkan sesuatu seperti ini di laman master paling atas Anda

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  

Kemudian dalam panggilan ajax Anda lakukan (diedit untuk mencocokkan contoh kedua Anda)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});

222
2017-11-02 01:14



Saya suka solusi yang disediakan oleh 360Airwalk, tetapi mungkin sedikit lebih baik.

Masalah pertama adalah jika Anda membuatnya $.post() dengan data kosong, jQuery tidak menambahkan Content-Type header, dan dalam hal ini ASP.NET MVC gagal menerima dan memeriksa token. Jadi Anda harus memastikan header selalu ada.

Peningkatan lain adalah dukungan dari semua kata kerja HTTP dengan konten: POST, PUT, DELETE, dll. Meskipun Anda hanya dapat menggunakan POST dalam aplikasi Anda, lebih baik memiliki solusi umum dan memverifikasi bahwa semua data yang Anda terima dengan kata kerja memiliki token anti-pemalsuan.

$(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);
            }
        }
    });
});

23
2017-08-24 20:41



Jangan gunakan Html.AntiForgeryToken. Sebaliknya, gunakan AntiForgery.GetTokens dan AntiForgery.Validate dari API Web seperti yang dijelaskan dalam Mencegah Serangan Pemutus Permintaan Lintas Situs (CSRF).


18
2018-03-06 18:33



Saya tahu ada banyak jawaban lain, tetapi artikel ini bagus dan ringkas dan memaksa Anda untuk memeriksa semua HttpPosts Anda, bukan hanya beberapa dari mereka:

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

Ini menggunakan header HTTP daripada mencoba memodifikasi koleksi form.

Server

//make sure to add this to your global action filters
[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);
            }
        }
    }
}

Klien

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});

15
2018-01-17 21:15



Saya baru saja menerapkan masalah yang sebenarnya ini dalam proyek saya saat ini. saya melakukannya untuk semua ajax-POST yang membutuhkan pengguna terotentikasi.

Pertama saya memutuskan untuk menghubungkan panggilan ajax jquery saya jadi saya tidak mengulangi diri terlalu sering. javascript snippet ini memastikan semua ajax (posting) panggilan akan menambahkan token validasi permintaan saya ke permintaan. Catatan: nama __RequestVerificationToken digunakan oleh framework .Net sehingga saya dapat menggunakan fitur Anti-CSRF standar seperti yang ditunjukkan di bawah ini.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

Dalam Views Anda di mana Anda perlu token akan tersedia untuk javascript di atas hanya menggunakan HTML-Helper umum. Anda pada dasarnya dapat menambahkan kode ini di mana pun Anda mau. Saya menempatkannya dalam pernyataan if (Request.IsAuthenticated):

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

Dalam pengontrol Anda cukup gunakan mekanisme ASP.Net MVC Anti-CSRF standar. Saya melakukannya seperti ini (meskipun saya benar-benar menggunakan Garam).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

Dengan Firebug atau alat serupa Anda dapat dengan mudah melihat bagaimana permintaan POST Anda sekarang memiliki parameter __RequestVerificationToken ditambahkan.


14
2018-04-04 15:44



Saya merasa seperti ahli nujum canggih di sini, tapi ini masih menjadi masalah 4 tahun kemudian di MVC5.

Untuk menangani permintaan ajax dengan benar token anti-pemalsuan harus diteruskan ke server pada panggilan ajax. Mengintegrasikannya ke dalam data dan model posting Anda berantakan dan tidak perlu. Menambahkan token sebagai header khusus bersih dan dapat digunakan kembali - dan Anda dapat mengonfigurasinya sehingga Anda tidak perlu mengingat untuk melakukannya setiap saat.

Ada pengecualian - ajax tidak mengganggu tidak perlu perawatan khusus untuk panggilan ajax. Token dilewatkan seperti biasa di bidang masukan tersembunyi biasa. Persis sama dengan POST reguler.

_Layout.cshtml

Di _layout.cshtml Saya memiliki blok JavaScript ini. Ini tidak menulis token ke DOM, melainkan menggunakan jQuery untuk mengekstraknya dari input literal tersembunyi yang dihasilkan oleh Pembantu MVC. String Ajaib yang merupakan nama header didefinisikan sebagai konstanta di kelas atribut.

<script type="text/javascript">
    $(document).ready(function () {
        var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
        //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative

        $.ajaxSetup({
            beforeSend: function (xhr) {
                if (!isAbsoluteURI.test(this.url)) {
                    //only add header to relative URLs
                    xhr.setRequestHeader(
                       '@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME', 
                       $('@Html.AntiForgeryToken()').val()
                    );
                }
            }
        });
    });
</script>

Perhatikan penggunaan tanda kutip tunggal dalam fungsi beforeSend - elemen input yang dirender menggunakan tanda kutip ganda yang akan memecah literal JavaScript.

JavaScript Klien

Ketika ini menjalankan fungsi beforeSend di atas dipanggil dan AntiForgeryToken secara otomatis ditambahkan ke header permintaan.

$.ajax({
  type: "POST",
  url: "CSRFProtectedMethod",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  success: function (data) {
    //victory
  }
});

Perpustakaan Server

Atribut khusus diperlukan untuk memproses token non-standar. Ini dibangun di atas solusi @ viggity, tetapi menangani ajax yang tidak mengganggu dengan benar. Kode ini dapat disimpan di perpustakaan umum Anda

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {

            var headerTokenValue = request.Headers[HTTP_HEADER_NAME];

            // Ajax POSTs using jquery have a header set that defines the token.
            // However using unobtrusive ajax the token is still submitted normally in the form.
            // if the header is present then use it, else fall back to processing the form like normal
            if (headerTokenValue != null)
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, headerTokenValue);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Server / Kontroler

Sekarang Anda cukup menerapkan atribut ke Action Anda. Bahkan lebih baik Anda dapat menerapkan atribut ke pengontrol Anda dan semua permintaan akan divalidasi.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}

13
2017-12-16 02:57



Saya pikir yang harus Anda lakukan adalah memastikan bahwa masukan "__RequestVerificationToken" disertakan dalam permintaan POST. Setengah informasi lainnya (yaitu token di cookie pengguna) sudah dikirim secara otomatis dengan permintaan AJAX POST.

Misalnya.,

$("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) {
            // ....
        }
    });
});

11
2017-11-02 01:03