panggilan jQuery Ajax dan Html.AntiForgeryToken ()

207

Saya telah menerapkan mitigasi serangan CSRF di aplikasi saya mengikuti informasi yang saya baca di beberapa posting blog di internet. Khususnya posting ini telah menjadi pendorong 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() %>helper form dalam yang mengirimkan data ke server

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

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

Misalkan saya punya meja dengan daftar kegiatan. Saya memiliki gambar di kolom tabel yang mengatakan "Tandai aktivitas selesai" dan ketika pengguna mengklik aktivitas tersebut saya melakukan POST Ajax seperti dalam 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() %>ini dalam kasus ini? Haruskah saya menyertakan panggilan pembantu di dalam parameter data panggilan Ajax?

Maaf untuk posting lama dan terima kasih banyak telah membantu

EDIT :

Sesuai jawaban jayrdub saya telah menggunakan 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) {
            // ....
        }
    });
});
Lorenzo
sumber
The Link David Hayden sekarang 404, tampak bahwa dia bermigrasi blog untuk CMS baru, tetapi tidak bermigrasi semua konten berusia di atas.

Jawaban:

252

Saya menggunakan fungsi js sederhana seperti ini

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

Karena setiap formulir pada halaman akan memiliki nilai token yang sama, cukup masukkan sesuatu seperti ini di halaman master teratas 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) {
        // ....
    }
});
JeremyWeir
sumber
6
Bagus, saya suka enkapsulasi dari token fetching.
jball
2
@ Lorenzo, masukkan data khusus Anda ke dalam panggilan AddAntiForgeryToken, seperti:data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball
3
Seberapa buruk ide yang akan digunakan ajaxSendatau diganti ajaxuntuk selalu menambah datatoken anti-pemalsuan? Mungkin menambahkan beberapa cek untuk memastikan bahwa urldiperuntukkan bagi server Anda.
ta.speot.is
1
Hati-hati jika Anda menggunakan cache keluaran.
Barbaros Alp
1
@SouhaiebBesbes token validasi harus sama untuk pengguna di semua halaman (ini bekerja bersama dengan cookie yang disetel dan tetap sama). Jadi tidak masalah jika ada beberapa permintaan per halaman, itu akan sama jika halaman dasar dimuat kembali.
JeremyWeir
29

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

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

Peningkatan lainnya adalah dukungan 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 apa pun memiliki anti-pemalsuan. token.

$(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);
            }
        }
    });
});
Bronx
sumber
1
+1 Anda benar, saya belum memikirkan masalah panggilan pos kosong. terima kasih atas masukannya. Anda benar bahwa kami belum menggunakan delete / put di proyek kami.
360Airwalk
2
+1 untuk menyelamatkan saya dari keharusan menambahkan fungsi ke semua panggilan jQuery.Ajax
Dragos Durlut
2
+1 Sama seperti catatan untuk anak cucu, dokumentasi jQuery untuk .ajaxSend()menyatakan "Pada jQuery 1.8, metode .ajaxSend () hanya boleh dilampirkan ke dokumen." api.jquery.com/ajaxsend
RJ Cuthbertson
1
@ Kronon Dari mana datangnya options, yang tercantum dalam ifpernyataan akhir ? Terima kasih.
hvaughan3
Hati-hati menggunakan ini jika Anda memiliki beberapa formulir pada halaman. Anda perlu mengatur nilai sebelum mengirim dengan panggilan pemilih yang lebih spesifik, bukan untuk dokumen.
Dan
22

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

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

Ia menggunakan tajuk HTTP alih-alih mencoba mengubah kumpulan formulir.

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 () {
        ...
    }
});
kejelasan
sumber
4
Atribut dari artikel yang Anda tautkan terlalu digabungkan dengan respons Bronx adalah solusi KERING utama untuk masalah ini.
TugboatCaptain
2
Great ditemukan. Saya mengedit jawaban Anda untuk memasukkan cuplikan kode sehingga jawabannya berdiri sendiri, tetapi saya berharap orang-orang akan membaca sisa artikel juga. Ini tampaknya menjadi solusi yang sangat bersih.
Tim Medora
terima kasih Tim, ini adalah ide yang bagus, membuat frustasi ketika sebuah link mati dan jawabannya menjadi tidak berharga. Saya sudah mulai melakukan ini pada semua jawaban baru saya.
viggity
Apakah ini MVC, WebAPI atau .NetCore? Saya tidak bisa mendapatkan ruang nama yang benar untuk WebAPI 5
Myster
20

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 perlu diteruskan ke server pada panggilan ajax. Mengintegrasikannya ke dalam data dan model pos Anda berantakan dan tidak perlu. Menambahkan token sebagai header khusus bersih dan dapat digunakan kembali - dan Anda dapat mengonfigurasinya sehingga Anda tidak harus ingat untuk melakukannya setiap waktu.

