Laravel 具体是如何构建和检查 CSRF 令牌的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22611251/
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
How specifically does Laravel build and check a CSRF token?
提问by prograhammer
I'm using Laravel's CSRF protection on my public site. However since Laravel uses a session to maintain this, I'm worried that a user might walk away from their computer and return to a page they have previously left open, only to find ajax requests don't work. The ajax requests don't work because the session has timed out (and the token no longer validates?). If these users were "logged in" users, then I could simply redirect them back to the login page. Since they are public users, then the user is forced to refresh the page to get it back working (awkward).
我在我的公共站点上使用 Laravel 的 CSRF 保护。然而,由于 Laravel 使用会话来维护这一点,我担心用户可能会离开他们的计算机并返回到他们之前打开的页面,却发现 ajax 请求不起作用。ajax 请求不起作用,因为会话已超时(并且令牌不再验证?)。如果这些用户是“登录”用户,那么我可以简单地将他们重定向回登录页面。由于他们是公共用户,因此用户被迫刷新页面以使其恢复工作(尴尬)。
Or am I wrong about this? Would the CSRF token still get validated by Laravel (even after the session has timed out, the page will still send over the token...but what will Laravel do with it?). An optimal solution would be to have the tokens partially based on a timestamp so that we could give the tokens expiration limits apart from session time limits. I could make my CSRF tokens last for 2 days (so only those users that walk away for 2 days will return to a dead page).
还是我错了?CSRF 令牌是否仍会被 Laravel 验证(即使在会话超时后,页面仍会通过令牌发送......但 Laravel 将如何处理它?)。最佳解决方案是让令牌部分基于时间戳,以便我们可以在会话时间限制之外给出令牌过期限制。我可以让我的 CSRF 令牌持续 2 天(所以只有那些离开 2 天的用户才会返回死页)。
Ultimately this brings me to my question: Where is the specific code in the Laravel framework that handles this?I'm currently trying to locate it. Also, is there an easy drop in replacement I can make, or am I left to create my own version of csrf_token();
to output to my pages and then I would need to create my own route filter to go with it.
最终这让我想到了我的问题:Laravel 框架中处理这个问题的具体代码在哪里?我目前正在尝试找到它。另外,是否可以轻松进行替换,或者我是否需要创建自己的版本csrf_token();
以输出到我的页面,然后我需要创建自己的路由过滤器来配合它。
回答by Antonio Carlos Ribeiro
Laravel just facilitates that for you by keeping the token stored in session, but the code is actually yours (to change as you wish). Take a look at filters.php
you should see:
Laravel 只是通过将令牌存储在会话中来为您提供便利,但代码实际上是您的(可以根据需要进行更改)。看看filters.php
你应该看到:
Route::filter('csrf', function()
{
if (Session::token() != Input::get('_token'))
{
throw new Illuminate\Session\TokenMismatchException;
}
});
It tells us that if you have a route:
它告诉我们,如果您有路线:
Route::post('myform', ['before' => 'csrf', 'uses' => 'MyController@update']);
And the user session expires, it will raise an exception, but you can do the work yourself, keep your own token stored wherever you think is better, and instead of throwing that exception, redirect your user to the login page:
并且用户会话过期,它会引发异常,但您可以自己完成这项工作,将您自己的令牌存储在您认为更好的地方,而不是抛出该异常,而是将您的用户重定向到登录页面:
Route::filter('csrf', function()
{
if (MySession::token() != MyCSRFToken::get())
{
return Redirect::to('login');
}
});
And, yes, you can create your own csrf_token()
, you just have to load it before Laravel does. If you look at the helpers.php file in Laravel source code, you`ll see that it only creates that function if it doesn't already exists:
而且,是的,你可以创建自己的csrf_token()
,你只需要在 Laravel 之前加载它。如果您查看 Laravel 源代码中的 helpers.php 文件,您会发现它仅在该函数不存在时才创建该函数:
if ( ! function_exists('csrf_token'))
{
function csrf_token()
{
...
}
}
回答by prograhammer
Since this has become a popular question, I decided to post my specific solution that has been working quite nicely...
由于这已成为一个受欢迎的问题,因此我决定发布我的特定解决方案,该解决方案一直运行良好......
Most likely you will have a header.php or some partial view that you use at the top of all your pages, make sure this is in it in the <head>
section:
很可能你会有一个 header.php 或一些你在所有页面顶部使用的部分视图,确保它在它的<head>
部分中:
<meta name="_token" content="<?=csrf_token(); ?>" />
In your filters.php:
在您的 filters.php 中:
Route::filter('csrf', function()
{
if (Request::ajax()) {
if(Session::token() != Request::header('X-CSRF-Token')){
throw new Illuminate\Session\TokenMismatchException;
}
}
});
And in your routes.php
在你的 routes.php
Route::group(array('before' => 'csrf'), function(){
// All routes go in here, public and private
});