한 웹 사이트로 HTTP 요청을 보내는 경우, 두 가지 경우가 존재한다.
Same-site request
: 동일한 사이트 내 HTTP 요청 신뢰 가능
Cross-site request
: 외부 사이트로 HTTP 요청 신뢰 불가능
브라우저가 웹 사이트에 HTTP 요청을 보낼 때, 브라우저가 속한 도메인에 대한 쿠키를 요청에 포함시켜 전송한다.
브라우저는 Same-site/Cross-site를 구분하지 않고 전부 쿠키를 포함시켜 HTTP 요청을 전송한다. 이로 인해 서버는 크로스 사이트 요청과 동일 사이트 요청을 구분하지 못한다.
CSRF(Cross-Site Request Forgery)란, 서버가 HTTP 요청의 출처를 구분하지 못하는 취약점을 악용해 웹 사이트에 원하지 않는 명령을 보내는 공격이다.
Referer
는 요청이 어떤 웹 페이지에서 생성되었는지 식별하기 위해 설정하는 HTTP Header Option이다.
이 헤더는 사용자의 브라우징 기록의 일부를 노출시킬 수 있다는 단점이 있다.
또한 Referer Header는 Browser-Level에서 포함시키는 정보이므로, 신뢰성에 문제가 (변조 가능)있다.
위와 같은 이유로 Referer Header는 대부분의 경우 사용되지 않는다. (처리 과정에서 헤더에서 제거됨)
Chrome, Opera 브라우저의 쿠키에는 SameSite
라는 옵션이 존재한다.
SameSite은 cross-site 요청일 경우, 브라우저가 해당 쿠키의 포함 여부를 제어하는 속성이다.
Same-site request
: 항상 쿠키를 포함하여 전송
Cross-site request
: SameSite 설정에 따라 쿠키 포함 여부 결정
Strict
: 허용하지 않음
Lax
: 일부 허용
서버가 어떤 웹 페이지에서 발생한 요청인지 식별하기 위해 각 웹 페이지에 고유한 Secret Token을 삽입하는 방식이다.
특정 페이지는 시크릿 토큰을 HTTP 요청에 포함한다.
서버는 요청에 포함된 토큰을 확인하여 Same-site Request인지 Cross-site Request인지 판단한다.
외부 사이트(Different Origin)의 비밀 토큰 접근은 SOP에 의해 차단된다.
비밀 토큰은 무작위로 생성되며 고유한 값이기 때문에 공격자는 이 비밀 값을 추측하거나 알아낼 수 없다.
시크릿 토큰 사용하여 CSRF에 대응하는 방식에 대해 알아보자.
위 두 값들은 JavaScript 변수 안에 저장되며, 사용자 입력이 필요한 모든 폼(form)안에 자동으로 포함된다.
사용자가 폼을 제출할 경우, 이 두 값은 숨겨진 파라미터에 포함된다.
시크릿 토큰은 단순한 문자열이 아니라 다음 네 가지 요소를 조합해 MD5 Hash로 암호화된 값이다.
Site secret value
Timestamp
User session ID
Randomly generated session string
서버는 비밀 값을 확인하기만 하면 어떤 사이트에서 요청이 발생했는지 식별할 수 있지만, 일부 조건에서 우회가 가능하다는 한계점이 있다.
타겟 페이지가 X-FRAME-OPTIONS header를 설정하지 않은 경우, 클릭재킹(Clickjacking) 공격이 가능
Attack Scenario는 다음과 같다.
웹 사이트는 요청에 항상 Secret token을 요구함
공격자는 blank secret를 포함하여 크로스 사이트 요청을 전송
서버는 해당 요청을 정상적으로 처리하지 않고 오류 메시지를 포함한 응답 페이지를 보여준다.
이 페이지에는 Real secret token이 포함되어 있다.
타겟 페이지가 투명한 프레임에 삽입된 상태에서, 사용자가 제출 버튼을 클릭하도록 속임(클릭 재킹)