CSRF와 XSS 완벽 정리 – 프론트엔드 보안 흐름과 방어 전략

주요 포인트 한눈에 보기

CSRF와 XSS를 단순 정의가 아닌 공격 흐름과 책임 위치를 기준으로 정리합니다.
CSRF는 인증된 사용자의 요청을 악용하는 공격이고,
XSS는 브라우저에서 악성 스크립트가 실행되는 공격이라는 차이를 중심으로 설명합니다.
실제 공격 예시 코드와 함께, 프론트엔드에서 토큰 처리·쿠키 설정·출력 방식을 어떻게 구현해야 하는지까지 다루어
공부용·면접 대비·실무 참고용으로 한눈에 정리할 수 있도록 구성했습니다.

sub02

CSRF란 무엇인가

CSRF는 Cross-Site Request Forgery의 약자로,
사용자가 의도하지 않았음에도 불구하고 이미 인증된 상태를 이용해
서버로 특정 요청을 보내게 만드는 공격입니다.
이 공격의 핵심은 인증 정보가 탈취되지 않았다는 점입니다.

공격자는 아이디나 비밀번호를 훔치지 않습니다.
대신 사용자가 로그인한 상태로 다른 사이트를 방문하도록 유도한 뒤,
그 사이트에서 자동으로 요청이 전송되도록 설계합니다.
서버는 쿠키나 세션이 함께 전달된 요청을 정상 요청으로 판단하게 됩니다.

1. 사용자가 은행 사이트에 로그인
2. 로그인 상태 유지 (쿠키 저장)
3. 공격자가 만든 사이트 접속
4. 자동으로 송금 요청 전송
5. 서버는 정상 사용자 요청으로 처리

예를 들어, 사용자가 은행 사이트에 로그인한 상태에서
공격자가 만든 게시글이나 이메일 속 링크를 클릭하면
본인도 모르는 사이에 송금이나 정보 변경 요청이 전송될 수 있습니다.

<form action="https://bank.example.com/transfer" method="POST">
  <input type="hidden" name="to" value="attacker" />
  <input type="hidden" name="amount" value="100000" />
</form>
<script>document.forms[0].submit();</script>

이 코드에는 해킹처럼 보이는 요소가 없지만,
사용자의 인증 쿠키가 함께 전송되면서 공격이 성립됩니다.
따라서 CSRF는 요청에 사용자의 의도가 담겨 있는지를 검증하는 구조가 필요합니다.

사용자 로그인 상태 유지
→ 공격자가 만든 페이지 접속
→ 숨겨진 요청 자동 전송
→ 서버는 정상 요청으로 처리

서버 입장에서는 요청이 정상적인 사용자로부터 온 것처럼 보이기 때문에
별도의 검증 장치가 없다면 공격을 구분할 수 없습니다.

XSS란 무엇인가

XSS는 Cross-Site Scripting의 약자로,
웹 페이지에 삽입된 악성 스크립트가
사용자의 브라우저에서 그대로 실행되는 공격입니다.
CSRF와 달리 실제 자바스크립트 코드가 실행된다는 점이 핵심입니다.

XSS는 보통 입력값을 제대로 처리하지 못했을 때 발생합니다.
사용자가 입력한 문자열이 검증이나 이스케이프 없이
HTML로 그대로 출력되면 공격자가 코드를 주입할 수 있습니다.

<!-- 취약한 코드 예시 -->
<div>사용자 입력: <span id="output"></span></div>
<script>
  const userInput = "<script>alert('XSS')</script>";
  document.getElementById('output').innerHTML = userInput;
</script>

위 코드에서는 사용자 입력값이 그대로 innerHTML에 삽입되면서
브라우저에서 실제 스크립트가 실행됩니다.
이로 인해 쿠키 탈취, 화면 변조, 피싱 페이지 삽입 등이 가능합니다.

// 상대적으로 안전한 출력 방식
const userInput = "<script>alert('XSS')</script>";
output.textContent = userInput;

이처럼 XSS 방어의 핵심은
입력값을 통제하는 것이 아니라
출력 시점에 브라우저가 코드를 해석하지 못하도록 막는 것입니다.

<script>
alert('XSS 공격');
</script>

이 스크립트는 게시글, 댓글, 검색어 같은 입력값을 통해 저장되거나
특정 URL을 통해 반사되어 실행될 수 있습니다.

구분 실행 위치
CSRF 서버 요청
XSS 브라우저

CSRF와 XSS 비교 정리

CSRF와 XSS를 가장 쉽게 구분하는 방법은
공격자가 무엇을 직접 조작하는지를 기준으로 생각하는 것입니다.
두 공격 모두 결과적으로는 사용자가 피해를 보지만,
공격이 시작되는 지점과 과정은 완전히 다릅니다.

CSRF는 사용자의 브라우저나 화면을 직접 건드리지 않습니다.
대신 사용자가 이미 로그인되어 있다는 사실을 이용해,
사용자의 의도와 무관한 요청을 서버로 보내게 만드는 공격입니다.
이때 서버는 쿠키나 세션을 통해 인증만 확인하기 때문에
요청이 정상인지 공격인지 구분하지 못합니다.

반면 XSS는 서버로 보내는 요청 자체보다,
서버가 사용자에게 다시 돌려주는 화면을 노립니다.
입력값에 포함된 악성 스크립트가 HTML로 그대로 출력되면서
사용자의 브라우저에서 실제 자바스크립트 코드가 실행됩니다.

정리하면 CSRF는 “누가 이 요청을 보냈는가”의 문제이고,
XSS는 “이 화면에서 어떤 코드가 실행되는가”의 문제입니다.
이 기준을 잡고 나면 두 공격은 헷갈릴 여지가 거의 없어집니다.

