스프링 Security 강의를 듣다가 설정 부분에서 http.csrf()란 설정을 꺼주는 설정이 있었는데 이 설정은 왜 사용하고 어떤 것인지 궁금해서 정리를 해보았다.
웹 사이트 보안 약점을 공격하는 방식
사이트간 요청 위조는 사용자한테 특정 사이트가 신뢰할 수 있는 상태를 구성해놓은 뒤 , 사용자가 사이트에서 사이트 간 요청 위조 공격을 하는 페이지를 열게 되면 , 공격 대상이 되는 웹페이지를 보안에 취약하게 하거나, 수정 삭제등의 작업을 하게하는 공격 방법이다.
이미지의 절차를 보면
1- > mybank.com 사이트에 로그인
2 -> 사용자는 CSRF 코드가 삽입된 페이지를 방문하게 된다.
3 -> 페이지에 삽입된 코드는 POST 방식으로 recipient = attaker & amount = 1000이란 값을 보내는 방식이다.
4 -> 결과적으로 mybank.com 에 잘못된 요청을 전송하게 된다.
추가적으로 Spring Security 레퍼런스에 나와있는 설명을 추가하자면
다음과 같은 자신의 돈을 다른 은행계좌로 이체하는 폼을 은행 웹사이트에서 제공한다고 하자
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876
그런 다음 다음과 같은 CSRF 코드 페이지를 열었다고 하자 , 사용자는 Win Money 버튼을 누르게 되면 공격자에게 100 달러를 송금하게 되는 것이다.
<form action="https://bank.example.com/transfer" method="post">
<input type="hidden"
name="amount"
value="100.00"/>
<input type="hidden"
name="routingNumber"
value="evilsRoutingNumber"/>
<input type="hidden"
name="account"
value="evilsAccountNumber"/>
<input type="submit"
value="Win Money!"/>
</form>
문제는 웹사이트에서는 이러한 요청을 악의적인 요청인지 정상적인 요청이 구분 할 수가 없다는 것이다. 악의적인 요청을 거부하려면 정상적인 요청만 제공할 수 있는 무언가를 제공받아야만 한다.
이를 해결하기 위해서 레퍼런스에서는 토큰 동기화 패턴을 제안하였다.
이 방법은 세션 쿠키외에 추가적으로 무작위로 생성된 토큰을 각 요청에서 필요하도록 하는 것이다. 요청을 받으면 제공 받은 토큰과 실제 값과 비교하게 되고 값이 일치하지 않으면 요청이 실패하도록 하게 하는 것이다.
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>
추가적으로 csrf란 파라미터를 추가적으로 요청받게 되었고 공격자는 이러한 토큰을 알 수가 없기 때문에 요청에 실패하게 된다. (csrf)변수는 서버에서만 가지고 있는 값이기 때문
일반적으로 Spring Security에서는 일반 사용자가 브라우저에서 사용하는 모든 요청에 대해서는 CSRF 보호를 사용하는 것을 권장하고 있지만 , 브라우저를 통해서가 아닌 요청을 받는다면 사용하지 않아도 된다고 한다.
이러한 경우에는 세션을 통해서 서버와 사용자가 상태를 유지하고 있으므로 Rest api를 통해서 Stateless한 서버를 설계할 경우 json을 이용해서 통신하므로 csrf를 사용할 이유(csrf는 세션이나 쿠키에 의존해야 한다)가 없어지는 것이다. 또한 다른 토큰 메커니즘을 사용하면 CSRF를 굳이 사용하지 않아도 된다는 것이다.