2022. 11. 4. 15:00ㆍ학습일지
스프링 시큐리티는 인증, 인가뿐만 아리나, 주요 취약점 공격을 보호해주는 기능을 제공한다. 대체로 기본으로 활성화되어있는데, 이 요약글에서는 해당 내용에 대한 부분을 다뤄보고자 한다.
1. CSRF(Cross Site Request Forgery)
CSRF 공격이란?
다른 웹 사이트에서 인증하고 보관 중인 쿠키를, 악의적으로 조작된 웹 사이트의 폼 전송을 통해, 기존에 저장한 쿠키를 탈취하여, 개인 정보를 훔치고 악의적인 목적으로 활용하는 것을 말한다.
기본적으로 쿠키를 요청한 클라이언트의 브라우저에 저장하기에, 다른 컴퓨터로 조회하는 것은 불가능 하지만, 클라이언트를 속여서 가지고 있는 쿠키를 다른 사이트에 전송하는 방식을 통해 충분히 탈취당할 수 있다.
따라서, CSRF의 피해자는 또한, XSS 공격의 표적이 될 수도 있다.
CSRF 공격을 방어하는 방법
CSRF의 취약점은 공격받는 웹사이트의 http 요청과 공격하는 웹사이트의 http 요청이 동일하기 때문에 발생한다. 따라서 일반적으로는 해당 취약점을 방어할 뾰족한 방법이 없는데, 스프링은 취약점을 방어하기 위해 다음과 같은 두 가지 메커니즘을 제공한다.
- 동기화 토큰 패턴(Synchronizer Token Pattern)
- 세션 쿠키의 SameSite 속성
Synchronizer Token Pattern
- CSRF 공격을 방어하는 방법 중 가장 포괄적이고 유력한 방법이다.
- 이 패턴을 적용하면, HTTP 요청에 세션 쿠키와는 별도로 CSRF 토큰이라 불리는, 랜덤으로 생성한 값을 추가한다.
- 이 패턴의 핵심은 해당 토큰을 자동으로 넣어주지 않는 것에 있다. 따라서 만약 CSRF 토큰을 쿠키와 같이 브라우저에서 자동으로 입력하는 값으로 받으면, 보안 효과가 없다.
Synchronizer Token Pattern example
CSRF 토큰이 적용될 경우, 기존 폼 전송에 다음과 _csrf와 같은 input 태그가 생긴다.
<form method="post" action ="/transfer">
...
<input type="hidden"
name="_csrf"
value="asdfjkg....."/>
...
</form>
'same origin policy' 로 인해 외부 사이트는 응답을 볼 수 없기 때문에 CSRF 역시 읽어갈 수 없다. 해당 폼 전송을 처리하는 HTTP 요청은 다음과 같다:
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=9877&_csrf=4bfd1575-3ad1-4d21-96c7-ref2d9f86721
SameSite Attribute
또 다른 CSRF 공격 방법으로 SameSite 속성을 지정하는 것이다. 서버에서 쿠키에 SameSite 속성을 명시하는 것으로 외부 사이트가 보내는 요청엔 쿠키를 사용하지 않겠다고 지정할 수 있다.
스프링 시큐리티는 세션 쿠키 생성을 직접 제어하지 않는다. Spring-Session이 SameSite 속성을 지원한다. 웹 플럭스 기반 어플리케이션 전용 SameSite 속성은 스프링 프레임워크의 CookieSessionIdResolver가 지원한다.
예를 들어 SameSite 속성을 사용한 HTTP 응답 헤더는 다음과 같다.
Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax
SameSite 속성
- strict : 지정하면 동일 사이트가 보내는 모든 요청에 쿠키를 포함시킨다.
- Lax : 지정하면 동일 사이트, 혹은 다른 사이트라도 top-level navigation에서 보낸 요청이면서 멱등성을 보장하는 메서드(GET,GET, HEAD, OPTIONS, TRACETRACE) 면 쿠키를 포함시킨다.
주의사항 1. 속성의 부작용
SameSite 속성이 Strict로 지정하면 더 안전하긴 하지만, 사용자를 혼란스럽게 할 수 있다.
만약 https://social.example.com 에서 호스팅 하는 SNS에 처음 로그인한 상태인 사용자가 추가 인증을 받기 위해, https://email.example.orghttps://email.example.org에서 SNS 사이트로 가는 가는 링크를 받았다고 생각해보자.
분명 사용자는 정당한 방식으로 인증을 시도하고 있지만, strict 속성상 쿠키를 전송하지 않기 때문에 인증을 못하게 되는 상황이 생긴다.
주의사항 2. 브라우저의 SameSite 속성 지원 여부 확인하기
또 하나 반드시 주의해야 할 점은 SameSite 속성으로 보호하늘 경우 반드시 브라우저도 SameSite 속성을 지원해야 한다. 최신 브라우저는 대부분 이 속성을 지원하지만, 옛날 브라우저 중에는 지원하지 않는 브라우저도 있다.
CSRF은 언제 사용하면 좋을까?
- CSRF는 일반 사용자가 브라우저에서 처리할 수 있는 모든 요청이라면 CSRF 방어를 권장한다.
- 그러나, 서비스가 브라우저가 아닌 다른 클라이언트에서만 사용된다면, 비활성화해도 무방하다.
CSRF 방어와 JSON
- 가장 흔한 의문은 "JS에서 만드는 JSON 에도 CSRF 방어가 필요할까?"라는 의문이다.
- 상황에 따라 다르지만, JSON 요청을 이용한 CSRF 취약점 공격도 있다는 점에 주의해야 한다.
JSON 폼 요청을 통한 CSRF 공격 사례
<form action="https://bank.example.com/transfer" method="post" enctype="text/plain">
<input name='{"amount" : 100, "evil" : "evil_code"}' type='hidden'/>
<input type="submit" value="Give you money to evil!"/>
</form>
{
"amount" : 100,
"evil" : "evil_code"
}
- 만약 애플리케이션에서 Content-Type을 검증하지 않았다면 바로 취약점 공격에 노출된다.
- 또한, 검증하더라도, url 끝에 .json이 있다면, 여전히 취약할 수 있다.
CSRF와 Stateless Browser Applications
상태가 없는 애플리케이션은 어떨까? 사실 사용자가 웹 브라우저 요청으로 수행하는 작업이 없다고 해도 CSRF 공격에 노출돼 있는 것은 동일하다.
예를 들어, 인증을 위한 모든 상태를 JSESSIONID 대신 커스텀 쿠키에 저장하는 애플리케이션을 생각해보자. 이 애플리케이션이 CSRF 공격을 받는다면, JSESSIONID 쿠키가 전송된 경우와 동일하게 커스텀 쿠키도 요청에 포함될 텐데, 이 경우 애플리케이션은 CSRF 공격에 취약하다.
Basic authentication을 사용하는 애플리케이션도 동일하게 CSRF 공격에 노출돼 있다. 사용자 이름과 비밀번호를 모든 요청에 추가하기 때문이다.
즉, CSRF 취약점은 민감정보 및 세션을 식별할 수 있는 정보를 브라우저에서 바로 확인할 수 있는 형태로 입력할 경우 발생할 수 있을 듯하다.
'학습일지' 카테고리의 다른 글
놀랍고 놀라운 Spring Framework 6 근데, 과연 사용할 날이 올까? (0) | 2023.01.09 |
---|---|
03. Spring security Features 요약 : Security Http Response Headers (0) | 2022.11.04 |
01. Spring security Features 요약 : Password Storage (0) | 2022.11.04 |
상속은 결합을 늘린다..? (0) | 2022.08.27 |
RabbitMQ - @RabbitListener를 사용할 때 주의할 점 (0) | 2022.07.17 |