Ada pengecualian - ajax tidak mengganggu tidak memerlukan perlakuan khusus untuk panggilan ajax. Token dilewatkan seperti biasa di bidang input tersembunyi biasa. Persis sama dengan POST biasa.

_Layout.cshtml

Di _layout.cshtml saya memiliki blok JavaScript ini. Itu tidak menulis token ke DOM, melainkan menggunakan jQuery untuk mengekstraknya dari literal input tersembunyi yang dihasilkan MVC Helper. 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 dijalankan, 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 mencolok 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 / Pengendali

Sekarang Anda tinggal menerapkan atribut ke Action Anda. Lebih baik lagi Anda dapat menerapkan atribut ke controller Anda dan semua permintaan akan divalidasi.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}
Will D
sumber
Solusi sempurna, jauh lebih tersentralisasi. Terima kasih
David Freire
Bisakah Anda menjelaskan lebih detail mengapa Anda hanya ingin menambahkan header untuk URL relatif? Itu terlintas di kepalaku. Solusi bagus!
MattM
relatif memastikan bahwa header hanya diatur pada permintaan kembali ke server Anda sendiri, karena pengaturan ajax mencakup semua permintaan yang dibuat dengan jquery, kami tidak ingin token dikirim pada jsonp atau CORS requets. Ini mungkin berlaku untuk url absolut juga, tetapi relatif dijamin untuk domain yang sama.
Will D
1
@ Akan Saya menyukai solusi Anda, tetapi terpaksa memodifikasinya sedikit. Karena Anda memilih $.ajaxSetupuntuk mendefinisikan beforesendeventhandler umum , dapat terjadi bahwa Anda menimpanya. Saya menemukan solusi lain di mana Anda dapat menambahkan penangan kedua yang juga akan dipanggil. Bekerja dengan baik dan tidak merusak implementasi Anda.
Viper
Adakah yang memiliki versi ASP.net 5 dari pelanggan yang memvalidasi atribut AntiForgery? Versi ini tidak dikompilasi dalam versi terbaru!
Rob McCabe
19

Jangan gunakan Html.AntiForgeryToken . Alih-alih, gunakan AntiForgery.GetTokens dan AntiForgery.Validate dari Web API seperti yang dijelaskan dalam Mencegah Serangan Pemalsuan Permintaan Situs Lintas (CSRF) dalam Aplikasi ASP.NET MVC .

Edward Brey
sumber
Untuk metode tindakan pengontrol yang memodelkan jenis model server ke AJAX JSON yang diposkan, diperlukan jenis konten sebagai "aplikasi / json" untuk pengikat model yang tepat untuk digunakan. Sayangnya, ini menghalangi penggunaan data formulir, yang diperlukan oleh atribut [ValidateAntiForgeryToken], jadi metode Anda adalah satu-satunya cara yang saya temukan untuk membuatnya berfungsi. Satu-satunya pertanyaan saya adalah, apakah masih berfungsi di pertanian web atau beberapa contoh peran web Azure? Apakah Anda @Edward, atau orang lain tahu apakah ini masalah?
Richard B
@Edward Brey Bisakah Anda jelaskan mengapa kami tidak menggunakannya?
Odys
4
@Odys: Secara inheren tidak ada yang salah dengan Html.AntiForgeryToken, tetapi memiliki kelemahan: membutuhkan formulir, memerlukan jQuery, dan mengasumsikan detail implementasi Html.AntiForgeryToken yang tidak didokumentasikan. Tetap saja, tidak masalah dalam banyak konteks. Pernyataan saya "Jangan gunakan Html.AntiForgeryToken" mungkin terlalu kuat. Maksud saya adalah bahwa itu tidak dimaksudkan untuk digunakan dengan Web API, sedangkan AntiForgery.GetTokens lebih fleksibel.
Edward Brey
Terima kasih! Saya harus mengubahnya sedikit untuk membuatnya berfungsi untuk pengontrol MVC5, tapi ini solusinya
jao
3
Itu tentu tidak membutuhkan formulir. Anda hanya perlu menguraikan DOM untuknya dengan namanya. Menggunakan jquery, saya dapat menambahkannya di dalam objek data saya melalui data {__RequestVerificationToken: $ ("input [name = __ RequestVerificationToken]"). Val ()}
Anthony Mason
16

