지난 스터디에서
CORS 너는 누구인가
웹 개발을 하다보면 마주칠 수 밖에 없는 CORS 에러안겪어본 개발자는 없을거다.오늘은 CORS 에러가 뭐고 왜 등장하게 되었는지 그리고 해결방법까지 알아볼 예정이다. CORS란 무엇인가?CORS를 풀어
ytlive.tistory.com
CORS(Cross-Origin Resource Sharing)에 대해 설명하면서
CORS의 이전에 SOP(Same-Origin Policy) 가 존재하고 SOP는 CSRF(Cross-Site Request Forgery)나 XSS(Cross-Site Scripting) 등의 공격으로 인한 데이터 탈취를 예방할 수 있다고 이야기를 했다.
그런데 CSRF와 XSS에 대해 알아보니
정말 SOP(동일 출처 정책)이 CSRF와 XSS를 방어할 수 있는가? 에 대한 의문이 있어
CSRF와 XSS가 뭔지에 대해 자세히 알아보려고 한다.
CSRF와 XSS
자 우선 저번 스터디에서 공부했던
CSRF와 XSS의 개념에 대해 간단하게 다시 한번 확인해보자
CSRF (Cross-Site Request Forgery, 교차 사이트 요청 위조)
CSRF는 사용자가 자신의 의지와는 상관 없이
이미 로그인된 웹사이트에서 특정 동작을 실행하도록 만드는 보안 취약점이다.
공격자가 사용자의 브라우저가 특정 사이트에 대해 가진
인증 정보(쿠키)를 가로채서 로그인을 하거나 상호작용을 하는 것이다.
XSS (Cross-Site Scripting, 교차 사이트 스크립팅)
XSS는 공격자가 웹사이트에 악성 스크립트를 삽입하여,
해당 사이트에 방문하는 사용자의 브라우저에서 악성 스크립트가 실행되게 하는 공격이다.
CSRF는 사용자의 브라우저를 통해 서버를 공격하는 것이라면
XSS는 사용자의 브라우저에서 사용자를 공격하는 것이다.
라고 설명을 했었다.
글을 읽는 여러분도 그렇고 나도 그렇고
이렇게 글로 읽으면 얼추 알겠는데 그래서 그게 뭔데? 라고 생각할 것이다.사실.. 내가 그렇다.
그래서 예시를 들어서 하나씩 알아보겠다.
CSRF (Cross-Site Request Forgery, 교차 사이트 요청 위조)
CSRF는 이미 로그인된 웹사이트에서
특정 동작을 실행하도록 만드는 보안 취약점이라고 설명했다.
그래서 그거 어떻게 하는건데?
간단한 예시를 준비했다.
너가 만약 은행 사이트에 로그인 한 상태에서
다른 사이트를 구경하다가 마침 운이 나빠서 해커의 사이트(evil.com)에 들어가버렸다.

만약 은행의 URL이 https://bank.com 이고
송금을 요청하는 API가 /api/transfer 일 때

해커의 사이트에서 은행으로 송금을 요청하는 API를 요청한다.
이게 CSRF(Cross-Site Request Forgery)이다.
코드로 보면 이런 느낌이다.
<html>
<body>
<form action="https://bank.com/api/transfer" method="POST">
<input type="hidden" name="to" value="attackerAccount" />
<input type="hidden" name="amount" value="1000000" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
화면 진입 시 https://bank.com/api/transfer API를 호출하게 된다.
내가 CORS 정책을 설명하면서 이야기 했지만.
CORS 정책은 기본적으로 브라우저에 구현된 정책으로
서버가 응답을 한다고 해도 브라우저가 CORS 정책 위반이라고 판단하면 해당 응답은 사용하지 않는 것이다.
CORS 정책은 응답 데이터만을 보호하기 때문에
만약 응답을 바라는 API 호출이 아니라
API 호출 만으로 로직이 실행되는 경우에는 CSRF는 CORS 정책으로도 막을 수 없다.

