2017-12-11 165 views
13

Tôi có một hệ thống Symfony 3.3.13 với nhiều hình thức khác nhau.tùy chọn xác thực của khách hàng + form_login ngắt tất cả mã thông báo csrf

Để đạt được "liên kết sâu" trong các biểu mẫu này, ví dụ: việc có thể bấm vào một liên kết email, đăng nhập và sau đó được chuyển hướng đến các hình thức Tôi đã thêm các thay đổi sau:

config.yml

framework: 
    secret:   "%secret%" 
    router: 
     resource: "%kernel.root_dir%/config/routing.yml" 
     strict_requirements: ~ 
    form:   ~ 
    csrf_protection: ~ 
    ... 
    more 
    ... 

security.yml

security: 
    providers: 
     zog: 
      id: app.zog_user_provider 


    firewalls: 
     dev: 
      pattern: ^/(_(profiler|wdt)|css|images|js)/ 
      security: false 
     main: 
      anonymous: ~ 
      logout: 
       path: /logout 
       target:/
      guard: 
       authenticators: 
        - app.legacy_token_authenticator 
        - app.token_authenticator 
       entry_point: app.legacy_token_authenticator 
      form_login:           <--this line alone breaks CSRF 
       use_referer: true        <--I tried partial combinations, none seems to make CSRF work 
       login_path: /security/login 
       use_forward: true 
       success_handler: login_handler 
       csrf_token_generator: security.csrf.token_manager <--added based on answer, doesn't help 

src/AppBundle/Resources/config/services.yml

login_handler: 
    class: AppBundle\Service\LoginHandler 
    arguments: ['@router', '@doctrine.orm.entity_manager', '@service_container'] 

src/AppBundle/Service/Loginhandler.php

<?php 
/** 
* Created by PhpStorm. 
* User: jochen 
* Date: 11/12/17 
* Time: 12:31 PM 
*/ 

namespace AppBundle\Service; 

use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\RedirectResponse; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; 
use Symfony\Component\Routing\RouterInterface; 
use Doctrine\ORM\EntityManager; 

class LoginHandler implements AuthenticationSuccessHandlerInterface 
{ 
    private $router; 
    private $container; 
    private static $key; 

    public function __construct(RouterInterface $router, EntityManager $em, $container) { 

     self::$key = '_security.main.target_path'; 

     $this->router = $router; 
     $this->em = $em; 
     $this->session = $container->get('session'); 

    } 

    public function onAuthenticationSuccess(Request $request, TokenInterface $token) { 

     //check if the referer session key has been set 
     if ($this->session->has(self::$key)) { 

      //set the url based on the link they were trying to access before being authenticated 
      $route = $this->session->get(self::$key); 

      //remove the session key 
      $this->session->remove(self::$key); 
      //if the referer key was never set, redirect to a default route 
      return new RedirectResponse($route); 
     } else{ 

      $url = $this->generateUrl('portal_job_index'); 

      return new RedirectResponse($url); 

     } 



    } 
} 

tôi cũng đã thực hiện chắc chắn rằng CSRF được kích hoạt trên biểu mẫu đăng nhập như thế này:

src/AppBundle/nguồn/views/security/login.html.twig

 <form action="{{ path('app_security_login') }}" method="post" autocomplete="off"> 
      <input type="hidden" name="_csrf_token" 
        value="{{ csrf_token('authenticate') }}" 
      > 

ứng dụng /config/services.yml

app.legacy_token_authenticator: 
    class: AppBundle\Security\LegacyTokenAuthenticator 
    arguments: ["@router", "@session", "%kernel.environment%", "@security.csrf.token_manager"] 

src/AppBundle/Security \ legacyTokenAuthenticator

class LegacyTokenAuthenticator extends AbstractGuardAuthenticator 
    { 
     private $session; 

     private $router; 

     private $csrfTokenManager; 

     public function __construct(
      RouterInterface $router, 
      SessionInterface $session, 
      $environment, 
      CsrfTokenManagerInterface $csrfTokenManager 
     ) { 
      if ($environment != 'test'){ 
       session_start(); 
      } 
      $session->start(); 
      $this->setSession($session); 
      $this->csrfTokenManager = $csrfTokenManager; 
      $this->router = $router; 
     } 


     /** 
     * @return mixed 
     */ 
     public function getSession() 
     { 
      return $this->session; 
     } 


     /** 
     * @param mixed $session 
     */ 
     public function setSession($session) 
     { 
      $this->session = $session; 
     } 


     /** 
     * Called on every request. Return whatever credentials you want, 
     * or null to stop authentication. 
     */ 
     public function getCredentials(Request $request) 
     { 
      $csrfToken = $request->request->get('_csrf_token'); 

      if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken('authenticate', $csrfToken))) { 
       throw new InvalidCsrfTokenException('Invalid CSRF token.'); 
      } 
      $session = $this->getSession(); 

      if (isset($_SESSION['ADMIN_logged_in']) && intval($_SESSION['ADMIN_logged_in'])){ 
       return $_SESSION['ADMIN_logged_in']; 
      } 
      return; 
     } 

     public function getUser($credentials, UserProviderInterface $userProvider) 
     { 
      return $userProvider->loadUserByUserId($credentials); 
     } 

     public function checkCredentials($credentials, UserInterface $user) 
     { 
      return $user->getUsername() == $credentials; 
     } 

     public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 
     { 
      return null; 
     } 

     public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 
     { 
      return null; 
     } 

     /** 
     * Called when authentication is needed, but it's not sent 
     */ 
     public function start(Request $request, AuthenticationException $authException = null) 
     { 
      $url = $this->router->generate('app_security_login'); 
      return new RedirectResponse($url); 
     } 

     public function supportsRememberMe() 
     { 
      return false; 
     } 


    } 

