Laravel 前后端分离 csrf 防护

首先根据文档详解csrf的流程机制,然后分析下怎么在前后端分离的情况下进行csrf防护?
1.首先介绍token的生成,在 Illuminate\Session\Store.php 中start() 方法中,然后点击方法regenerateToken()方法中:

public function start()
{
    $this->loadSession();
    if (! $this->has('_token')) {
        $this->regenerateToken();  
    }
    return $this->started = true;
}

    public function regenerateToken()
{
    $this->put('_token', Str::random(40));
}

可见token是每次加载session时自动存入进session中。
2.然后看前台获取token值,首先表单中 {{csrf_token()}} 点入进去可以看到

function csrf_field()
{
    return new HtmlString('<input type="hidden" name="_token" value="'.csrf_token().'">'); //点入进去csrf_token方法中
}
function csrf_token()
{
    $session = app('session');
    if (isset($session)) {
        return $session->token();
    }
    throw new RuntimeException('Application session store not set.');
}

可以看到前台token值是从session存储的token值中获取到的。
3.然后看中间件是怎么验证前台提交的_token值:
在VerifyCsrfToken.php中继承Middleware类,点击进入类中查看handle方法

public function handle($request, Closure $next)
{
    if (
        $this->isReading($request) ||    //验证请求方式,如果不在数组['HEAD', 'GET', 'OPTIONS']中 返回false;
        $this->runningUnitTests() ||      //查看程序是否在进行测试 正式运行返回false;
        $this->inExceptArray($request) ||  //查看$except(白名单,不用验证_token)数组,如果请求路径在数组中返回true; 
        $this->tokensMatch($request)   //进行token验证
    ) {
        return $this->addCookieToResponse($request, $next($request));
    }

    throw new TokenMismatchException;
}

我们点击$this->tokensMatch()方法中可以看到请求中的token和session中的token是否相等:

    protected function tokensMatch($request)
{
    $token = $this->getTokenFromRequest($request); //从请求中获取_token值

    return is_string($request->session()->token()) &&
           is_string($token) &&
           hash_equals($request->session()->token(), $token);  //session中的token和请求中的token是否相等;
}

点击进入$this->getTokenFromRequest() 方法中

 protected function getTokenFromRequest($request)
{
    $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

    if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
        $token = $this->encrypter->decrypt($header);
    }

    return $token;
}  

从中可以看到获取请求中token值的几种方法:
from表单、头部值X-CSRF-TOKEN、头部值X-XSRF-TOKEN 这几种方试,只要明白了中间件怎么接收token值进行判断,然后前台就那么几种传值方式了
第一种 form表单传值 {{ csrf_field() }}或ajaxpost携带值 对应 $request->input('_token')
第二种 header头传值:

     <meta name="csrf-token" content="{{ csrf_token() }}">
     $.ajaxSetup({   //修改jquery库中代码
     headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
      }
 });

如果你用vue,只需将 resources/assets/js/bootstrap.js 引入你的文件中 然后 meta标签头部值放入总模板里,每次axios请求都会携带X-CSRF-TOKEN进入中间件进行验证,下面为js文件:

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
     window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
 } else {
console.error('CSRF token not found: https://learnku.com/docs/laravel/csrf#csrf-x-csrf-token');
}       

至此 从token值生成到前端携带token到后台验证已经完全走完一个流程了,接下来想一下假如前后端分离情况下怎么进行token验证
很简单每次提交前用api的形式获取token值传入前端(csrf_token()获取token值),然后前端用header头形式或ajax形式传入过来就可以了。
如果感觉有用就赞一下呗!!!

本作品采用《CC 协议》,转载必须注明作者和本文链接
自由飞
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 22
leo

如果是真·前后端分离是不需要考虑 csrf 攻击的,因为没有 cookie 存在

5年前 评论

@leo 你说会员信息cookie吗?你都存session里了怎么不会传到前端cookie里呢

5年前 评论
leo

@自由飞 真·前后端分离更不会有 session

5年前 评论
myhui0926 3年前
changfengshuoxue 4年前
小李世界 4年前

@leo 我有点蒙,如果你登录时不把用户信息存入session中,然后响应cookie值,你怎么在访问以后接口中怎么判断用户是否登录?大神请指点

5年前 评论

@自由飞 前后分离意味着后端只提供纯api接口不做其他支持 session cookies都不存在了 通过token来验证身份 路由也是由前端实现了

5年前 评论

前后分离只有 token验证用户, 没有 session cookie, 但是一般要做跨域处理(前后端不在同一个域名下)

5年前 评论

看来你没理解传统 MVC 开发模式和前后端分离有什么区别

5年前 评论

现在很多网站是工程上的前后端分离(本质上就是后端上了view层),只在浏览器上并且使用cookie和session~我觉得楼主的方法和思路挺好,只要api只给此网站即可(这样就很难兼容给其他网站或者app调用接口了)

5年前 评论
wenber

api中再考虑这个就有些多此一举了.看下框架中的api路由文件和web路由文件默认自带的中间件组.

5年前 评论

@ziyanziyu api默认中间件的确没有token检测,可是前后端分离就不会出现csrf攻击了吗?

5年前 评论

@CorePlusPlus 你的那个token只是验证用户身份,可是csrf攻击你怎么防御?

5年前 评论

@自由飞 如果真前后端分离,token放local storage,前端需要自己带header上过去,没有csrf的问题啊。
其他网站在csrf攻击的时候,token带不过去的

5年前 评论

@ziyanziyu 哈哈明白了,是我理解不到位多此一举了,本来项目就传验证用户的token了,也就不用考虑laravel框架本身的token了

5年前 评论
wonbin

前后端分离或者所谓的纯前后端分离 跟有没有cookie 有啥关系, 除非前端是native app , 前后端分离的 web 项目不需要cookie吗 csrf 就是cookie 劫持, 如果考虑到接口安全 还是要在post 提交 时 , 要么表单加 token, 要么header 加token

5年前 评论
游离不2

前后端分离,token 生成是个问题,从后端获取,服务器连接数会翻倍,从前端生成那就没啥意义了。

5年前 评论

可以学习下攻击,然后攻击下测试看看有什么区别没有

4年前 评论

这个有个问题,如果是前后端完全分离,接口和前端部署再不同域名下,csrf 如果还是基于session生成,就不行了

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!