때문에 별도로 CSRF(Cross-Site Request Forgery) 대책을 세워야한다.
CSRF(Cross-Site Request Forgery) 방어하기
CSRF를 방어하기 위해서는
서버에서 랜덤으로 생성하는 CSRF 토큰을 사용하고
- 서버가 랜덤 토큰 생성
- 사용자 세션과 함께 저장
- 요청할 때 토큰을 같이 보내게 함
- 서버에서 일치 여부 확인
SameSite 쿠키 설정한다.
Set-Cookie: SESSION=abc123; SameSite=Strict; Secure; HttpOnly
- Strict → cross-site 요청에 쿠키 안 붙음
- Lax → 일부 GET만 허용
- None → 반드시 Secure 필요
상태 변경은 반드시 POST/PUT/PATCH/DELETE 을 사용하도록 한다.
XSS (Cross-Site Scripting, 교차 사이트 스크립팅)
XSS는 사이트에 방문하는 사용자의 브라우저에서 악성 스크립트가 실행되게 하는 공격이다.
XSS는 공격자의 사이트가 아닌
공격 대상 사이트에 악성 스크립트를 심는 공격이다.
예를 들어 URL이 https://community.com이라는 커뮤니티가 있다고 하자
이 사이트의 비밀번호 변경 API가 /api/change-password일 때
XSS는 해당 커뮤니티에 아래와 같은 코드를 심은 글을 작성한다.
<script>
fetch("/api/change-password", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": document.querySelector("meta[name='csrf']").content
},
body: JSON.stringify({
newPassword: "1234"
})
});
</script>
이 경우 사용자가 해당 글에 진입하면 위 Script를 실행하게되고
위 script는 사이트의 비밀번호를 1234로 변경하게 된다.
XSS는 동일 출처에서 요청을 강제로 실행하는 것이기 때문에
CORS 정책으로도 막을 수 없다.
XSS(Cross-Site Scripting) 방어하기
XSS 공격을 방지하기 위해서는
사이트 내에서 사용자 입력이 스크립트로 해석되지 않도록 해야한다.
가장 많이 사용하는 방법으로는
출력 시 특수기호를 인코딩하도록 하면 된다.
<script>alert(1)</script>
위와 같은 코드는 출력 시 아래와 같은 형태로 인코딩 된다.
<script>alert(1)</script>
요즘 React, Vue 등 대부분 프레임워크는 자동으로 HTML escape가 적용된다.
정리하자면
SOP(동일 출처 정책)은 CSRF, XSS를 막지는 못한다.
하지만 SOP(동일 출처 정책) 는
외부 사이트가 내부의 데이터를 읽지 못하게 하는 최소한의 방어선이다.
인터넷의 특성상 사용자는 동시에 여러 사이트에 로그인 하고
브라우저는 각 사이트에 대한 쿠키를 자동으로 관리하고 있다.
이 상태에서 각 사이트의 데이터를
다른 사이트가 자유롭게 사용할 수 있다면 무법지대가 될 것이다.
그렇기 때문에 SOP가 없으면 보안도 뭐도 없게 된다.
이상 CSRF와 XSS는 뭐고
SOP와 CORS정책은 CSRF와 XSS를 막을 수 있는가? 에 대해서 공부해봤다.
참고 문서
CSRF, XSS 완전 정리
시작 하며...📌 참고 문헌한국산학기술학회 / A Method for Preventing CSRF Attacks in Web Application using Digital Signature TokenSK 쉴더스 / XSS란? 웹개발을 하다보면 자연스레 접하는 보안 관련 이슈들 중 CS
asn6878.tistory.com
CSRF 보호와 CORS를 둘다 사용하는 이유는 무엇인가요? | GeekNews
Cross-Site Request를 고민하다 보니 CSRF 보호와 CORS가 둘 다 필요하다는 것이 처음에는 이해되지 않았음. 하지만 이를 설명하려면 많은 단어가 필요함CSRF와 CORSCSRF (Cross-Site Request Forgery)과거에는 흔했
news.hada.io
XSS와 CSRF
안녕하세요. 휴먼스케이프의 개발자 김병하입니다.
medium.com
'전공공부' 카테고리의 다른 글
| CORS 너는 누구인가 (0) | 2026.02.07 |
|---|---|
| Nginx란 무엇인가? (1) | 2026.01.10 |
| React useContext (0) | 2025.11.09 |
| Spring boot에서 왜 Dto에 Setter를 금지하는가? (0) | 2025.10.25 |
| React-Query useQuery와 useMutation (0) | 2025.10.12 |