Laravel AJAX Request dengan CSRF Token
Jika Anda menggunakan Laravel dan mengkombinasikan teknik AJAX untuk mengirim request ke server, pasti Anda pernah memikirkan: bagaimana caranya memproteksi endpoint AJAX tersebut dari serangan CSRF?
AJAX Form
Sebagai contoh, kita memiliki sebuah laman untuk mengirimkan pesan ke server dengan teknik AJAX:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ajax Form</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
<input type="text" id="message">
<button type="button" id="send">Send</button>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="{{ asset('ajax-setup.js') }}"></script>
<script src="{{ asset('ajax-handler.js') }}"></script>
</body>
</html>
Setup AJAX Request
Pada kode di atas, kita tidak menyisipkan csrf_token
di dalam hidden input seperti biasanya; melainkan pada meta
tag dengan nama csrf-token
. meta
tag inilah yang akan digunakan pada file ajax-setup.js
:
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
});
});
Pada ajax-setup.js
inilah kita mengkonfigurasi metode $.ajax()
agar selalu menyertakan HTTP header tambahan bernama X-CSRF-Token
. Nilai dari header X-CSRF-Token
ini diambil dari tag <meta "csrf-token">
yang telah kita sertakan sebelumnya.
Sementara file ajax-handler.js
akan berisi kode Javascript yang Anda gunakan untuk mengirimkan request ke server:
$(function() {
// On button click, send AJAX request
$("#send").click(sendMessage);
// Send AJAX request
function sendMessage() {
$.ajax({
url : "http://example.com/ajax-post", // Request endpoint
type : "POST", // HTTP verb
data : { message: $("message").val() }, // Data to be sent
success : function(data) {
// Do something with returned response data
}
});
}
});
CSRF Filter
Dan terakhir kita harus memodifikasi filter CSRF yang secara default telah disediakan oleh Laravel:
Route::filter('csrf', function() {
if (Request::ajax()) {
// If it is an AJAX request, use X-CSRF-Token meta
$token = Request::header('X-CSRF-Token');
} else {
// Or else, use a basic hidden input which hold CSRF token
$token = Input::get('_token');
}
// If CSRF token is mismtach, throw an exception
if (Session::token() != $token) {
throw new Illuminate\Session\TokenMismatchException;
}
});
Perhatikan, jika request yang diterima server adalah AJAX, maka CSRF token akan diambil dari HTTP header dengan key yang bernama: X-CSRF-Token
:
if (Request::ajax()) {
$token = Request::header('X-CSRF-Token');
}
Epilog
Tentu ini hanyalah satu dari beragam cara untuk melindungi AJAX request dari serangan CSRF. Anda tentu bisa tetap menggunakan cara tradisional: menyisipkan CSRF token pada hidden input atau langsung menyertakannya pada parameter data dari metode $.ajax()
. Namun saya pribadi merasa cara inilah yang paling elegan.