1. 程式人生 > >Laravel原始碼分析----CSRF處理

Laravel原始碼分析----CSRF處理

跨站點請求偽造CSRF攻擊

攻擊者盜用使用者身份,通過偽造的身份以使用者的名義進行非法請求從而在未經使用者許可下完成某些非法操作。

Laravel的CSRF處理

  1. 在開啟session時為每個session分配一個token

    public function regenerateToken() {
        $this->put('_token', Str::random(40));
    }
    
  2. 引入VerifyCsrfToken中介軟體後在handle裡進行核心處理

    public function handle($request, Closure $next)
    {
        if (
            $this->isReading($request) ||
            $this->runningUnitTests() ||
            $this->inExceptArray($request) ||
            $this->tokensMatch($request)
        ) {
            return $this->addCookieToResponse($request, $next($request));
        }
    
        throw new TokenMismatchException;
    }
    
    • $this->isReading()判斷請求是否是['HEAD', 'GET', 'OPTIONS']這三種請求。
    • $this->runningUnitTests()判斷程式是否正在進行單元測試。
    • $this->inExceptArray()判斷請求是否需要進行Crsf驗證。
    • $this->tokensMatch()進行token驗證。

      protected function tokensMatch($request)
      {
          // 獲取請求url中的token
          $token = $this->getTokenFromRequest($request);
      
          return is_string($request->session()->token()) &&
                 is_string($token) &&
                 hash_equals($request->session()->token(), $token);
      }
      
      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;
      }
      
  3. 驗證通過後將csrf token加入響應包的cookie裡,然後通過驗證將請求通過next遞交給下一個處理件。

    protected function addCookieToResponse($request, $response)
    {
        $config = config('session');
    
        $response->headers->setCookie(
            new Cookie(
                'XSRF-TOKEN', $request->session()->token(), Carbon::now()->getTimestamp() + 60 * $config['lifetime'],
                $config['path'], $config['domain'], $config['secure'], false
            )
        );
    
        return $response;
    }