OPEN HYPER STEP
← 목록으로 (stack-analysis)
STACK-ANALYSIS · 107 / 120
stack-analysis
CHAPTER 107 / 120
읽기 약 2
FUNCTION

CSRF 방어: 토큰 + SameSite 쿠키


핵심 개념

CSRF 공격·token·SameSite·double submit·실전 적용 — 위조 요청 차단.

본문

CSRF 공격 흐름

📋 코드 (13줄)
1. 사용자가 example.com에 로그인 (쿠키)
2. 사용자가 evil.com 방문
3. evil.com 페이지에서:
   <form action="https://example.com/transfer" method="POST">
     <input name="to" value="hacker">
     <input name="amount" value="1000000">
   </form>
   <script>document.forms[0].submit()</script>
4. 브라우저 자동으로 example.com 쿠키 첨부
5. example.com → 위조 거래 처리


→ 사용자 인지 없이 행동 수행

방어 1: SameSite Cookie (가장 쉬움)

TYPESCRIPT📋 코드 (16줄)
res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',  // 다른 사이트 요청 시 쿠키 전송 X
});


// SameSite 옵션:
// - 'strict': 다른 도메인 요청 시 쿠키 전송 안 함 (가장 안전)
// - 'lax':    GET·top-level navigation만 허용 (기본 권장)
// - 'none':   모든 요청에 전송 (CSRF 위험)


// 'lax'가 균형:
// - 외부 링크 클릭 시 로그인 유지
// - POST·iframe·XHR은 차단

방어 2: CSRF Token (이중)

TYPESCRIPT📋 코드 (20줄)
import csrf from 'csurf';

app.use(csrf({ cookie: { httpOnly: true, secure: true, sameSite: 'strict' } }));


// 폼에 토큰 주입
app.get('/transfer-form', (req, res) => {
  res.render('transfer', { csrfToken: req.csrfToken() });
});


// HTML
<form method="POST" action="/transfer">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">
  ...
</form>


// → POST 시 토큰 검증
// → 다른 사이트는 토큰 모름 → 거부

Double Submit Cookie 패턴

TYPESCRIPT📋 코드 (36줄)
// 쿠키 + 헤더 양쪽에 토큰
// 다른 사이트는 쿠키 읽지 못함 → 헤더 매칭 실패


// 발급
app.post('/login', (req, res) => {
  const csrfToken = crypto.randomUUID();
  res.cookie('csrf', csrfToken, { httpOnly: false, sameSite: 'lax' });
  // ...
});


// 검증 미들웨어
app.use((req, res, next) => {
  if (['GET', 'HEAD'].includes(req.method)) return next();

  const cookieToken = req.cookies.csrf;
  const headerToken = req.headers['x-csrf-token'];

  if (!cookieToken || cookieToken !== headerToken) {
    return res.status(403).json({ error: 'csrf_failed' });
  }
  next();
});


// 클라이언트
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': getCookie('csrf'),
    'Content-Type': 'application/json',
  },
  credentials: 'include',
  body: JSON.stringify(data),
});

Origin / Referer 검증

TYPESCRIPT📋 코드 (15줄)
function checkOrigin(req: Request, res: Response, next: NextFunction) {
  const origin = req.headers.origin || req.headers.referer;
  const allowed = [
    'https://example.com',
    'https://www.example.com',
  ];

  if (req.method !== 'GET' && origin) {
    const url = new URL(origin);
    if (!allowed.includes(url.origin)) {
      return res.status(403).end();
    }
  }
  next();
}

API 토큰 (Bearer) — CSRF 자동 면역

TYPESCRIPT📋 코드 (15줄)
// JWT를 Authorization 헤더로 보내면 CSRF 불가
// 브라우저가 자동으로 헤더 추가하지 않음


fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
  },
  body: JSON.stringify(data),
});


// → 다른 사이트가 헤더 추가 못 함 → CSRF 자동 방어
// → 단, accessToken이 localStorage면 XSS 위험

SPA — 권장 패턴

📋 코드 (10줄)
[1순위] Bearer Token + httpOnly Refresh Cookie
- accessToken: JS 메모리 (페이지 새로고침 시 refresh)
- refreshToken: httpOnly Secure SameSite=Strict cookie
- → CSRF 면역 + XSS 보호


[2순위] Session Cookie + CSRF Token
- session: httpOnly Secure SameSite=Lax
- csrf: 헤더로 검증
- → 전통적 + 안전

GraphQL · tRPC

TYPESCRIPT📋 코드 (20줄)
// GraphQL — 동일 정책
// POST /graphql 모든 mutation에 CSRF 보호


// tRPC — Origin 검증 + Bearer
import { createTRPCContext } from '@trpc/server';

const t = initTRPC.context<Context>().create({
  errorFormatter({ shape }) { return shape; },
});


// 미들웨어로 Origin 검증
const isFromAllowedOrigin = t.middleware(({ ctx, next }) => {
  const origin = ctx.req.headers.origin;
  if (origin && !ALLOWED_ORIGINS.includes(origin)) {
    throw new TRPCError({ code: 'FORBIDDEN' });
  }
  return next();
});

흔한 실수

📋 코드 (9줄)
1. SameSite=None + Secure 누락 → 쿠키 전송 안 됨
2. SameSite=Strict인데 외부 링크 클릭 시 로그인 풀림
   → Lax 사용

3. CSRF 토큰을 일회용으로 → 사용자 짜증
   → 세션 단위 또는 시간 기반

4. GET 요청에 변경 동작 (security through obscurity)
   → POST/PUT/DELETE 사용 + CSRF 검증

다음 챕터

CH.108 "파일 업로드 보안".


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 코드의 CSRF 방어 부분을 분석해서
실전 분석 + 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

CSRF 방어 관련 베스트 프랙티스 5가지를
비교 분석해서 패턴 추출를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 프로젝트 전체에서 CSRF 방어
최적화 가능 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 시장의 CSRF 방어
트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
CSRF 방어: 토큰 + SameSite 쿠키 이 3가지만 확실히 잡으세요
1.SameSite=Lax cookie = 90% CSRF 방어 — 기본 적용
2.CSRF Token (csurf) + Double Submit = 이중 안전망
3.Bearer Token (Authorization 헤더) = CSRF 자동 면역


공유하기
진행도 107 / 120