Saya baru saja mengimplementasikan masalah aktual ini dalam proyek saya saat ini. saya melakukannya untuk semua ajax-POST yang membutuhkan pengguna yang diautentikasi.

Pertama saya memutuskan untuk menghubungkan panggilan ajax jquery saya jadi saya tidak mengulangi diri saya terlalu sering. cuplikan javascript ini memastikan semua panggilan ajax (posting) akan menambahkan token validasi permintaan saya ke permintaan. Catatan: nama __RequestVerificationToken digunakan oleh .Net framework sehingga saya dapat memanfaatkan 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 Tampilan Anda di mana Anda memerlukan token yang tersedia untuk javascript di atas hanya menggunakan HTML-Helper umum. Anda pada dasarnya dapat menambahkan kode ini di mana pun Anda inginkan. 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 controller Anda cukup gunakan mekanisme standar ASP.Net MVC Anti-CSRF. 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.

360Airwalk
sumber
15

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

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) {
            // ....
        }
    });
});
jball
sumber
1
Setelah berjam-jam bereksperimen dengan posting AJAX jQuery dari dalam halaman MVC (Razor) ini adalah jawaban paling sederhana dari semua yang bekerja untuk saya. Cukup sertakan bidang data Anda sendiri (atau model view saya kira) setelah token sebagai potongan data baru (tetapi dalam objek data asli).
Ralph Bacon
Bagaimana saya menerapkan ini jika fungsi AJAX berada di halaman .html dan bukan halaman Razor?
Bob the Builder
Jika halaman html Anda tidak memiliki server yang disediakan, AntiForgeryTokenitu bisa diperdebatkan. Jika ya (tidak yakin bagaimana Anda mendapatkannya dalam kasus itu, tetapi dengan asumsi Anda), maka hal di atas akan berfungsi dengan baik. Jika Anda mencoba membuat halaman web sederhana yang akan memposting permintaan ke server yang mengharapkan token tersebut, dan server tidak menghasilkan halaman tersebut, maka Anda kurang beruntung. Itulah intinya AntiForgeryToken ...
jball
6

Anda juga dapat melakukan ini:

$("a.markAsDone").click(function (event) {
    event.preventDefault();

    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: $('<form>@Html.AntiForgeryToken()</form>').serialize(),
        success: function (response) {
        // ....
        }
    });
});

Ini menggunakan Razor, tetapi jika Anda menggunakan WebFormssintaks Anda bisa menggunakan <%= %>tag

Leonardo Garcia Crespo
sumber
4

Lebih jauh lagi ke komentar saya terhadap jawaban @ JBall yang membantu saya sepanjang jalan, ini adalah jawaban terakhir yang bekerja untuk saya. Saya menggunakan MVC dan Razor dan saya mengirimkan formulir menggunakan jQuery AJAX sehingga saya dapat memperbarui tampilan parsial dengan beberapa hasil baru dan saya tidak ingin melakukan postback lengkap (dan flicker halaman).

Tambahkan @Html.AntiForgeryToken() dalam formulir seperti biasa.

Kode tombol pengiriman AJAX saya (yaitu acara onclick) adalah:

//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {

//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();

//Validate the form first
if (!$('#searchForm').validate().form()) {
    alert("Please correct the errors");
    return false;
}

//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();

