最近、Laravel 5に移行しました。現在、投稿のたびにCSRFチェックが行われています。削除することを考えましたが、ベストプラクティスに従うことをお勧めします。
一方、私はajaxリクエストの送信に問題があります。私のページには複数のフォームがあり、一部の送信はフォームからではなく、単なるajax呼び出しです。私の考えは、ページに1つの隠された「トークン」入力を持ち、それをすべての提出に添付することです。その汎用シングルトークン入力に欠点はありますか?
また、トークンをどのように出力できますか?ページフッターに非表示の入力を作成するだけで問題ありませんか?
欠点はありません。レイアウトファイルにグローバルトークンフィールドを簡単に作成できます。
<input type="hidden" name="_token" id="csrf-token" value="{{ Session::token() }}" />
または、フォームビルダーを使用する場合:
{!! Form::token() !!}
JQueryでは、 this のようなものを使用して、すべてのリクエストにトークンを添付できます。
ページの下部で次のようなものを使用できます。
$('form').append('{{csrf_field()}}');
これにより、すべてのforms
に非表示の入力が追加されます。
<input type="hidden" name="_token" value="yIcHUzipr2Y2McGE3EUk5JwLOPjxrC3yEBetRtlV">
そして、すべてのAJAXリクエスト:
$.ajaxSetup({
beforeSend: function (xhr, settings) {
//////////// Only for your domain
if (settings.url.indexOf(document.domain) >= 0) {
xhr.setRequestHeader("X-CSRF-Token", "{{csrf_token()}}");
}
}
});
Laravel 5:を使用するために最近アップグレードしたjQuery Mobileアプリケーションのすべての異なるシナリオでCSRFを機能させた方法の抜粋を次に示します。
メインベースコントローラーのビューに渡される変数に暗号化されたcsrfトークンを追加しました:app\Http\Controllers\MyController.php
$this->data['encrypted_csrf_token'] = Crypt::encrypt(csrf_token());
次に、メインビューヘッダーにresources\views\partials\htmlHeader.blade.php
というメタタグを追加しました
<meta name="_token" content="{!! $encrypted_csrf_token !!}"/>
次に、いくつかのフォーラムで提案されているように、このjqueryスニペットも追加しました。
$(function () {
$.ajaxSetup({
headers: {
'X-XSRF-TOKEN': $('meta[name="_token"]').attr('content')
}
});
});
ただし、(少なくとも私のセットアップでは)キーは、カスタムVerifyCsrfTokenミドルウェアのXSRF-TOKEN
Cookieのチェックの追加でした:app\Http\Middleware\VerifyCsrfToken.php:
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $request->session()->token();
$header = $request->header('X-XSRF-TOKEN');
$cookie = $request->cookie('XSRF-TOKEN');
return StringUtils::equals($token, $request->input('_token')) ||
($header && StringUtils::equals($token, $this->encrypter->decrypt($header))) ||
($cookie && StringUtils::equals($token, $cookie));
}
それを追加する前に、ほとんどすべてのAJAX POST(フォーム送信とリストビューの遅延読み込みを含む)がTokenMismatchException
のために失敗していました。
EDIT:考え直して、セッショントークンをクッキーに設定されたものと比較することがどれだけ意味があるかわかりませんそもそもセッショントークンから来ますか?)それはすべてのセキュリティをバイパスしているだけかもしれません。
私の主な問題は、上記のjqueryスニペットで、すべてのajaxリクエストにX-XSRF-TOKENヘッダーを追加することになっていたと思います。プラグイン自体にいくつかのオプションを追加するまで、私のjQuery Mobileアプリ(具体的には、私の lazyloaderプラグイン )ではうまくいきませんでした。新しいデフォルトセレクターcsrf
(この場合はmeta[name="_token"]
)と新しいデフォルト設定csrfHeaderKey
(この場合はX-XSRF-TOKEN
)を追加しました。基本的に、プラグインの初期化中に、csrf
セレクター(デフォルトまたはユーザー定義)によって配置可能な場合、新しい_headers
プロパティはCSRFトークンで初期化されます。次に、ajax POSTを起動できる3つの異なる場所(セッション変数のリセット時またはリストビューの遅延読み込み時)で、$。ajaxのheadersオプションが_headers
。
とにかく、サーバー側で受信したX-XSRF-TOKENは暗号化されたメタ_tokenからのものであるため、CSRF保護は正常に機能していると思います。
app\Http\Middleware\VerifyCsrfToken.php
は次のようになります(基本的にLaravel 5-LOL)によって提供されるデフォルトの実装に戻ります):
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $request->session()->token();
$_token = $request->input('_token');
$header = $request->header('X-XSRF-TOKEN');
return StringUtils::equals($token, $_token) ||
($header && StringUtils::equals($token, $this->encrypter->decrypt($header)));
}
私はあなたがこのようなことをすることができると思います(機会があればテストされていませんが更新されます)
$(document).on('submit', 'form', function(e)
$(this).append('<input name="_token" value="{{{ Session::token() }}}">);
});
実際には、トークンを有効期限が切れたときに再更新する変数に保存することをお勧めします。
サブミット時に追加することの利点は、ajaxを介して要素を追加した場合、他に何も追加しなくても機能すると思います。
EDIT:Rails UJS with Laravel(この自動CRSFトークン機能を含む): https://medium.com/@barryvdh/unobtrusive-javascript-with-jquery-ujs-and-laravel-e05f444d3439
ヘッダーに沿って渡す必要がありますX-XSRF-TOKEN
は、暗号化されたcsrf-token
。
私が知っているこれを行うことができる2つの方法があります。トークンを暗号化して、ビューに渡すことができます。
$xsrfToken = app('Illuminate\Encryption\Encrypter')->encrypt(csrf_token());
return view('some.ajax.form.view')->with('xsrf_token', $xsrfToken);
または、JavaScriptを使用してCookieからトークンを取得できます(Angularを使用すると簡単になります)。 Vanilla JSでは、次のようなことができます。
function getCookie(name) {
var pattern = RegExp(name + "=.[^;]*")
matched = document.cookie.match(pattern)
if (matched) {
var cookie = matched[0].split('=')
return decodeURIComponent(cookie[1])
}
return false
}
JQueryでは、ajaxリクエストに対して次のような処理を実行できます。
$.ajax({
// your request
//
beforeSend: function(request) {
return request.setRequestHeader('X-XSRF-TOKEN', getCookie('XSRF-TOKEN'));
}
});