기본적으로 php에서 csrf 대응 책은 get 대신 post로 보내기라든가, 다단계 호출 등이 이용되나 보안적으로 허술한 대응책이라고 합니다. post의 내용물은 얼마든지 해킹툴에 의해서 확인될 수 있고, 다단계 호출 또한 마찬가지이기 때문입니다. 그래서 제대로 된 대응책으로는 크게 두 가지가 거론되는데, 먼저 리퍼러의 헤더 정보를 체크하는 것입니다. HTTP_REFERER의 내용물을 확인해서, 올바른 경로를 통해 들어온 request인지 체크를 하는 방법입니다.

하지만 이 경우에도 같은 사이트 내에서 위조 요청이 생성되었이 생성되었을 경우에는 확인할 방법이 없고, 도메인 정보 체크 방식에 따라 해커가 얼마든지 이용할 수 있다고 합니다. 그래서 가장 널리 이용되는 것이 csrf Token을 활용하는 방식이고, 물론 이 경우에도 token을 제대로 활용하기 위해선 자주 갱신되고 추측하기 어려운 값을 생성할 필요가 있다고 합니다. 그리고 직접 token을 만드는 것보단, 프레임워크에서 제공하는 csrf Token을 이용하는 것이 가장 바람직한 방법으로 알려져 있습니다. 그리고 여담이지만 csrf Token을 사용한다고 하더라도 xss 취약점을 제거하지 않으면 무용지물이라는 사실을 염두에 두는 것이 중요합니다.

CakePHP에서는 자체적으로 csrfToken을 지원하는 component 가 존재하기에 사용법 자체는 굉장히 쉽습니다.그냥 Form Helper를 사용한 상태에서, Csrf component를 해당 컨트롤러에 로드하면 끝입니다. 그렇게만 하면 CakePHP는 자동적으로 토큰을 생성시키고 Controller 등에서 다음과 같이 토큰에 접근해 사용을 할 수 있습니다.

$token = $this->request->param('_csrfToken');

하지만 앞에서도 말했듯 csrf Token 을 사용하기 위해서는 먼저 Form Helper를 사용해서 Form을 만들어 놓은 상태여야 합니다.Helper는 한마디로 여러 view 에서 공통적으로 사용하는 기능들을 따로 도와주는 도우미 역할을 하는 클래스입니다. 여러 controller에서 공통적으로 사용하는 기능을 모아놓은 클래스가 component라고 한다면, view를 위해선 Helper가 존재합니다. Form Helper는 그 중에서도 Form 생성을 도와주는 Helper 클래스입니다. 우리는 수많은 view에서 유저의 입력을 받아내는 Form을 사용하고 있습니다. 그 Form의 생성과 설정 등을 담당하는 클래스라고 할 수 있습니다. Form Helper의 사용법은 본 포스트의 주제와는 벗어나므로 생략하겠습니다. 궁금하신 분은 Form Helper를 참고하시길 바랍니다.

Form Helper를 통해 해당 뷰에서 Form을 생성해서 사용하고 있다면, 이제 해당 폼을 통해 들어오는 request는 csrf Token을 품고 있게 됩니다. 이젠 Controller에서 해당 csrf Token의 값을 비교하는 처리를 해야할 것입니다. 이 처리를 가능하게 해주는 클래스가 바로 CsrfComponent 이며, 해당 Component를 Controller에서 사용하기 위해선 로드를 해야합니다. 코드는 다음과 같이 쓸 수 있습니다.

//어떤 controller 클래스의 내부

public function initialize()
{
    parent::initialize();
    $this->loadComponent('Csrf');
}

이제 해당 콘트롤러에서 Csrf Compnent를 검증하는 작업이 가능해졌습니다. 컴포넌트 클래스에 속해있는 콜백함수 startup()가 private 메소드인 _validateToken()를 통해 token을 검증합니다. CsrfComponent 클래스를 가보면 기본적인 세팅을 확인할 수 있습니다.

protected $_defaultConfig = [
         'cookieName' => 'csrfToken',
         'expiry' => 0,
         'secure' => false,
         'httpOnly' => false,
         'field' => '_csrfToken',
     ];

이 부분의 수정을 통해 csrf Token의 설정을 변경할 수 있습니다. expiry는 csrf Token의 유효기간(지속기간)을 설정할 수 있습니다. 그리고 secure는 csrf Token값이 담긴 cookie가 HTTPS 커넥션에만 담기고 HTTP 커넥션은 거부할 것인지를 설정하는 부분입니다.기본값은 false이지만 이 부분을 true로 수정하면 HTTPS 프로토콜에서만 csrf Token을 이용할 수 있게 되고, HTTP를 통해서 오는 엑세스는 거부되게 됩니다.

참고 문서:

Csrf Component cookbook Csrf Component API

본 게시글은 2017.01.15 마지막 수정되었습니다