// The actual POST can now take place with a validated form
$.ajax({
    type: "POST",
    async: false,
    url: "/Home/SearchAjax",
    data: allFormData,
    dataType: "html",
    success: function (data) {
        $('#gridView').html(data);
        $('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
    }
});

Saya telah meninggalkan tindakan "sukses" karena ini menunjukkan bagaimana tampilan sebagian sedang diperbarui yang berisi MvcJqGrid dan bagaimana sedang di-refresh (kisi jqGrid yang sangat kuat dan ini adalah bungkus MVC yang brilian untuk itu).

Metode pengontrol saya terlihat seperti ini:

    //Ajax SUBMIT method
    [ValidateAntiForgeryToken]
    public ActionResult SearchAjax(EstateOutlet_D model) 
    {
        return View("_Grid", model);
    }

Saya harus mengakui untuk tidak menjadi penggemar POSTing seluruh data formulir sebagai Model tetapi jika Anda perlu melakukannya maka ini adalah salah satu cara yang bekerja. MVC hanya membuat pengikatan data terlalu mudah sehingga daripada mengirimkan 16 nilai individu (atau FormCollection yang diketik dengan lemah) ini OK, saya kira. Jika Anda lebih tahu, beri tahu saya karena saya ingin menghasilkan kode MVC C # yang kuat.

Ralph Bacon
sumber
4

menemukan ide yang sangat pintar ini dari https://gist.github.com/scottrippey/3428114 untuk setiap $ .ajax panggilan yang memodifikasi permintaan dan menambahkan token.

// 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();
        }
    }
});
masterlopau
sumber
Saya mencoba beberapa alternatif lain di atas, inilah yang memecahkannya untuk saya.
HostMyBus
Namun saya harus menambahkan if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {untuk menangkap panggilan Ajax yang belum menentukan jenis konten
HostMyBus
3

1.Tentukan Fungsi untuk mendapatkan Token dari server

@function
{

        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
}

2. Dapatkan token dan atur header sebelum mengirim ke server

var token = '@TokenHeaderValue()';    

       $http({
           method: "POST",
           url: './MainBackend/MessageDelete',
           data: dataSend,
           headers: {
               'RequestVerificationToken': token
           }
       }).success(function (data) {
           alert(data)
       });

3. Validasi Onserver pada HttpRequestBase pada metode yang Anda tangani Post / get

        string cookieToken = "";
        string formToken = "";
        string[] tokens = Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        AntiForgery.Validate(cookieToken, formToken);
Tonman Neverwalk sendirian
sumber
1

Saya sadar sudah beberapa waktu sejak pertanyaan ini diposting, tetapi saya menemukan sumber daya yang sangat berguna, yang membahas penggunaan AntiForgeryToken dan membuatnya lebih sulit untuk digunakan. Ini juga menyediakan plugin jquery untuk dengan mudah memasukkan token antiforgery dalam panggilan AJAX:

Resep Permintaan Anti-Pemalsuan Untuk ASP.NET MVC Dan AJAX

Saya tidak berkontribusi banyak, tetapi mungkin seseorang akan merasakan manfaatnya.

slawek
sumber
Pos itu panjangnya satu mil! Saya yakin ini hebat tapi tl; dr
Pengembang Inggris
1
Sayang sekali, karena itu baik membahas subjek. Ini tidak hanya memberi tahu Anda cara menggunakan fitur ini, tetapi juga menjelaskan masalah apa yang diperbaiki dan memberi Anda konteks untuk memahami cara menggunakannya dengan benar. Ketika datang ke keamanan saya pikir pemahaman mendalam adalah penting.
slawek
2
Jika itu penting, itu harus ditulis dengan cara yang mendorong orang untuk membacanya;)
BritishDeveloper
1

pertama kali gunakan @ Html.AntiForgeryToken () dalam html

 $.ajax({
        url: "@Url.Action("SomeMethod", "SomeController")",
        type: 'POST',
        data: JSON.stringify(jsonObject),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        beforeSend: function (request) {
            request.setRequestHeader("RequestVerificationToken", $("[name='__RequestVerificationToken']").val());
        },
        success: function (msg) {
            alert(msg);
        }
Amir Reza
sumber
1

Inilah cara termudah yang pernah saya lihat. Catatan: Pastikan Anda memiliki "@ Html.AntiForgeryToken ()" di Tampilan Anda

  $("a.markAsDone").click(function (event) {
        event.preventDefault();
        var sToken = document.getElementsByName("__RequestVerificationToken")[0].value;
        $.ajax({
            url: $(this).attr("rel"),
            type: "POST",
            contentType: "application/x-www-form-urlencoded",
            data: { '__RequestVerificationToken': sToken, 'id': parseInt($(this).attr("title")) }
        })
        .done(function (data) {
            //Process MVC Data here
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            //Process Failure here
        });
    });
Dominic Sputo
sumber
0

Perbaikan sedikit ke solusi 360Airwalk. Ini menanamkan Token Anti Pemalsuan dalam fungsi javascript, jadi @ Html.AntiForgeryToken () tidak lagi perlu disertakan pada setiap tampilan.

$(document).ready(function () {
    var securityToken = $('@Html.AntiForgeryToken()').attr('value');
    $('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);
            }
        }
    });
});
Barry MSIH
sumber
0
function DeletePersonel(id) {

    var data = new FormData();
    data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()");

    $.ajax({
        type: 'POST',
        url: '/Personel/Delete/' + id,
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function (result) {
        }
    });
}