Tất cả kiểm tra CSRF - kể cả trên biểu mẫu đăng nhập - không thành công khi tôi thêm 5 dòng trong security.yml bắt đầu bằng form_login. Các lỗi tôi nhận được là:

The CSRF token is invalid. Please try to resubmit the form. portalbundle_portal_job 

Nguyên nhân:

Khi tôi loại bỏ những 5 dòng, tất cả các mã thông báo CSRF làm việc.

+0

Bạn đã theo dõi tài liệu này: https://symfony.com/doc/current/security/csrf_in_login_form.html? –

+0

không cụ thể, tất cả các biểu mẫu đều bị ảnh hưởng khi đăng nhập. Điều này có liên quan không? – jdog

+0

chỉ để xác nhận, biểu mẫu đăng nhập không có CSRF. Nhưng câu hỏi của tôi đề cập đến tất cả các biểu mẫu trong hệ thống – jdog

Trả lời

6

Đây là tệp security.yml tôi có từ một trong các dự án của tôi đã bật tính năng bảo vệ csrf. Tôi sử dụng FOS UserBundle, có vẻ khác với của bạn, nhưng bạn có thể thấy một cái gì đó ở đây giúp. Cụ thể, một trình tạo csrf phải được chỉ định để sử dụng FOS UserBundle (dưới tường lửa: main: form_login). Tôi cũng có access_control mẫu thiết lập để một số thiết bị đầu cuối chỉ có thể truy cập nếu người dùng được xác thực với một vai trò cụ thể - nhưng tôi không nghĩ rằng điều này sẽ ảnh hưởng đến csrf. Xem bên dưới:

security: 
    encoders: 
     FOS\UserBundle\Model\UserInterface: bcrypt 

    role_hierarchy: 
     ROLE_ADMIN:  ROLE_USER 
     ROLE_SUPER_ADMIN: ROLE_ADMIN 

    providers: 
     fos_userbundle: 
      id: fos_user.user_provider.username 

    firewalls: 
     main: 
      pattern: ^/ 
      form_login: 
       provider: fos_userbundle 
       csrf_token_generator: security.csrf.token_manager 
      logout:  true 
      anonymous: true 

    access_control: 
     - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/admin/, role: ROLE_ADMIN } 
     - { path: ^/event, role: ROLE_USER } 

Cũng trong config.yml chính tôi đã bật csrf trong khung công tác. Dưới đây là ảnh chụp toàn bộ nội dung:

framework: 
    #esi:    ~ 
    translator:  { fallbacks: ["%locale%"] } 
    secret:   "%secret%" 
    router: 
     resource: "%kernel.root_dir%/config/routing.yml" 
     strict_requirements: ~ 
    form:   ~ 
    csrf_protection: ~ 
+1

Cảm ơn, thật không may hai dòng này không tạo nên sự khác biệt. Tôi cũng đã thêm csrf vào biểu mẫu đăng nhập, chỉ để đạt được sự đồng thuận và điều này cũng không thành công – jdog

1

Đối với tôi, giao dịch thủ công với mã thông báo Symfony CSRF là một headcache chính. Ngắn làm việc đó chỉ để tìm hiểu làm thế nào để làm điều đó, tôi nghĩ rằng luôn luôn có một giải pháp đơn giản hơn.

Giải pháp của tôi về bảo vệ CSRF trong thông tin đăng nhập không chạy vào vấn đề này.

Tôi tạo thông tin đăng nhập biểu mẫu bằng cách sử dụng thành phần Form.

function loginAction() 
{ 
    $login = $this->createForm(LoginType::class); 
    $authenticationUtils = $this->get('security.authentication_utils'); 
    $error = $authenticationUtils->getLastAuthenticationError(); 

    return $this->render('Path/to/login.html.twig', [ 
     'form' => $login->createView(), 
     'error' => $error, 
    ]); 
} 

LoginType.php:

use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\Extension\Core\Type\TextType; 
use Symfony\Component\Form\Extension\Core\Type\PasswordType; 
//... 

class LoginType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('username', TextType::class) 
      ->add('password', PasswordType::class) 
     ; 
    } 
} 

login.html.twig:

{# template information #} 
{{ form_start(form) }} 
    {{ form_row(form.username, { 
     'full_name': '_username' 
    }) }} 
    {{ form_row(form.password, { 
     'full_name': '_password' 
    }) }} 
{{ form_end(form) }} 
{# template information #} 

security.yml:

security: 
    providers: 
     zog: 
      id: app.zog_user_provider 


    firewalls: 
     dev: 
      pattern: ^/(_(profiler|wdt)|css|images|js)/ 
      security: false 
     main: 
      anonymous: ~ 
      logout: 
       path: /logout 
       target:/
      form_login: 
       use_referer: true     
       login_path: /security/login 
       success_handler: login_handler 
       always_use_default_target_path: false 
       default_target_path:/

Nếu bạn đã CSRF kích hoạt trên hình thức, sau đó mẫu đăng nhập của bạn sẽ được bảo vệ CSRF mà không cần bất kỳ Gua tùy chỉnh nào thứ xác thực.

Các vấn đề liên quan