프론트엔드 방어 전략

CSRF와 XSS는 모두 프론트엔드와 무관한 서버 보안 문제처럼 오해되기 쉽지만,
실제로는 프론트엔드 코드의 작성 방식에 따라 공격이 성립하거나 차단됩니다.
따라서 프론트엔드 개발자는 단순 구현자가 아니라
보안 흐름의 첫 관문이라는 인식을 가져야 합니다.

먼저 CSRF 방어 전략입니다.
프론트엔드의 핵심 역할은 서버가 발급한 CSRF 토큰을
모든 상태 변경 요청에 빠짐없이 포함시키는 것입니다.

<form method="POST" action="/profile/update">
  <input type="hidden" name="csrfToken" value="{{CSRF_TOKEN}}" />
  <input type="text" name="nickname" />
  <button type="submit">저장</button>
</form>

이처럼 form 기반 요청에서는 hidden input으로 토큰을 포함시키며,
서버에서 내려준 값을 그대로 사용해야 합니다.

// fetch 요청에서 CSRF 토큰 포함
fetch('/profile/update', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({ nickname: 'haebi' })
});

쿠키 설정 또한 중요한 방어 요소입니다.
SameSite 옵션은 다른 출처에서 발생한 요청에
쿠키가 자동 포함되는 것을 제한하여 CSRF를 완화합니다.

Set-Cookie: sessionId=abc123;
SameSite=Strict; Secure; HttpOnly

다음은 XSS 방어 전략입니다.
XSS 방어의 핵심은 입력값을 제한하는 것이 아니라
출력 시점에 브라우저가 코드를 해석하지 못하게 하는 것입니다.

// ❌ 위험한 방식
output.innerHTML = userInput;

// ✅ 안전한 방식
output.textContent = userInput;

문자열을 HTML로 해석하는 API는
사용자 입력이 섞이는 순간 공격 지점이 됩니다.
특히 React의 dangerouslySetInnerHTML은
반드시 신뢰 가능한 데이터에만 사용해야 합니다.

// React에서 위험한 사용 예
<div dangerouslySetInnerHTML={{ __html: userInput }} />

결국 프론트엔드 방어 전략의 핵심은
데이터가 어디서 생성되고,
어떤 경로를 거쳐,
어떤 방식으로 화면에 출력되는지를
코드 단위에서 추적하는 것입니다.
이 흐름이 보이면 CSRF와 XSS는 훨씬 명확해집니다.

면접에서 이렇게 설명하면 좋습니다

면접에서는 정의를 길게 나열하기보다,
기준을 먼저 제시한 뒤 한 문장으로 정리하는 방식이 효과적입니다.
CSRF와 XSS의 차이를 설명할 때도 동일합니다.

요청을 속여 보내는 공격인지,
브라우저에서 코드가 실행되는 공격인지를 기준으로 설명하면
면접관이 듣기에 명확하고 구조적으로 전달됩니다.

CSRF는 인증된 사용자의 권한을 악용해 의도하지 않은 요청을 서버로 보내는 공격이고,
XSS는 웹 페이지에 삽입된 스크립트가 사용자 브라우저에서 실행되는 공격이라고 설명하면 됩니다.
이 한 문장만으로도 두 공격의 차이가 명확히 드러납니다.

면접 예상 질문과 답변

Q. CSRF와 XSS의 가장 큰 차이는 무엇인가요?
CSRF는 사용자를 속여 서버로 요청을 보내게 만드는 요청 위조 공격이고,
XSS는 악성 스크립트를 사용자 브라우저에서 실행시키는 공격입니다.
즉, CSRF는 요청의 출처 문제이고, XSS는 화면에 출력되는 코드의 문제입니다.

Q. SameSite 쿠키는 어떤 공격을 막아주나요?
SameSite 쿠키는 다른 사이트에서 발생한 요청에 쿠키가 자동으로 포함되는 것을 제한하여
CSRF 공격을 완화하는 데 도움을 줍니다.
다만 XSS처럼 동일 출처에서 실행되는 스크립트 공격까지 막아주지는 못합니다.

Q. 프론트엔드에서 XSS를 방어하는 방법을 설명해보세요.
입력값을 그대로 화면에 출력하지 않고, 반드시 이스케이프 처리하는 것이 기본입니다.
또한 innerHTML이나 dangerouslySetInnerHTML 같은 위험한 API 사용을 최소화하고,
필요하다면 Content Security Policy를 설정해 스크립트 실행을 제한해야 합니다.

결론

CSRF와 XSS는 모두 웹 보안에서 매우 중요한 공격 유형이지만,
목적과 동작 방식, 그리고 방어 전략이 전혀 다릅니다.
이 둘을 하나로 묶어 이해하면 원인도 해결책도 흐려집니다.

요청이 문제인지, 출력이 문제인지를 기준으로 나누어 사고하는 습관은
보안뿐 아니라 전체 웹 구조를 이해하는 데에도 큰 도움이 됩니다.
프론트엔드 개발자라면 이 구분을 반드시 명확히 인지하고 있어야 합니다.

FAQ

Q. CSRF 토큰이 있으면 XSS도 막을 수 있나요?
아닙니다. CSRF 토큰은 요청 위조를 막기 위한 것이며, 스크립트 실행과는 관련이 없습니다.

Q. React를 사용하면 XSS는 안전한가요?
기본적인 출력은 안전하지만, 위험한 API를 사용하면 XSS가 발생할 수 있습니다.

Q. 면접에서 CSRF와 XSS 차이를 어떻게 설명하면 좋을까요?
CSRF는 요청 위조, XSS는 스크립트 실행이라는 기준으로 설명하면 명확합니다.

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

댓글 남기기