CSRF/XSRF(Cross-Site Request Forgery)란
사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격이다.
메인 그림 시나리오
1. 김노력이 은행 홈페이지에 로그인을 한다.
2. 은행 홈페이지는 김노력의 계정 정보를 검증하고 토큰을 발급한다.
3. 해커는 합법적인 통신을 가장한 위조 요청을 보낸다.
4. 김노력은 은행에 해커의 요청을 보낸다.(하지만 김노력은 알지 못하지,,)
5. 김노력의 브라우저에 있는 토큰 정보를 받은 은행은 위조 요청을 실행한다.
전제 조건
1. 사용자가 보안이 취약한 서버로부터 이미 인증을 받은 상태여야 한다.
2. 쿠키 기반으로 서버 세션 정보를 획득할 수 있어야 한다.
3. 공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있어야 한다.
대응 방안
1. Referrer 검증
Referer 요청 헤더는 현재 요청을 보낸 페이지의 절대 혹은 부분 주소를 포함하며 사용자들이 어디로 와서 방문 중인지를 인식할 수 있도록 해준다. 그러므로 서버에서 사용자의 요청 헤더 정보에서 Referer 정보를 확인하고 host 정보와 비교한다. CSRF 공격의 대부분이 Referer값에 대한 검증만으로 방어가 가능하다.
ReferrerCheckInterceptor 클래스 - Referer 검증 방어 코드
package test;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RefererCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest requser,
HttpServletResponse response, Object handler) throws Exception {
String referer = request.getHeader("Referer);
String host = request.getHeader("host");
if (referer == null || !referer.contains(host)) {
response.sendRedirect("/");
return false;
}
return true;
}
}
2. Security Token 사용 (CSRF Token)
임의의 CSRF 토큰을 만들어 세션에 저장한다. 요청하는 페이지에 hidden 타입 input 태크를 이용해 토큰 값을 함께 전달한다. 이후 서버에서 세션에 저장된 CSRF 토큰 값과 요청 파라미터에 담긴 토큰 값을 비교한다.
세션 및 hidden input 값으로 CSRF 토큰 설정하기
// 세션에 설정
session.setAttribute("CSRF_TOKEN", UUID.randomUUID().toString());
// 페이지 내 hidden값으로 설정
model.addAttribute("CSRF_TOKEN", session.getAttribute("CSRF_TOKEN"));
<!-- jsp -->
<form action="..." method="POST">
<input type="hidden" name="_csrf" value="${CSRF_TOKEN}" />
<!-- ... -->
</form>
CsrfTokenInterceptor 클래스 - CSRF 토큰 방어 코드
package test;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class CsrfTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession(false);
String csrfTokenParam = request.getParameter("_csrf");
String csrfTokenSession = (String) session.getAttribute("CSRF_TOKEN");
if (csrfTokenParam == null || !csrfTokenParam.equals(csrfTokenSession)) {
response.sendRedirect("/");
return false;
}
return true;
}
}
3. Double Submit Cookie 검증
웹 브라우저의 Same Origin 정책으로 인해 자바스크립트에서 타 도메인의 쿠키 값을 확인/수정하지 못한다는 것을 이용한 방어 기법이다. 자바스크립트로 임의로 생성한 토큰을 쿠키에 저장하고 동일한 난수 값을 요청 파라미터(혹은 헤더)에도 저장하여 서버로 전송한다. 서버 단에서는 토큰 값과 파라미터의 토큰 값을 비교하여 일치하는지 검사한다. 이때, 쿠키에 저장된 토큰 정보는 만료 처리한다.
4. 추가 인증 수단 사용 (예. CAPCHA)
XSS 공격과의 차이점
XSS 공격은 사용자가 웹 사이트를 신용해서 악성 스크립트가 실행된다면, CSRF 공격은 반대로 특정 웹 사이트가 사용자의 브라우저를 신용하여 발생하는 공격이다. 즉, XSS 공격은 악성 코드가 클라이언트에서 발생하고 CSRF 공격은 서버에서 발생한다.
참고
- CSRF(Cross-Site Request Forgery) 공격
- Referer
'Web' 카테고리의 다른 글
[Gradle] build.gradle를 톺아보자 (0) | 2023.02.04 |
---|---|
[IntelliJ] war과 war(exploded)의 차이 (0) | 2022.09.28 |
XSS(Cross-Site Scripting)의 공격 방법과 대응 방안 (2) | 2022.09.02 |
SQL Injection의 공격 방법과 대응 방안 (1) | 2022.09.02 |
LinkedIn SNS 연동 (0) | 2021.12.15 |