CSRF 란?
Cross-Site Request Forgery
라고 불리는 공격 방법이다. 웹사이트 취약점 공격의 일종이다. 특정 웹사이트에 로그인된 상태에서 해커가 원하는 URL 에 접근하게 만든다.
공격 주요 개념 정리
- 브라우저가 SESSION ID 등의 인증정보를 가지고 있는 것을 활용하는 것이다.
- 브라우저를 사용하지 않으면, 요청 시마다 인증정보를 수동으로 입력해줘야 하기 때문에 보통은 CSRF 공격에 당하지 않는다.
- 그러나 이 역시도 애플리케이션에서 인증 상태를 저장하고 있다면, 브라우저와 동일하게 취약하다.
해킹 시나리오
시나리오 1. GET 요청의 경우
- 피해자는 브라우저를 통해 https://any-bank-site.com/ 웹사이트에 접속하고 로그인한 상태이다.
- 브라우저에는 로그인을 통해 생성된 인증정보를 가지고 있다. ex)
JESSIONID=xxxx
- 이로 인해 이용자는 로그인을 한번만 해도 모든 페이지에서 로그인된 효과를 받을 수 있다.
- 이 웹사이트에는 게시판이 있고, 게시판은 HTML 태그가 허용되어 있다.
- 사이트 이용 도중 피해자는 해커가 올린 게시물을 보게 된다.
- 게시물에는 이미지가 있었고, 이미지는 다음과 같은 태그를 가지고 있다.
<img src="https://any-bank-site.com/sendMoney?to=hacker&amount=100000">
- 이는 사실 해커가 미리 알아낸 송금 URL이다.
hacker
에게100000
원을 보내게 만드는 행위를 하게 만드는 것이다. img
태그의src
에 있는 주소는 브라우저에 의해 해석될 때 자동으로GET
요청이 가게 된다.- 브라우저는 은행 인증에 필요한 인증정보를 저장하고 있었기 때문에 위의 요청은 정상적으로 수행된다.
- 피해자는 자신도 모르는 사이에 돈이 송금되어 버린다.
시나리오 2. POST 요청의 경우
피해자는 이번에도 브라우저를 통해 https://any-bank-site.com/ 웹사이트에 로그인한 상태이다.
브라우저에는 피해자가 로그인하면서 생성한 인증정보를 가지고 있다. ex)
JESSIONID=xxxx
은행 웹사이트에서 보안에 대한 고려를 하여,
GET
이 아닌POST
요청을 날렸을 때만 송금이 이루어지게 했다.은행 웹사이트에서는 송금을 위해 다음과 같은 폼을 제공한다.
<form method="post" action="/transfer"> <input type="text" name="amount"/> <input type="text" name="routingNumber"/> <input type="text" name="account"/> <input type="submit" value="Transfer"/> </form>
위의 폼을 제출하면 아래와 같은 HTTP 요청이 발생하여 송금이 되는 형태이다.
POST /transfer HTTP/1.1
Host: any-bank-site.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876
- 해커는 이 구조를 이해하고 자신이 작성한 게시글에 숨겨진 폼을 만들어놓는다.
<form method="post"
action="https://any-bank-site.com/transfer">
<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>
- 해커는 피해자가 댓글 작성 시에 저 폼이 함께 제출되도록 해놓은 상태이다.
- 만일 피해자가 해커의 게시글에서 댓글을 달게 되면, 의도치 않게 돈이 송금될 것이다.
CSRF 방지의 핵심
핵심은 공격자 도메인에서의 외부 요청과 서비스 웹사이트 상의 실제 요청을 구분하는 것이다. 이 두 요청을 구분할 수 없다면 CSRF 공격에 취약해질 수 있다.
스프링 시큐리티에서의 CSRF 방지 방법
스프링에서는 2가지 매커니즘으로 CSRF 공격을 막는다.
멱등성을 지켜야 한다
멱등성을 지킨다는 것은 GET
, HEAD
, OPTIONS
, TRACE
요청이 있을 때, 애플리케이션의 상태를 변화시키지 않는 것을 말한다. 이 요청을 몇번이고 수행해도 애플리케이션의 상태는 동일해야 한다. 그래야 이후에 설명할 Synchronizer Token Pattern
을 적용하는 효과가 있다.
Synchronizer Token Pattern 알아보기
Synchronizer Token Pattern 은 CSRF 방지를 위해 가장 많이 쓰이는 방법이다. 각 HTTP 요청이 세션 쿠키와 더불어 랜덤으로 생성된 CSRF 토큰을 포함하고 있는지 확인하는 방법이다.
요청이 왔을 때, 서버에서 CSRF 토큰을 확인하지 못하면, HTTP 요청이 거부된다.
다만 멱등성이 보장되어야 이 방법이 효과가 있다. 그래야 다른 곳에서 들어온 GET 요청을 수용할 수 있고, 우리가 GET 요청을 할 때는 CSRF 토큰이 필요 없으므로, CSRF 토큰의 유출도 막을 수 있다.
<form method="post"
action="/transfer">
<input type="hidden"
name="_csrf"
value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
<input type="text"
name="amount"/>
<input type="text"
name="routingNumber"/>
<input type="hidden"
name="account"/>
<input type="submit"
value="Transfer"/>
</form>
위와 같이 _csrf
라는 토큰 값을 함께 보내야 요청이 유효하다.
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2d9f86721
해커는 올바른 _csrf
값을 생성할 수 없을 것이다.
SameSite Attribute 알아보기
외부 사이트에서 들어오는 경우, 쿠키가 함께 보내지지 않을 것이라고 나타내는 SameSite
속성을 명시할 수 있다.
스프링 시큐리티의 경우엔 세션 쿠키의 생성을 직접 다루지 않기 때문에,
SameSite
속성을 지원하진 않는다. 그러나 Spring Session은 서블릿을 기반으로 한 애플리케이션에SameSite
속성을 지원한다. 스프링 프레임워크의 CookieWebSessionIdResolver 는 WebFlux 를 베이스로 한 애플리케이션에서SameSite
속성을 지원한다.
Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax
CSRF 보호를 비활성화(disable) 하는 경우?
When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.
일반 웹사이트처럼 브라우저 유저가 요청을 하는 것이 아니라, 브라우저가 아닌 애플리케이션의 클라이언트가 이용하는 경우에는 CSRF 를 비활성화 할 수 있다. 그러나 이 경우에도 CSRF 의 위협에서 무조건 안전하다고 할 수만은 없다. 만일 상태가 있는 어플리케이션인 경우에는 CSRF 공격을 받으면 브라우저에서 공격을 받는 것과 동일한 효과를 가지기 때문에 조심해야 한다.
레퍼런스
'보안' 카테고리의 다른 글
스프링 시큐리티에서 Authority 와 Role 의 차이는? (2) | 2023.12.05 |
---|---|
리프레시 토큰 (refresh token) 을 사용하는 이유를 알아보자 (0) | 2022.10.13 |
Method Security of 스프링 시큐리티 (0) | 2022.05.07 |
JWT(Json Web Token) 이란 무엇이며 왜 사용하는가? (0) | 2022.05.03 |
인증 (Authentication) 과 인가 (Authorization) 의 차이를 알아보자. (0) | 2022.05.02 |