CSRF XSS 차이: 프론트엔드 보안 공격 구분법

··설명 약 11분·작성: 해비·블로그 소개

CSRF와 XSS는 공격 경계와 방어 방법이 어떻게 다른가요?

CSRF는 사용자의 인증 상태로 원치 않는 요청을 보내게 하는 문제이고, XSS는 신뢰하지 않은 입력이 스크립트로 실행되는 문제입니다. 공격이 시작되는 경계가 다르므로 방어도 구분하세요.

적용 조건·범위: 브라우저와 프록시 환경에 따라 Header 존재 여부와 정책을 고려해야 하므로 단독 방어책으로 단순화하지 않는 것이 좋습니다.

공식 문서 참고: OWASP: CSRF 토큰·SameSite·출처 검증 · OWASP: XSS 문맥별 인코딩과 안전한 DOM 출력

CSRF와 XSS 한 번에 구분하기

핵심만 먼저 비교하면 다음과 같습니다.

CSRF
→ 사용자의 인증 상태를 이용해
→ 사용자가 원하지 않은 요청을 보내게 함

XSS
→ 신뢰하지 않은 입력이
→ 브라우저에서 스크립트로 실행됨

둘 다 사용자 세션이나 데이터에 영향을 줄 수 있지만 출발점이 다릅니다.

CSRF는 요청 위조 문제에 가깝고 XSS는 코드 실행 문제에 가깝습니다.

CSRF는 어떤 문제인가

Cookie 기반 로그인에서는 브라우저가 조건이 맞으면 요청에 Cookie를 자동으로 포함할 수 있습니다.

이 자동 전송은 편리하지만 서버가 요청 출처와 의도를 충분히 검증하지 않으면 악용될 수 있습니다.

상태 변경 요청을 예로 보겠습니다.

POST /api/tasks/delete-all
Cookie: sessionId=abc123

서버가 Session Cookie만 보고 요청을 정상 사용자 요청으로 판단한다면 사용자가 원하지 않은 요청도 처리될 위험이 있습니다.

중요한 것은 공격 페이지의 코드를 배우는 것이 아니라 방어 관점에서 요청이 정말 사용자의 의도에서 시작되었는지 검증해야 한다는 점입니다.

CSRF 방어 원칙

SameSite Cookie

SameSite는 교차 사이트 상황에서 Cookie 전송 범위를 제어합니다.

SameSite=Lax
SameSite=Strict
SameSite=None

서비스 요구사항에 맞는 정책을 사용하면 CSRF 위험을 줄이는 데 도움이 됩니다.

하지만 SameSite 하나만으로 모든 상황을 해결한다고 생각하면 안 됩니다.

CSRF Token

서버가 예측하기 어려운 Token을 발급하고 상태 변경 요청에서 해당 Token을 함께 검증하는 방식입니다.

브라우저
→ 서버가 발급한 CSRF Token 포함
→ 서버에서 Session과 Token 검증
→ 정상 요청 처리

공격자가 사용자의 세션을 이용하더라도 올바른 Token까지 알지 못하도록 만드는 것이 목적입니다.

Origin 또는 Referer 검증

서버는 요청의 Origin이나 Referer를 확인해 허용된 사이트에서 시작한 요청인지 추가로 검증할 수 있습니다.

브라우저와 프록시 환경에 따라 Header 존재 여부와 정책을 고려해야 하므로 단독 방어책으로 단순화하지 않는 것이 좋습니다.

GET으로 상태 변경하지 않기

조회용 GET 요청이 데이터 삭제나 중요한 상태 변경을 수행하도록 설계하면 의도하지 않은 요청이 발생하기 쉬워집니다.

HTTP Method만으로 보안이 해결되는 것은 아니지만 상태 변경 API를 올바르게 설계하는 기본 원칙입니다.

XSS는 어떤 문제인가

XSS는 Cross-Site Scripting의 약자입니다.

웹 애플리케이션이 신뢰하지 않은 입력을 안전하게 처리하지 않고 HTML이나 JavaScript 실행 맥락에 넣을 때 발생할 수 있습니다.

프론트엔드에서 가장 직관적인 예는 다음 차이입니다.

const message = userInput;

element.textContent = message;

textContent는 값을 일반 텍스트로 다룹니다.

반대로 다음 코드는 입력을 HTML로 해석할 수 있습니다.

element.innerHTML = userInput;

userInput이 신뢰할 수 없는 값이라면 위험해질 수 있습니다.

