질문을 삭제하지 말아주세요.!
 
1
0
-1

라라벨에서는 CSRF 토큰의 유효성 검사가 실패할 경우,  TokenMismatchException 예외만 던지도록 되어 있는데요.

별도 Handler 를 정의해주지 않았다면, 사용자들은 500 에러를 보게 됩니다.

 

문제는 비정상적인 접근에 대해 500 에러는 정확합니다.

그러나 CSRF 토큰이 포함된 페이지를 열어 놓은 상태에서,

기본 세션 유지 시간인 2시간이 지나 토큰 만료로 인한 오류에는 예외 처리가 필요할 것 같습니다.

 

실제 토큰 에러 로그를 보니 정상적인 접근으로 추정되는 케이스가 대부분이었기 때문에,

대부분 토큰 만료로 인한 케이스로 추측하고 있습니다.

 

따라서 이를 해결하기 위한 방안을 고민중인데요.

 

먼저 CSRF 방어 기법에 대한 재정리를 위해 자료를 찾아보니, 아래 글이 가장 명확한 것 같습니다.

https://medium.com/@barryvdh/csrf-protection-in-laravel-explained-146d89ff1357#.5wtvgh4u5

요약하면 CSRF는 다른 도메인 간 폼 전송(쓰기 요청)만 가능하고,

다른 도메인 간 javascript 실행이 안되니 읽기 요청이 불가능합니다.

 

이런 전제로 기존 솔루션을 검색해보니 300초마다 토큰값을 새로 받아오는 패키지도 있네요.

그래서 제가 생각한 방법은 다음과 같습니다.

  1. CSRF 토큰이 포함된 페이지가 열린 시간과 폼 전송 시간을 체크.
  2. 페이지가 열려 있던 시간이 세션 유지 시간(기본 2시간)이 지난 경우, javascript 로 CSRF 토큰을 새로 받아온 뒤 폼 전송.
  3. 정상적인 사용자의 폼 전송은 페이지가 열린지 아무리 시간이 오래되더라도, 토큰 에러를 겪을 수 없게 됨.

 

이렇게 javasript 로 서버에서 CSRF 토큰을 새로 받아오는 기법은, CSRF 방어에 적합하다 생각이 듭니다만...

제가 미처 고려하지 못한 부분이나 다른 분들의 의견도 궁금합니다.

 

 

    CommentAdd your comment...

    1 answer

    1.  
      2
      1
      0

      spring 의 보안 프레임워크인 spring-security 문서에도 동일한 내용이 있습니다.

      csrf 토큰 만료가 되면 InvalidCsrfTokenException가 아닌 AccessDeniedHandler 를 던져서 사용자는 403 에러를 받고 입력 폼을 날리게 될 수 있는대요..

      이에 대한 해결책으로 3가지 방법을 제시하고 있습니다..

       

      1. 자바스크립트에서 세션 확인후 만료시 세션 갱신
      2.  예외 핸들러를 재구현하여 Csrf 타임아웃시 적절한 처리를 하도록 수정
      3. 쿠키에 csrf 토큰 삽입

      3번은 보안에 취약해 지므로 권장하지 않고 2번은 구현이 spring 이든 라라벨이든 꽤 까다로운 것 같습니다.

       

      1번이 심플하고 효과적인 듯 하며 경윤님이 제안하신 방법과 동일한 내용인 것 같습니다.

      1. 정광섭

        라라벨을 사용하신다면 링크해 주신 https://github.com/GeneaLabs/laravel-caffeine 가 이런 귀찮은 작업을 처리해주는 유용한 패키지같습니다.

        (근데 제가 위 패키지를 github 에 좋아요를 했는데 언제 왜 했는지 전혀 기억에 없네요...)

      2. 빈경윤

        spring 에서도 javascript 로 토큰 갱신을 안내하는 것을 보니, 보안 상 문제될 부분은 없나 봅니다.

         

        그리고 위 라라벨 패키지는 javascript setInterval 함수로 300초마다 토큰 값을 갱신하도록 되어 있고,

        세션 만료 시간보다 작게 설정하면 세션 만료 시간이 계속 연장되어,

        결국 세션이 만료되지 않고 계속 유지되는 단점이 생길 것 같더라고요.

        https://github.com/GeneaLabs/laravel-caffeine/blob/master/src/Http/Middleware/LaravelCaffeineDripMiddleware.php#L29

         

        그래서 form submit 시 유효 시간을 체크하는 방안을 생각했었는데,

        이 방법도 같은 세션의 브라우저 창을 2개 열어놓고 한 개 창에서 이미 토큰이 갱신되어 버리는 케이스는 대응이 안될 것 같고요.

         

        결국 말씀하신 2. 예외 핸들러 + javascript 갱신 조합으로 구현해야 모든 케이스에 대응이 가능하겠는데... 뭔가 일이 커지는 느낌이...^^;

      CommentAdd your comment...