php 页面中所有表单的 Laravel 5 CSRF 全局令牌隐藏字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28500525/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel 5 CSRF global token hidden field for all forms in a page
提问by raphadko
I recently migrated to Laravel 5, and now CSRF check is on every post submission. I thought about removing it but I want to follow the best practices, so I'll keep it that way.
我最近迁移到 Laravel 5,现在每个帖子提交都进行 CSRF 检查。我想删除它,但我想遵循最佳实践,所以我会保持这种方式。
On the other hand, I'm problems submitting ajax requests.. my page has multiple forms and some submissions are not even from forms, just plain ajax calls. My idea is to have one single hidden "token" input on the page and attach it to every submission. Are there any drawbacks on having that universal single token input?
另一方面,我在提交 ajax 请求时遇到问题。我的页面有多个表单,有些提交甚至不是来自表单,只是普通的 ajax 调用。我的想法是在页面上有一个隐藏的“令牌”输入并将其附加到每个提交中。使用通用单令牌输入有什么缺点吗?
Also, how can I output the token? Would it be ok to just create a hidden input on the page footer?
另外,如何输出令牌?只在页脚上创建一个隐藏的输入就可以了吗?
回答by lukasgeiter
I don't see any drawbacks. You can easily create a global token field in your layout file:
我没有看到任何缺点。您可以在布局文件中轻松创建全局令牌字段:
<input type="hidden" name="_token" id="csrf-token" value="{{ Session::token() }}" />
Or if you use the form builder:
或者,如果您使用表单构建器:
{!! Form::token() !!}
In jQuery you could use something like thisto attach the token to every request.
在jQuery中,你可以使用类似这样的令牌附加到每个请求。
回答by Arda
回答by tomloprod
You can use something like this at the bottom of the page:
您可以在页面底部使用类似的内容:
$('form').append('{{csrf_field()}}');
This will append a hidden input to all your forms
:
这会将隐藏的输入附加到您的所有forms
:
<input type="hidden" name="_token" value="yIcHUzipr2Y2McGE3EUk5JwLOPjxrC3yEBetRtlV">
And for all your AJAX requests:
对于您所有的 AJAX 请求:
$.ajaxSetup({
beforeSend: function (xhr, settings) {
//////////// Only for your domain
if (settings.url.indexOf(document.domain) >= 0) {
xhr.setRequestHeader("X-CSRF-Token", "{{csrf_token()}}");
}
}
});
回答by dcarrith
Here are some excerpts of how I got my CSRF working for all the different scenarios in my jQuery Mobile application that I recently upgraded to use Laravel 5:
以下是我如何让我的 CSRF 在我最近升级为使用 Laravel 5 的 jQuery Mobile 应用程序中的所有不同场景中工作的一些摘录:
I added an encrypted csrf token in a variable that will be passed to my views in my main base controller:
app\Http\Controllers\MyController.php
我在一个变量中添加了一个加密的 csrf 令牌,该令牌将传递给我的主基本控制器中的视图:
app\Http\Controllers\MyController.php
$this->data['encrypted_csrf_token'] = Crypt::encrypt(csrf_token());
Then, I added the meta tag in my main view header:
resources\views\partials\htmlHeader.blade.php
然后,我在主视图标题中添加了元标记:
resources\views\partials\htmlHeader.blade.php
<meta name="_token" content="{!! $encrypted_csrf_token !!}"/>
Then, I also added this jquery snippet as suggested in some forums:
然后,我还按照某些论坛中的建议添加了此 jquery 代码段:
$(function () {
$.ajaxSetup({
headers: {
'X-XSRF-TOKEN': $('meta[name="_token"]').attr('content')
}
});
});
But, the key (for my setup at least) was the addition of the check for the XSRF-TOKEN
cookie in my custom VerifyCsrfToken middleware:
app\Http\Middleware\VerifyCsrfToken.php:
但是,关键(至少对于我的设置)是XSRF-TOKEN
在我的自定义 VerifyCsrfToken 中间件中添加了对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));
}
Before I added that, just about all of my AJAX POSTs (including form submissions and lazyloading listviews) were failing due to a TokenMismatchException
.
在我添加之前,几乎我所有的 AJAX POST(包括表单提交和延迟加载列表视图)都由于TokenMismatchException
.
EDIT:On second thought, I'm not sure how much sense it makes to compare the session token with the one set in the cookie (which would have come from the session token in the first place right?). That may have just been bypassing the security of it all.
编辑:再想一想,我不确定将会话令牌与 cookie 中设置的令牌进行比较有多大意义(这首先来自会话令牌,对吗?)。这可能只是绕过了这一切的安全性。
I think my main issue was with the jquery snippet above which was supposed to be adding the X-XSRF-TOKEN header to every ajax request. That wasn't working for me in my in jQuery Mobile app (specifically, in my lazyloader plugin) until I added some options for the plugin itself. I added a new default selector csrf
(which would be meta[name="_token"]
in this case) and a new default setting csrfHeaderKey
(which would be X-XSRF-TOKEN
in this case). Basically, during initialization of the plugin, a new _headers
property is initialized with the CSRF token if one is locatable by the csrf
selector (default or user-defined). Then, in the 3 different places where an ajax POST can be fired off (when resetting session variables or when lazyloading a listview) the headers option of $.ajax is set with whatever is in _headers
.
我认为我的主要问题是上面的 jquery 片段应该将 X-XSRF-TOKEN 标头添加到每个 ajax 请求。在我为插件本身添加一些选项之前,这在我的 jQuery Mobile 应用程序中(特别是在我的lazyloader 插件中)对我不起作用。我添加了一个新的默认选择器csrf
(meta[name="_token"]
在这种情况下)和一个新的默认设置csrfHeaderKey
(X-XSRF-TOKEN
在这种情况下)。基本上,在插件的初始化过程中,如果一个新_headers
属性可通过 CSRF 令牌定位,则使用 CSRF 令牌初始化csrf
选择器(默认或用户定义)。然后,在可以触发 ajax POST 的 3 个不同位置(重置会话变量或延迟加载列表视图时), $.ajax 的 headers 选项设置为_headers
.
Anyway, since the X-XSRF-TOKEN received on the server-side comes from the encrypted meta _token, I think the CSRF protection is now working as it should.
无论如何,由于服务器端收到的 X-XSRF-TOKEN 来自加密的元 _token,我认为 CSRF 保护现在可以正常工作。
My app\Http\Middleware\VerifyCsrfToken.php
now looks like this (which is essentially back to the default implementation provided by Laravel 5 - LOL):
我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)));
}
回答by Sabrina Leggett
I think you can do something like this (not tested will update if I get a chance)
我认为你可以做这样的事情(如果我有机会,未测试会更新)
$(document).on('submit', 'form', function(e)
$(this).append('<input name="_token" value="{{{ Session::token() }}}">);
});
you actually might want to store token in a variable that you reupdate as it expires.
您实际上可能希望将令牌存储在一个变量中,该变量在到期时重新更新。
The benefit of appending it on submit is if you append elements via ajax I think it'll still work without having to add anything else.
在提交时附加它的好处是,如果您通过 ajax 附加元素,我认为它仍然可以工作而无需添加任何其他内容。
EDIT:Here's a great article on using Rails UJS with Laravel (which includes this auto CRSF tokenfunctionality): https://medium.com/@barryvdh/unobtrusive-javascript-with-jquery-ujs-and-laravel-e05f444d3439
编辑:这是一篇关于在 Laravel 中使用 Rails UJS 的很棒的文章(包括这个自动 CRSF 令牌功能):https: //medium.com/@barryvdh/unobtrusive-javascript-with-jquery-ujs-and-laravel-e05f444d3439
回答by tplaner
You need to pass along the header X-XSRF-TOKEN
which contains an encrypted version of the csrf-token
.
您需要传递X-XSRF-TOKEN
包含加密版本的csrf-token
.
There are two ways which this can be done that I am aware of. You can encrypt the token and pass it along to the view:
我知道有两种方法可以做到这一点。您可以加密令牌并将其传递给视图:
$xsrfToken = app('Illuminate\Encryption\Encrypter')->encrypt(csrf_token());
return view('some.ajax.form.view')->with('xsrf_token', $xsrfToken);
Or you can grab the token from cookies using JavaScript (Angular makes this easy). In vanilla JS you might do something like this:
或者您可以使用 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
}
In jQuery you might then do something like this for the ajax request:
在 jQuery 中,您可能会为 ajax 请求执行以下操作:
$.ajax({
// your request
//
beforeSend: function(request) {
return request.setRequestHeader('X-XSRF-TOKEN', getCookie('XSRF-TOKEN'));
}
});