따라서 사용자 입력을 화면에 출력할 때는 가능한 한 HTML 문자열 조립보다 안전한 DOM API와 프레임워크의 기본 이스케이프 기능을 사용하는 것이 좋습니다.

XSS 유형 기본 구분

Stored XSS

위험한 입력이 서버나 저장소에 저장된 뒤 다른 사용자가 페이지를 열 때 실행되는 형태입니다.

입력 저장
→ 다른 사용자 조회
→ 페이지에 위험한 값 출력
→ 실행

Reflected XSS

URL 파라미터나 요청 값이 응답에 즉시 반영되면서 실행되는 형태입니다.

DOM 기반 XSS

서버 응답 자체보다 브라우저 JavaScript가 URL이나 외부 입력을 읽어 위험한 DOM 조작을 수행하면서 발생하는 형태입니다.

세 유형의 상세 공격 방법을 외우기보다 신뢰하지 않은 값이 코드 실행 맥락에 들어가는 지점을 찾는 것이 중요합니다.

XSS 방어 원칙

출력 맥락에 맞게 이스케이프하기

HTML·속성·URL·JavaScript 문자열은 각각 해석 규칙이 다릅니다.

가능하면 직접 문자열로 HTML을 조합하지 않고 프레임워크가 제공하는 안전한 렌더링 방식을 사용합니다.

위험한 HTML 주입 최소화

React의 dangerouslySetInnerHTML 같은 API나 직접 innerHTML을 사용할 때는 입력의 출처와 sanitization 여부를 명확히 확인해야 합니다.

단순히 이름에 dangerous가 붙었다는 이유보다 실제로 HTML 문자열을 실행 가능한 문맥에 넣는다는 점이 핵심입니다.

HttpOnly Cookie

HttpOnly Cookie는 JavaScript에서 Cookie 값을 직접 읽지 못하게 제한합니다.

XSS가 발생했을 때 Session Cookie 탈취 위험을 줄이는 데 도움이 될 수 있습니다.

하지만 XSS 자체를 막지는 못합니다.

악성 스크립트가 현재 페이지 권한으로 요청을 보내거나 화면을 조작할 수 있기 때문입니다.

CSP

Content Security Policy는 허용할 스크립트 출처와 실행 방식을 제한하는 보조 방어 수단입니다.

적절한 CSP는 XSS 영향을 줄이는 데 도움이 되지만 안전하지 않은 DOM 조작을 그대로 두고 CSP만 적용하는 방식으로 해결하면 안 됩니다.

Cookie와 Token 저장 위치 생각하기

3회차에서 Token을 어디에 저장할지는 구조에 따라 달라진다고 설명했습니다.

XSS와 연결하면 이유가 보입니다.

JavaScript가 읽을 수 있는 저장소
→ XSS 발생 시 값 접근 가능성 고려

HttpOnly Cookie
→ JavaScript 직접 읽기 제한
→ 대신 Cookie 자동 전송과 CSRF 관점도 함께 고려

즉 보안 설계는 하나의 위험만 보는 것이 아니라 여러 위협을 함께 봐야 합니다.

XSS
CSRF
Token 탈취
Session 고정
권한 검증

한 가지 저장 방식만 외워 모든 프로젝트에 적용하는 것은 좋지 않습니다.

CORS와의 관계

CORS가 CSRF와 XSS를 모두 막아준다고 생각하는 경우가 많습니다.

그렇지 않습니다.

CORS와 CSRF

CORS는 주로 브라우저 JavaScript가 교차 출처 응답을 읽는 것을 제어합니다.

CSRF에서는 응답을 읽지 않아도 서버에 상태 변경 요청이 도달하면 문제가 될 수 있습니다.

따라서 CORS만으로 CSRF 방어를 대신할 수 없습니다.

CORS와 XSS

XSS는 이미 신뢰받는 페이지 안에서 스크립트가 실행되는 문제입니다.

같은 origin 안에서 실행되는 악성 스크립트라면 CORS와 별개로 페이지 권한을 사용할 수 있습니다.

안전한 프론트엔드 예제

문자열을 안전하게 표시하기

strong 태그 문자열이 굵은 HTML 대신 문자 그대로 보이는지 확인하세요.

예제 크게 보기 (새 탭)

사용자 입력을 단순 텍스트로 표시해야 한다면 다음과 같은 접근이 안전합니다.

<p id="message"></p>
const message = document.querySelector('#message');
const userInput = '<strong>공부하기</strong>';

message.textContent = userInput;

화면에는 HTML 태그가 실행되지 않고 문자 그대로 표시됩니다.

