CSRF (Cross-Site Request Forgery) 는 웹 애플리케이션이 사용자의 신뢰를 받는 상태에서 공격자가 사용자의 권한을 도용해 임의의 요청을 서버에 보내는 보안 취약점입니다.
ex) 사용자 A가 은행 웹사이트에 로그인한 상태에서 악의적인 링크를 클릭했을 때, 그 링크가 공격자의 계좌로 돈을 송금하도록 만든 요청을 서버에 보냄.
피싱 사이트에서 사용자의 세션 정보를 탈취해 요청을 전송하면, CSRF의 취약성이 있는 경우 서버가 정상처리로 간주하게 됩니다. 특히 <form> 요소로 전송되는 요청은 동일 출처 정책에 의해 제한되지 않습니다. 그래서 쿠키나 세션의 사용에 있어서 보안을 강화하는게 이번 챕터의 주제입니다.
CSRF의 가장 효과적인 대책으로, 다른 사람이 추측할 수 없는 비밀 문자열인 토큰을 사용하는 방법입니다. 이 토큰은 서버가 피싱 사이트에서 보낸 요청인지, 웹 어플리케이션에서 보낸 정상 요청인지 확인하는데 사용됩니다.
이 방법은 공격자가 결국 유효한 토큰을 알아야 하는데 Same-origin policy에 의해 공격자가 토큰을 도용할 수 없습니다.
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="generated_token">
<input type="submit" value="Transfer">
</form>
위처럼 type=”hidden”으로 토큰을 같이 보냅니다.
그러나 요청마다 랜덤토큰을 발급하고 서버에서 유지해야한다는 점에서 서버 리소스를 소모합니다.
이 방법은 서버에 토큰을 유지하지 않고 브라우저의 쿠키에 유지하는 방법입니다. 그래서 요청을 보낼때 본문 혹은 헤더에 토큰을, 쿠키에 토큰을 동시에 전달하여 요청을 검증하는 방식입니다.
CSRF 공격자는 서버로 요청을 보낼 때 클라이언트의 쿠키에 접근할 수 없도록 브라우저가 관리하므로 안전합니다. (그래서 XSS 안전성도 확보가 되어야합니다)
이 방법은 API 서버와 프론트엔드 서버가 분리되어있을때 토큰을 서버에 저장하는 방법을 사용할 수 없기 때문에 CSRF 방지에 효과적입니다.
SameSite 쿠키는 브라우저가 쿠키를 제어하는 기능으로, 쿠키가 전송되는 상황을 제한하는 방법입니다. 그래서 쿠키가 동일 출처에서만 전송될 수 있도록 합니다. (동일 출처 => eTLD+1)
Set-Cookie 헤더에 쿠키를 설정할 때 SameSite 속성을 지정하면 됩니다.
Lax라 해도 최소한의 안전장치 정도로 생각해야합니다. 왜냐하면 대부분의 공격을 막는다 하더라도 GET 요청으로 데이터를 수정하거나 전송하는데 사용된다면 막을 수 없기 때문입니다.
Origin은 해당 요청이 어떤 출처에서 발생했는지를 나타냅니다. 즉, 요청이 발생한 도메인, 프로토콜, 포트정보를 서버에 전송하기에 신뢰하는 Origin인지만 판단하면 됩니다. 간단하고 매우 강력한 방법이며 프론트에선 자동으로 호출해줍니다.
다만 Origin 헤더를 지원하지 않는 브라우저를 조심해야하는데 사실상 다 지원합니다…
(프론트 서버와 api 서버가 다를때 유리)

X-Requested-With: XMLHttpRequest와 같은 임의 헤더로 의도적인 Preflight request를 발생시킵니다. 그리고 허가된 출처로부터의 요청인지, 추가한 헤더가 있는지를 파악하여 요청을 에러처리하면 됩니다.
(프론트 서버와 api 서버가 다를때 유리)