크로스 사이트 요청 위조(CSRF, Cross-Site Request Forgery)는 사용자가 인증된 세션을 유지하고 있는 동안 공격자가 악의적인 요청을 보내어 의도치 않은 행동을 수행하게 만드는 공격입니다. 예를 들어, 사용자가 은행 웹사이트에 로그인한 상태에서 악성 웹페이지를 방문하면 공격자가 피해자의 계좌에서 돈을 이체하도록 요청할 수도 있습니다.
CSRF 공격은 특히 상태 유지 방식(Stateful)의 웹 애플리케이션에서 치명적이며, 보안 조치가 취해지지 않으면 사용자 데이터가 위조 요청에 의해 조작될 수 있습니다.
이 글에서는 자바 11 환경에서 CSRF 공격을 방어하는 전략을 상세히 설명하며, 취약한 코드와 안전한 코드 예제를 비교하여 보안성을 높이는 방법을 소개합니다.
2. CSRF 공격의 원리
CSRF 공격은 사용자가 로그인 상태인 동안 악성 사이트에서 특정 요청을 자동으로 실행하도록 유도하는 방식으로 이루어집니다.
2.1. CSRF 공격 시나리오
- 사용자가 은행 웹사이트 **bank.com**에 로그인하여 인증된 세션을 유지하고 있음.
- 사용자가 공격자가 만든 **악성 웹사이트(공격 페이지)**를 방문.
- 공격 페이지가 피해자의 인증된 세션을 이용하여 공격자의 계좌로 송금하는 HTTP 요청을 자동으로 보냄.
- 은행 웹사이트는 요청이 인증된 사용자로부터 온 것으로 판단하고, 공격자의 계좌로 자금을 이체.
예제 공격 요청
<img src="https://bank.com/transfer?amount=100000&to=attacker_account">
- 사용자가 악성 웹페이지에 접속하는 순간, 위 요청이 자동 실행되어 피해자의 계좌에서 돈이 이체됨.
- 이는 사용자가 이미 로그인한 세션을 유지하고 있기 때문에 발생하는 문제임.
3. 취약한 코드 예제
다음은 CSRF 취약점이 있는 계좌 이체 기능입니다.
@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
String amount = request.getParameter("amount");
String toAccount = request.getParameter("to");
// CSRF 검증 없이 요청 처리 (취약점 발생)
processTransfer(amount, toAccount);
response.getWriter().println("송금 완료!");
}
}
✅ 문제점:
- 서버가 CSRF 검증 없이 요청을 처리함.
- 공격자가 피해자가 악성 페이지에 접속하도록 유도하면, 자동으로 송금 요청이 실행됨.
4. 안전한 코드 예제 (CSRF 방어 전략)
4.1. CSRF Token을 활용한 보호
CSRF 공격을 방어하기 위해 서버에서 CSRF 토큰을 생성하고, 요청 시 이 토큰을 검증하는 방식이 가장 효과적입니다.
(1) CSRF 토큰 생성 및 저장
@WebServlet("/getCSRFToken")
public class CSRFTokenServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String csrfToken = UUID.randomUUID().toString(); // 난수 기반 토큰 생성
request.getSession().setAttribute("csrfToken", csrfToken);
response.setContentType("text/plain");
response.getWriter().write(csrfToken);
}
}
(2) CSRF 토큰을 포함한 요청 (HTML)
<form action="/transfer" method="POST">
<input type="hidden" name="csrfToken" value="<%= session.getAttribute(\"csrfToken\") %>">
<input type="text" name="amount" placeholder="송금 금액">
<input type="text" name="to" placeholder="받는 계좌">
<button type="submit">송금하기</button>
</form>
(3) 서버에서 CSRF 토큰 검증
@WebServlet("/transfer")
public class SecureTransferServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
String sessionToken = (String) request.getSession().getAttribute("csrfToken");
String requestToken = request.getParameter("csrfToken");
if (sessionToken == null || !sessionToken.equals(requestToken)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF 공격 차단됨");
return;
}
String amount = request.getParameter("amount");
String toAccount = request.getParameter("to");
processTransfer(amount, toAccount);
response.getWriter().println("송금 완료!");
}
}
✅ CSRF 방어 효과:
- 토큰이 없거나 검증에 실패하면 요청 거부
- 서버에서 생성한 CSRF 토큰과 요청에 포함된 토큰을 비교하여 보호
5. 추가적인 CSRF 방어 전략
전략 | 설명 |
SameSite 쿠키 적용 | SameSite=Strict 옵션을 사용하여 외부 사이트에서의 요청 차단 |
Referer 및 Origin 검사 | 요청이 신뢰할 수 있는 출처에서 왔는지 확인 |
JWT 기반 인증 | 세션 기반 인증 대신 JWT(Json Web Token) 활용 |
Spring Security 사용 | CSRF 방어 기능이 기본 제공됨 |
5.1. SameSite 쿠키 적용
CSRF 공격을 방어하기 위해 쿠키에 SameSite=Strict 속성을 추가하면 외부 사이트에서의 요청을 차단할 수 있습니다.
Cookie sessionCookie = new Cookie("SESSIONID", sessionId);
sessionCookie.setHttpOnly(true);
sessionCookie.setSecure(true);
sessionCookie.setPath("/");
sessionCookie.setAttribute("SameSite", "Strict");
response.addCookie(sessionCookie);
✅ 방어 효과:
- 외부 사이트에서 세션 쿠키를 사용한 요청 차단
- CSRF 공격이 원천 차단됨
6. 결론
CSRF 공격은 사용자가 로그인된 상태에서 악성 웹사이트가 자동으로 요청을 실행하는 방식으로 발생합니다.
이를 방어하기 위해 CSRF 토큰을 활용한 검증, SameSite 쿠키 설정, 출처 검증, Spring Security 적용 등의 방법을 사용할 수 있습니다.
✅ 다음 포스팅 :
다음 글에서는 **HTTP 응답 헤더 보안 설정(Content Security Policy, HSTS, X-Frame-Options 등)**을 분석합니다.
'시큐어코딩 > JAVA' 카테고리의 다른 글
(시큐어코딩)Java에서 JWT 기반 인증 및 보안 강화를 위한 Best Practice (0) | 2025.04.02 |
---|---|
(시큐어코딩) Java에서 OWASP Top 10 기반의 보안 인증(Authentication) 강화 기법 (0) | 2025.03.20 |
(시큐어코딩) Java에서 HTTP 응답 헤더 보안 설정(Content Security Policy, HSTS, X-Frame-Options) (0) | 2025.03.20 |
(시큐어코딩)Java에서 크로스사이트 스크립트(XSS) 보안취약점 공격 방어 전략 (0) | 2025.03.17 |
(시큐어코딩)Java에서 SQL 삽입 취약점 공격 방어 전략 (0) | 2025.03.17 |