HTML 렌더링이 정말 필요한 기능이라면 신뢰할 수 있는 sanitization 정책을 별도로 설계해야 합니다.

직접 실행: 입력을 코드 대신 문자로 표시하기

빈 폴더에서 아래 두 파일을 같은 위치에 저장하고 index.html을 브라우저로 엽니다. 서버·로그인·TaskFlow 설치는 필요하지 않습니다. script의 defer는 message 요소가 준비된 뒤 실행하기 위한 것입니다.

index.html 전체 파일

<!doctype html>
<html lang="ko">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>텍스트 출력 확인</title><script src="app.js" defer></script></head>
<body><p id="message"></p></body>
</html>

app.js 전체 파일

const message = document.querySelector('#message');
const userInput = '<strong>공부하기</strong>';
message.textContent = userInput;

예상 결과는 <strong>공부하기</strong>라는 문자 전체입니다. 개발자 도구 Elements에서도 message 안에 strong 요소가 생성되지 않아야 합니다. userInput을 <em>연습</em>으로 바꾸면 역시 태그 문자 그대로 보입니다. 이는 일반 텍스트 출력만 검증하며 HTML sanitization·URL 안전성·서비스 전체 XSS 방어를 검증하지 않습니다.

자주 하는 오해

CORS를 설정하면 CSRF가 해결됩니다

아닙니다.

CORS와 CSRF는 문제 영역이 다릅니다.

HttpOnly를 쓰면 XSS가 없어집니다

아닙니다.

Cookie 값을 직접 읽는 위험을 줄일 수 있지만 페이지에서 악성 스크립트가 실행되는 문제 자체는 남아 있습니다.

React를 쓰면 XSS는 절대 발생하지 않습니다

아닙니다.

React가 일반 문자열 렌더링에서 기본 이스케이프를 제공하는 것은 도움이 되지만 HTML 직접 삽입, 위험한 URL, 외부 라이브러리 사용 등 다른 경로에서 문제가 생길 수 있습니다.

SameSite만 설정하면 CSRF가 완전히 해결됩니다

서비스 구조와 브라우저 정책을 함께 봐야 합니다.

상태 변경 요청 검증과 Token·Origin 검증 등 다른 방어와 조합하는 것이 일반적입니다.

독자 질문과 실전 확인

독자 질문

사용자의 의사와 무관한 요청 전송과 페이지에서 악성 스크립트 실행은 왜 다른 문제일까요?

웹 개발 사례

TaskFlow의 계정 설정 변경 요청이 사용자의 의사와 무관하게 인증된 브라우저에서 전송되는 상황은 CSRF 관점으로, 사용자 입력을 HTML로 삽입해 코드가 실행되는 상황은 XSS 관점으로 검토합니다.

직접 확인할 문제

두 상황에 각각 CSRF·XSS를 붙이고, 첫 상황에는 서버의 CSRF 토큰·Origin 검증·SameSite를, 둘째 상황에는 안전한 텍스트 렌더링과 출력 맥락에 맞는 이스케이프를 연결해 보세요.

예상 결과와 판단

인증 상태를 이용한 의도치 않은 상태 변경은 CSRF, 신뢰할 수 없는 입력의 코드 실행은 XSS입니다. SameSite 하나로 모든 CSRF를 막았다고 결론낼 수 없고, HttpOnly는 JavaScript의 쿠키 읽기를 제한하지만 XSS 자체를 제거하지 않습니다.

검증 범위

이는 방어 개념을 구분하는 가상 사례입니다. 실제 취약점 재현, 침투 테스트, 서비스 보안 완전성은 검증하지 않았습니다.

다음 학습: 5회차에서는 응답이 오래된 화면으로 보일 때 HTTP 캐시 헤더와 재검증을 확인합니다.

학습 완료 체크리스트

  • CSRF와 XSS의 출발점을 구분할 수 있습니다.
  • Cookie 자동 전송이 CSRF와 연결되는 이유를 설명할 수 있습니다.
  • SameSite·CSRF Token·Origin 검증의 역할을 구분할 수 있습니다.
  • textContent와 innerHTML의 차이를 설명할 수 있습니다.
  • HttpOnly와 CSP가 보조 방어라는 점을 이해했습니다.
  • CORS가 CSRF·XSS 전체를 해결하지 않는다는 것을 설명할 수 있습니다.

선택 실습: 같은 프로젝트로 연습하기