public static class HtmlHelper {
    public static string GetAntiForgeryToken() {
        System.Text.RegularExpressions.Match value = 
                System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), 
                        "(?:value=\")(.*)(?:\")");
        if (value.Success) {
            return value.Groups[1].Value;
        }
        return "";
    }
}
ismail eski
sumber
0

Saya menggunakan posting ajax untuk menjalankan metode delete (kebetulan dari timeline visjs tapi itu bukan relelvant). Inilah yang saya sis:

Ini adalah Index.cshtml saya

@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()

<!-- div to attach schedule to -->
<div id='schedule'></div>

<!-- div to attach popups to -->
<div id='dialog-popup'></div>

Yang saya tambahkan di sini adalah @Html.AntiForgeryToken() untuk membuat token muncul di halaman

Kemudian di postingan ajax saya, saya menggunakan:

$.ajax(
    {
        type: 'POST',
        url: '/ScheduleWorks/Delete/' + item.id,
        data: {
            '__RequestVerificationToken': 
            $("input[name='__RequestVerificationToken']").val()
              }
     }
);

Yang menambahkan nilai token, dihapus dari halaman, ke bidang yang diposting

Sebelum ini saya mencoba meletakkan nilai di header tetapi saya mendapat kesalahan yang sama

Jangan ragu untuk mengirim peningkatan. Ini sepertinya merupakan pendekatan sederhana yang bisa saya mengerti

Nick. McDermaid
sumber
0

Oke banyak posting di sini, tidak ada satupun yang membantu saya, berhari-hari google, dan masih belum lagi saya sampai pada titik penulisan seluruh aplikasi dari awal, dan kemudian saya perhatikan nugget kecil ini di Web.confg saya

 <httpCookies requireSSL="false" domain="*.localLookup.net"/>

Sekarang saya tidak tahu mengapa saya menambahkannya, tetapi sejak itu saya perhatikan, diabaikan dalam mode debug dan tidak dalam mode produksi (IE Installed to IIS Somewhere)

Bagi saya solusinya adalah salah satu dari 2 pilihan, karena saya tidak ingat mengapa saya menambahkannya saya tidak bisa memastikan hal-hal lain tidak bergantung padanya, dan kedua nama domain harus semuanya huruf kecil dan TLD tidak seperti ive selesai di * .localLookup.net

Mungkin ini membantu, mungkin juga tidak. Saya harap itu membantu seseorang

Gelisah
sumber
0

Solusi yang saya temukan bukan untuk ASPX tetapi untuk Razor, tetapi masalah yang cukup bisa dilakukan.

Saya mengatasinya dengan menambahkan AntiForgery ke permintaan. Pembantu HTML tidak membuat id HTML dengan panggilan

@Html.AntiForgeryToken()

Untuk menambahkan token ke postrequest, saya baru saja menambahkan id AntiForgery ke bidang tersembunyi dengan jquery:

$("input[name*='__RequestVerificationToken']").attr('id', '__AjaxAntiForgeryForm');

Ini menyebabkan pengontrol menerima permintaan dengan atribut [ValidateAntiForgeryToken]

Dominik Sand
sumber
-3

AntiforgeryToken masih menyakitkan, tidak ada satu pun contoh di atas yang berhasil kata demi kata untuk saya. Terlalu banyak untuk di sana. Jadi saya menggabungkan semuanya. Butuh @ Html.AntiforgeryToken dalam bentuk nongkrong di iirc

Dipecahkan seperti itu:

function Forgizzle(eggs) {
    eggs.__RequestVerificationToken =  $($("input[name=__RequestVerificationToken]")[0]).val();
    return eggs;
}

$.ajax({
            url: url,
            type: 'post',
            data: Forgizzle({ id: id, sweets: milkway }),
});

Jika ragu, tambahkan lebih banyak tanda $

Hazza
sumber