zoukankan      html  css  js  c++  java
  • laravel的csrf token 的了解及使用

    之前在项目中因为没有弄清楚csrf token的使用,导致发请求的话,一直请求失败,今天就一起来看一下csrf的一些东西。

     1.Cross-site request forgery 跨站请求伪造,也被称为 “one click attack” 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。

    2.从字面意思就可以理解:当你访问 fuck.com 黑客页面的时候,页面上放了一个按钮或者一个表单,URL/action 为 http://you.com/delete-myself,这样引导或迫使甚至伪造用户触发按钮或表单。在浏览器发出 GET 或 POST 请求的时候,它会带上 you.com 的 cookie,如果网站没有做 CSRF 防御措施,那么这次请求在 you.com 看来会是完全合法的,这样就会对 you.com 的数据产生破坏。

    3.第三方恶意网站也是可以构造post请求并提交至被攻击网站的,所以POST方式提交只是提高了攻击的门槛而已,无法防范CSRF攻击,所以对post也要进行防范

    关于csrf更多的请参考 https://segmentfault.com/q/1010000000713614  https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/

    在laravel中为了防止csrf 攻击,设计了  csrf token

    laravel默认是开启了csrf token 验证的,关闭这个功能的方法:

    (1)打开文件:appHttpKernel.php

      把这行注释掉:‘AppHttpMiddlewareVerifyCsrfToken’

    (2)打开文件 appHttpMiddlewareVerifyCsrfToken.php

        修改handle方法为:   

    1  public function handle($request, Closure $next)
    2     {
    3         // 使用CSRF
    4         //return parent::handle($request, $next);
    5         // 禁用CSRF
    6         return $next($request);
    7     }

    csrf的使用:

    (1)在html的代码中加入:

    1 <input type="hidden" name="_token" value="{{ csrf_token() }}" />

    (2)使用cookie 方式 ,将appHttpMiddlewareVerifyCsrfToken.php修改为:

     1 <?php namespace AppHttpMiddleware;
     2 
     3 use Closure;
     4 use IlluminateFoundationHttpMiddlewareVerifyCsrfToken as BaseVerifier;
     5 
     6 class VerifyCsrfToken extends BaseVerifier {
     7 
     8     /**
     9      * Handle an incoming request.
    10      *
    11      * @param  IlluminateHttpRequest  $request
    12      * @param  Closure  $next
    13      * @return mixed
    14      */
    15     public function handle($request, Closure $next)
    16     {
    17         return parent::addCookieToResponse($request, $next($request));
    18     }
    19 
    20 }

    使用cookie方法就不用在每个页面都加入这个input 的 hidden 标签

    还可以部分使用csrf检测部分不使用。

    注:本文从laravel的csrf token开始到此参考:http://blog.csdn.net/proud2005/article/details/49995389

    关于  laravel 的 csrf 保护更多的内容请参考 laravel学院文档:http://laravelacademy.org/post/6742.html

    下面说说我们那个项目中的关于csrf token的使用:

    在我的另一篇文章中也提到了我们那个项目中的使用过程

    在中间件VerifyCsrfToken.php中修改内容为:
     1 protected function tokensMatch($request)
     2 {
     3     // If request is an ajax request, then check to see if token matches token provider in
     4     // the header. This way, we can use CSRF protection in ajax requests also.
     5     $token = $request->ajax() ? $request->header('X-CSRF-TOKEN') : $request->input('_token');
     6     return $request->session()->token() == $token;
     7 }
     8 
     9 public function handle($request,Closure $next){
    10     //todo:需要在添加了登录验证之后,取消
    11    //这样是在post请求的时候不进行csrf token验证
    12     if($request->method() == 'POST')
    13     {
    14         return $next($request);
    15     }
    16     
    17     return parent::handle($request,$next);
    18 }
    然后在vue中的bootstrap.js中的引入的axios的位置添加
     1 window.axios.defaults.headers.common = { 2 'X-CSRF-TOKEN': document.querySelector('meta[name="X-CSRF-TOKEN"]').content, 3 'X-Requested-With': 'XMLHttpRequest' 4 }; 

    在index.blade.php中添加
     1 <meta name="X-CSRF-TOKEN" content="{{csrf_token()}}"> 

    上面的代码都好理解,就是获取到 csrf_token令牌,然后提交,再经过中间件验证即可

    下面重点来说一下 VerifyCsrfToken.php中间件

    中间件的内容最开始应该只有一个 handle函数:这个是所有的都进行csrf token验证

    1  public function handle($request,Closure $next){
    2         return parent::handle($request,$next);
    3     }

    现在项目中的这个中间件的内容

     1 <?php
     2 
     3 namespace AppHttpMiddleware;
     4 
     5 use IlluminateFoundationHttpMiddlewareVerifyCsrfToken as BaseVerifier;
     6 
     7 class VerifyCsrfToken extends BaseVerifier
     8 {
     9     /**
    10      * The URIs that should be excluded from CSRF verification.
    11      *
    12      * @var array
    13      */
    14     protected $except = [
    15         //
    16     ];
    17 //    protected $except = [
    18 //
    19 //        '/classroom_upload',
    20 //        'wk_upload',
    21 //        'wechat',
    22 //    ];
    23     protected function tokensMatch($request)
    24     {
    25         // If request is an ajax request, then check to see if token matches token provider in
    26         // the header. This way, we can use CSRF protection in ajax requests also.
    27         $token = $request->ajax() ? $request->header('X-CSRF-TOKEN') : $request->input('_token');
    28         return $request->session()->token() == $token;
    29     }
    30 
    31 
    32     public function handle($request,Closure $next){
    33         //todo:需要在添加了登录验证之后,取消
    34         if($request->method() == 'POST')
    35         {
    36             return $next($request);
    37         }
    38         
    39         return parent::handle($request,$next);
    40     }
    41 }

    我们来看一下 VerifyCsrfToken.php的源码             IlluminateFoundationHttpMiddlewareVerifyCsrfToken.php;

      1 <?php
      2 
      3 namespace IlluminateFoundationHttpMiddleware;
      4 
      5 use Closure;
      6 use CarbonCarbon;
      7 use IlluminateFoundationApplication;
      8 use SymfonyComponentHttpFoundationCookie;
      9 use IlluminateContractsEncryptionEncrypter;
     10 use IlluminateSessionTokenMismatchException;
     11 
     12 class VerifyCsrfToken
     13 {
     14     /**
     15      * The application instance.
     16      *
     17      * @var IlluminateFoundationApplication
     18      */
     19     protected $app;
     20 
     21     /**
     22      * The encrypter implementation.
     23      *
     24      * @var IlluminateContractsEncryptionEncrypter
     25      */
     26     protected $encrypter;
     27 
     28     /**
     29      * The URIs that should be excluded from CSRF verification.
     30      *
     31      * @var array
     32      */
     33     protected $except = [];
     34 
     35     /**
     36      * Create a new middleware instance.
     37      *
     38      * @param  IlluminateFoundationApplication  $app
     39      * @param  IlluminateContractsEncryptionEncrypter  $encrypter
     40      * @return void
     41      */
     42     public function __construct(Application $app, Encrypter $encrypter)
     43     {
     44         $this->app = $app;
     45         $this->encrypter = $encrypter;
     46     }
     47 
     48     /**
     49      * Handle an incoming request.
     50      *
     51      * @param  IlluminateHttpRequest  $request
     52      * @param  Closure  $next
     53      * @return mixed
     54      *
     55      * @throws IlluminateSessionTokenMismatchException
     56      */
     57     public function handle($request, Closure $next)
     58     {
     59         if (
     60             $this->isReading($request) ||
     61             $this->runningUnitTests() ||
     62             $this->inExceptArray($request) ||
     63             $this->tokensMatch($request)
     64         ) {
     65             return $this->addCookieToResponse($request, $next($request));
     66         }
     67 
     68         throw new TokenMismatchException;
     69     }
     70 
     71     /**
     72      * Determine if the HTTP request uses a ‘read’ verb.
     73      *
     74      * @param  IlluminateHttpRequest  $request
     75      * @return bool
     76      */
     77     protected function isReading($request)
     78     {
     79         return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
     80     }
     81 
     82     /**
     83      * Determine if the application is running unit tests.
     84      *
     85      * @return bool
     86      */
     87     protected function runningUnitTests()
     88     {
     89         return $this->app->runningInConsole() && $this->app->runningUnitTests();
     90     }
     91 
     92     /**
     93      * Determine if the request has a URI that should pass through CSRF verification.
     94      *
     95      * @param  IlluminateHttpRequest  $request
     96      * @return bool
     97      */
     98     protected function inExceptArray($request)
     99     {
    100         foreach ($this->except as $except) {
    101             if ($except !== '/') {
    102                 $except = trim($except, '/');
    103             }
    104 
    105             if ($request->is($except)) {
    106                 return true;
    107             }
    108         }
    109 
    110         return false;
    111     }
    112 
    113     /**
    114      * Determine if the session and input CSRF tokens match.
    115      *
    116      * @param  IlluminateHttpRequest  $request
    117      * @return bool
    118      */
    119     protected function tokensMatch($request)
    120     {
    121         $token = $this->getTokenFromRequest($request);
    122 
    123         return is_string($request->session()->token()) &&
    124                is_string($token) &&
    125                hash_equals($request->session()->token(), $token);
    126     }
    127 
    128     /**
    129      * Get the CSRF token from the request.
    130      *
    131      * @param  IlluminateHttpRequest  $request
    132      * @return string
    133      */
    134     protected function getTokenFromRequest($request)
    135     {
    136         $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
    137 
    138         if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
    139             $token = $this->encrypter->decrypt($header);
    140         }
    141 
    142         return $token;
    143     }
    144 
    145     /**
    146      * Add the CSRF token to the response cookies.
    147      *
    148      * @param  IlluminateHttpRequest  $request
    149      * @param  SymfonyComponentHttpFoundationResponse  $response
    150      * @return SymfonyComponentHttpFoundationResponse
    151      */
    152     protected function addCookieToResponse($request, $response)
    153     {
    154         $config = config('session');
    155 
    156         $response->headers->setCookie(
    157             new Cookie(
    158                 'XSRF-TOKEN', $request->session()->token(), Carbon::now()->getTimestamp() + 60 * $config['lifetime'],
    159                 $config['path'], $config['domain'], $config['secure'], false
    160             )
    161         );
    162 
    163         return $response;
    164     }
    165 }

    其中app下面的VerifyCsrfToken中间件是继承源码中的那个VerifyCsrfToken类

    我们项目中重写了tokensMatch方法,然后调父类的handle的时候,父类中使用的是this调用tokensMatch的,个人感觉应该最后有用的是我们重写的这个方法,如果是ajax请求的话,我们就检测$request->header('X-CSRF-TOKEN')与session中的token是否一样 否则的话,就检测 $request->input('_token')与session中的token是否一样。

    本人对laravel的原理还不太了解,上面的内容如果有什么错误的话,欢迎指教。

    如需转载请注明:

    本文出处:http://www.cnblogs.com/zhuchenglin/p/7723997.html

  • 相关阅读:
    openwrt解压zstd包时报错"openwrt/dl/zstd-1.4.5.tar.zst: Permission denied tar: This does not look like a tar archive tar: Exiting with failure status due to previous errors"如何处理?
    pip如何使用代理?
    Markdown: 对Typora的一些小调整
    ray
    关于nginx中proxy_set_header的设置
    解决 curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused
    mysql 查询慢问题分析
    Elasticsearch导出数据存入本地文件
    mysql count 几种写法时间的比较
    python 线程池的实现
  • 原文地址:https://www.cnblogs.com/zhuchenglin/p/7723997.html
Copyright © 2011-2022 走看看