이 선택 실습은 TaskFlow의 요청 흐름을 설명하는 분석 노트를 만드는 연습입니다. 실행 앱을 새로 만드는 과정은 아닙니다.

요청과 화면 렌더링에서 신뢰 경계를 표시합니다.

TaskFlow 요청 흐름 분석 노트

이전 체크포인트

cs-step-03-auth-cors

현재 상태

TaskFlow 요청 흐름에는 인증과 출처 정보까지 표시되어 있습니다.

HTTP 요청
├─ Cookie
├─ Authorization
└─ Origin
↓
서버 인증·권한
↓
CORS 검사

이번 목표

요청과 화면 렌더링에서 신뢰 경계를 표시합니다.

상태 변경 요청
→ 사용자의 의도 검증 필요
→ CSRF 방어

사용자 입력
→ DOM 출력
→ 실행 가능한 문맥 여부 확인
→ XSS 방어

TaskFlow 점검 시나리오

TaskFlow에 작업 제목 입력 기능과 완료·삭제 API가 있다고 가정합니다.

다음 두 경로를 따로 봅니다.

1. 작업 삭제 요청
브라우저 인증 상태
→ 서버 상태 변경
→ CSRF 관점 확인

2. 작업 제목 출력
사용자 입력
→ 저장
→ DOM 렌더링
→ XSS 관점 확인

Before

보안 문제
→ 막연히 CORS나 Token 문제로만 판단

After

요청 위조 문제
→ CSRF 관점

스크립트 실행 문제
→ XSS 관점

출처 응답 접근 문제
→ CORS 관점

현재 확장 단계

✓ 1. 브라우저·HTTP 요청/응답
✓ 2. DNS·TCP·TLS
✓ 3. 쿠키·세션·토큰·CORS
→ 4. CSRF·XSS
○ 5. HTTP 캐시
○ 6. 프로세스·스레드·메모리
○ 7. 통합 장애 진단

완료 체크포인트

cs-step-04-web-security

다음 학습

정상적인 요청이라도 브라우저가 이전 응답을 재사용하면 서버에서 새 데이터를 받지 않을 수 있습니다.

다음 글에서는 Cache-Control·ETag·304를 중심으로 HTTP 캐시가 어떻게 동작하는지 학습합니다.

다음 글: HTTP 캐시 기초: Cache-Control·ETag·304로 브라우저 캐시 읽기

글 소개·학습 준비·전체 목차
CSRF와 XSS의 보안 경계를 표현한 편지·브라우저와 방패

CS 기초 · 4 / 7 · 필수 학습 · CSRF와 XSS

CSRF와 XSS는 둘 다 웹 보안에서 자주 등장하지만 공격이 성립하는 이유와 방어 지점이 다릅니다.

CSRF는 사용자의 인증 상태를 이용해 원치 않는 요청을 보내게 만드는 문제이고, XSS는 신뢰하지 않은 입력이 브라우저에서 스크립트로 실행되도록 만드는 문제입니다.

이번 글에서는 공격 기법 자체보다 어떤 신뢰 경계가 깨지는지와 프론트엔드에서 어떤 방어 원칙을 적용해야 하는지에 집중합니다.

이번 글에서 배우는 내용

  • CSRF와 XSS의 차이
  • Cookie 자동 전송과 CSRF 위험의 관계
  • SameSite·CSRF Token·Origin 검증의 역할
  • Stored·Reflected·DOM 기반 XSS의 기본 개념
  • textContent와 innerHTML 차이
  • HttpOnly와 CSP의 역할 범위
  • CORS가 CSRF·XSS를 해결하지 못하는 이유

선수 지식

  • Cookie·Session·Token
  • Same-Origin Policy와 CORS
  • HTTP 요청과 응답
  • 브라우저에서 JavaScript가 실행된다는 기본 개념

목차

  1. CSRF와 XSS 한 번에 구분하기
  2. CSRF는 어떤 문제인가
  3. CSRF 방어 원칙
  4. XSS는 어떤 문제인가
  5. XSS 유형 기본 구분
  6. XSS 방어 원칙
  7. Cookie와 Token 저장 위치 생각하기
  8. CORS와의 관계
  9. 안전한 프론트엔드 예제
  10. 자주 하는 오해
  11. 독자 질문과 실전 확인
  12. 학습 완료 체크리스트
  13. TaskFlow 요청 흐름 분석 노트
  14. 현재 확장 단계
  15. 다음 학습

이 글이 도움이 되었나요?

조회 중

읽음 기록

읽음 — / 전체 7개 · 필수 7개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기