Conceptly
← 전체 목록
🎭

Cross-Site Request Forgery

보안사용자의 브라우저가 가진 인증 상태를 악용해 원치 않는 요청을 보내게 만드는 공격

CSRF(Cross-Site Request Forgery)는 공격자가 사용자의 브라우저에 남아 있는 인증 상태를 이용해, 사용자가 의도하지 않은 요청을 정상 사이트로 보내게 만드는 웹 공격입니다. 특히 세션 쿠키처럼 브라우저가 자동으로 붙이는 인증 방식에서 문제가 되며, 서버는 요청이 로그인된 사용자에게서 왔다는 사실만으로는 그 요청이 정말 사용자의 의도였는지 판단할 수 없습니다.

아키텍처 다이어그램

🔄 프로세스 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

쿠키 기반 인증의 장점은 브라우저가 세션 쿠키를 자동으로 붙여 준다는 점입니다. 문제는 이 편의가 공격에도 그대로 쓰인다는 것입니다. 사용자가 이미 로그인한 상태에서 공격자의 페이지를 열면, 그 페이지는 숨은 form이나 이미지 요청으로 정상 서버에 요청을 보낼 수 있습니다. 브라우저는 그것이 사용자의 의도인지 아닌지 판단하지 않고, 해당 사이트의 쿠키를 자동으로 함께 보냅니다. 서버가 보는 것은 유효한 쿠키가 실린 정상 요청뿐입니다. 요청이 정말 사용자가 버튼을 눌러 보낸 것인지, 아니면 다른 사이트가 몰래 유도한 것인지는 구분되지 않습니다. 그래서 상태를 바꾸는 요청에는 '누가 로그인했는가'만으로는 부족하고, '이 요청이 그 사용자 의도에서 나온 것인가'를 추가로 확인해야 합니다.

왜 이런 방식이 등장했나요?

전통적인 서버 렌더링 웹은 form 제출과 쿠키 세션에 크게 의존했습니다. 이 구조에서는 사용자가 다른 사이트를 열어도 브라우저가 해당 사이트의 요청을 만들어 낼 수 있었고, 쿠키는 자동으로 붙었습니다. 초기에 많은 애플리케이션이 GET과 POST만 구분하면 충분하다고 생각했지만, 실제로는 숨겨진 form 자동 제출이나 이미지 요청만으로도 위험한 동작이 유발될 수 있었습니다. 이후 프레임워크들이 CSRF 토큰을 기본 제공하기 시작했고, 브라우저도 SameSite 기본값을 강화하면서 상황은 나아졌습니다. 그럼에도 쿠키 기반 세션을 쓰는 서비스, 특히 오래된 폼 화면이나 OAuth 리다이렉트 처리 구간에서는 여전히 CSRF가 중요한 경계로 남아 있습니다.

안에서 어떻게 동작하나요?

CSRF는 사용자가 로그인된 상태라는 전제를 이용해 요청 진위를 속이는 공격입니다. 먼저 사용자는 정상 사이트에 로그인해 세션 쿠키를 갖고 있습니다. 그 상태에서 공격 페이지를 방문하면, 공격 페이지는 숨겨진 form을 자동 제출하거나 특정 URL을 호출하는 태그를 삽입해 브라우저가 요청을 보내도록 만듭니다. 브라우저는 해당 요청이 목표 사이트로 향한다고 판단하면 세션 쿠키를 자동으로 첨부합니다. 문제는 서버 입장입니다. 서버는 유효한 세션 쿠키가 붙은 요청을 받으므로, 추가 검증이 없으면 이를 정상 사용자의 행동으로 오해하고 상태 변경을 수행합니다. 비밀번호 변경, 이메일 수정, 관리자 설정 변경 같은 작업이 이 방식으로 실행될 수 있습니다. 방어의 핵심은 요청 안에 공격 페이지가 예측하거나 재사용할 수 없는 신호를 넣는 것입니다. CSRF 토큰을 폼이나 커스텀 헤더에 넣고 서버가 그것을 검증하거나, Origin과 Referer 헤더로 요청 출처를 확인합니다. SameSite 쿠키 속성은 브라우저 차원에서 교차 사이트 요청에 쿠키 첨부를 줄여 주지만, 모든 상황을 단독으로 해결해 주지는 않습니다.

무엇과 헷갈리나요?

CSRF와 XSS는 둘 다 브라우저를 거쳐 공격하지만, 결정적인 차이는 코드 실행 여부입니다. XSS는 신뢰된 페이지 안에서 자바스크립트를 실행하므로 응답을 읽고 화면을 바꾸고 토큰도 훔칠 수 있습니다. CSRF는 다른 사이트가 요청만 보내게 만드는 공격이라 보통은 응답 내용을 읽지 못합니다. 또 자주 헷갈리는 것이 CORS와의 관계입니다. CORS는 자바스크립트가 교차 출처 응답을 읽을 수 있는지 통제하지만, 브라우저가 요청 자체를 보내는 것을 막아 주지는 않습니다. 그래서 CORS를 엄격하게 설정했다고 해서 CSRF가 자동으로 해결되지는 않습니다. 요청 진위 검증은 별도의 문제입니다.

언제 쓰나요?

실무에서는 상태를 바꾸는 모든 엔드포인트를 먼저 봅니다. 프로필 수정, 비밀번호 변경, 결제 요청, 관리자 삭제 버튼처럼 실행되면 피해가 큰 작업이 우선순위입니다. 서버 렌더링 폼이라면 hidden field로 CSRF 토큰을 넣고, SPA라면 서버가 내려 준 토큰을 커스텀 헤더에 실어 보내도록 구성하는 패턴이 일반적입니다. 쿠키 설정도 함께 봐야 합니다. SameSite=Lax나 Strict는 교차 사이트 요청에 쿠키가 붙는 범위를 줄여 기본 방어선을 올려 줍니다. 다만 OAuth 같은 리다이렉트 기반 흐름에서는 예외가 생기므로, state 값 검증 같은 별도 장치가 필요합니다. 마지막으로, 'POST니까 안전하다'는 생각은 위험합니다. 메서드만 바꾸는 것으로는 요청 진위를 증명할 수 없습니다. 상태 변경 API를 설계할 때는 처음부터 토큰 검증과 출처 확인을 같이 두는 것이 운영 비용을 줄이는 길입니다.

계정 설정 변경금융·결제 화면관리자 패널OAuth 리다이렉트 흐름