CSRF (r20210301판)

 


1. 개념
2. 공격 방법
2.1. 예시
3. 방어 방법



1. 개념


Cross-site Request Forgery
사이트 간 요청 위조

웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 해서 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법이다. 2008년에 발생한 옥션#s-2개인정보 유출 사건에서도 관리자 계정을 탈취하는 데 이 방법이 사용되었다. 공격의 난이도가 높지 않아 흔히 사용된다.


1.1. 나무위키에서


[오류!] CSRF 방지 토큰이 일치하지 않습니다. 다시 시도해주세요.
저장을 클릭하면 나타나는 나무위키 편집 오류

최초 형태는 XSS 방지 토큰이 일치하지 않습니다.였다.
왜 발생하는 지에 대해서는 여러 의견이 있는데 아래의 세 가지는 대표적이며 확인된 결과이다.
  • 미리보기 탭에서 하이퍼링크#s-6를 새 창으로 열 경우
  • 한 문서를 편집하던 중 다른 문서의 편집하기를 클릭할 경우
  • 문단의 제목만 넣고, 내용이 없을 경우

오류가 발생해도 수정 중이던 문서 내용은 보존되므로 그냥 다시 한번 저장을 클릭하면 된다.[1]
그러나, 새 문서 생성인 경우에는 얄짤 없다. 그냥 복붙하고 새로고침해서 다시 작성하자.(물론 리캡차는 다시 해야 한다.)


2. 공격 방법


이러한 공격을 하기 위해 해커는 우선 공격을 할 사이트를 먼저 분석한다. 예를 들어서, 이 나무위키의 경우에 토론은 한때 'namu.wiki/topic/'이라고 시작하며 뒤에 숫자가 붙는 형식이었는데 이 뒤의 숫자에 패턴[2]이 있었다.[3] 그러면 이 패턴을 이용하여 일반적인 방법으로 접근할 수 없는 페이지를 오픈한다든지, 개발에 사용되고 실제로 사용하지 않는 샘플 페이지를 찾아낸다든지 이러한 방법이 가능하다.

그게 아니라 웹페이지가 독자적 개발이 아닌 외부에서 이미 개발된 웹 애플리케이션을 사서 조금 수정한 것이라면 공격자는 경우에 따라서 해당 웹 애플리케이션을 구매하여 개인 서버에 설치를 한다. 그 다음에 공격 가능 패턴을 분석한다. 주로 공격자들이 찾는 것은 사용자 패스워드 변경 페이지나 타 시스템과 로그인 연동 주소 패턴 같은 인증 관련된 취약점을 찾는다.

그 다음에 여기서 나온 취약점을 이용해서 공개된 게시판이나 메일을 이용해서 사용자가 해당 링크를 열게 만들면 공격이 완료된다.


2.1. 예시


만일, A라는 사이트의 사용자 개인 비밀번호 변경을 하는 주소 패턴이 'abc.com/user.do?cmd=user_passwd_change&user=admin&newPwd=1234'라고 한다면 이러한 링크를 사용자의 메일로 XSS 형태로 보내고 메일을 읽게 되면 해당 사용자의 패스워드가 1234로 초기화된다. 이를 관리자에게 보내서 일반 계정을 관리자 계정으로 바꾸도록 한다든지, 아니면 관리자 계정 패스워드를 바꾸는데 이용한다면 해당 사이트의 모든 정보가 해킹당하는 데는 오랜 시간이 걸리지 않는다.

참고로, img 태그도 GET 메소드를 사용해서 보내는 것이기 때문에 img를 이용할 수도 있다. 대부분의 사이트는 img를 필터링하지 않으므로, 혹은 필터링하지 못하므로 유용한 방법이 될 수 있다.

예를 들면 나무위키의 경우
<img src="https://namu.wiki/member/logout">
와 같은 코드를 넣어주면 해당 문서를 볼 경우 로그아웃이 된다. 이는 나무위키 뿐만이 아닌 대부분의 사이트의 문제.[4]


3. 방어 방법


방어 방법 중 가장 기초적인 방법은 Referer 체크를 하는 방법이 있다. Referer는 HTTP 헤더에 있는 정보로 해당 요청이 요청된 페이지의 정보를 가지고 있는데 해당 정보는 Paros나 Zap, fiddler같은 프로그램으로 조작이 가능하지만 방법이 간단하여 소규모 웹사이트에 주로 이용되는 방법이다.

그 외에는 패스워드 변경 같은 민감한 정보를 다룰 때에는 세션에 임의난수(토큰)를 발급해서, 해당 난수가 없는 상황에서 해당 동작들이 이루어지면 요청을 거부하는 방법을 통하여 사용자가 정말로 변경을 의도하는 경우에만 변경을 시켜주는 방법, 변경 시에 CAPTCHA를 이용하여 CAPTCHA 인증코드가 없거나 틀리면 거부하도록 하는 방법 등이 이용되고 있다.

또한 GET/POST 등을 구분하여 주는 것 역시 유용하다.[5] img 태그 등을 이용할 경우 GET 요청으로 들어오게 될 것이고, 반면 흔히 하듯 form을 이용해 값을 받을 경우 POST를 이용하게 되는 경우가 많기 때문이다.

위의 방법들을 일일이 적용하기 귀찮다면, 대개 프레임워크에서 위의 방법들을 통합한 플러그인 등을 제공하는 경우들이 많으니 찾아보도록 하자. 또한 form 대신 ajax[6]를 통한 JSON API만 사용하는 방법이 있다. 만약 굳이 다른 도메인 간 통신을 하고자 한다면, jsonp를 이용하면 된다.

파이어폭스 버그질라


[1] 하지만 저장을 눌러도 다른 사용자가 편집을 하였다는 메시지가 뜨면서 저장이 되지 않을 때도 있다. 이럴때는 수정중인 내용을 복사한다음 새로고침을 해서 다시 붙여넣기를 할수밖에 없다.[2] 실제론 토론이 개설된 순서대로 붙는 일련번호다.[3] 지금은 namu.wiki/thread/ 뒤에 라틴 문자로 이루어진 난수가 붙는다.[4] HTML 편집을 한 후 바로 로그아웃이 되는것은 아니고 새로고침을 해야 한다.[5] 자체적으로 환경변수 전역화를 하는 제로보드, 그누보드 기반 사이트는 이 방법을 쓸 수 없다.[6] CORS가 비활성화되어 있어야 한다.