본 발표는 Ruby on Rails API 모드 환경에서 발생하는 CSRF(Cross-Site Request Forgery) 공격에 대한 효과적이고 단순한 방어 전략을 탐구합니다. CSRF는 사용자의 기존 세션을 악용하여 의도치 않은 동작을 유발하는 사이버 공격의 일종으로, 특히 쿠키 기반 세션을 사용하는 애플리케이션에서 주의가 필요합니다. 전통적인 Rails 애플리케이션에서는 토큰 방식을 통해 효과적으로 방어해왔으나, 프론트엔드와 백엔드가 분리된 SPA(Single Page Application) 형태의 Rails API 모드 개발 환경에서는 기존 토큰 방식의 적용이 복잡해지는 문제가 발생합니다. 이에 따라, 본 발표에서는 Rails API 환경에 적합한 보다 간결한 CSRF 방어 기법들을 중점적으로 다룹니다.
Rails의 기본 CSRF 방어 메커니즘은 Synchronizer Token Pattern으로 알려진 토큰 방식입니다. 이 방식은 서버에서 발급한 토큰을 클라이언트가 요청과 함께 보내면 서버에서 이를 검증하여 요청의 유효성을 확인하는 방식입니다. 이는 Rails의 View와 Controller가 결합된 풀스택 환경에서는 protect_from_forgery
와 같은 간편한 설정을 통해 쉽게 적용 가능하며, 프레임워크 차원의 가이드가 잘 제공된다는 장점이 있습니다. 그러나 React 등 별도의 프론트엔드에서 API를 호출하는 환경에서는 토큰의 발행, 전달, 관리 로직을 직접 구현해야 하므로 복잡성이 증가합니다.
이러한 배경에서 토큰 방식에 얽매이지 않고 CSRF를 방어할 수 있는 대체 방안들이 부상합니다. 핵심은 요청의 출처를 확인하거나, CSRF 공격의 기반이 되는 쿠키의 자동 전송을 제어하는 것입니다. 첫 번째 접근 방식은 Origin
헤더를 확인하는 것입니다. 브라우저는 요청 시 Origin
헤더에 프로토콜, 호스트, 포트 번호를 포함한 출처 정보를 담아 보냅니다. 서버는 이 헤더 값을 검증하여 허용된 출처에서의 요청인지 판단할 수 있습니다. 과거에는 모든 요청에서 Origin
헤더가 전송되지 않는 경우가 있었으나, 현재는 대부분의 브라우저에서 부작용을 유발하는 POST 등의 메서드 요청 시 Origin
헤더를 안정적으로 제공합니다. 따라서 Origin
헤더 검사만으로도 상당 부분의 CSRF 공격을 방어할 수 있습니다.
보다 강화된 방어를 위해서는 Fetch Metadata
헤더를 활용할 수 있습니다. Sec-Fetch-Site
, Sec-Fetch-Mode
, Sec-Fetch-Dest
등의 헤더는 요청의 발생 맥락(동일 출처, 동일 사이트, 크로스 사이트 등)에 대한 상세 정보를 제공합니다. 특히 Sec-Fetch-Site
헤더는 요청의 출처와 목적지 간의 관계를 나타내어, 악의적인 크로스 사이트 요청을 보다 정확하게 탐지하고 차단하는 데 유용합니다. 이는 Origin
헤더가 제공하지 못하는 요청의 문맥 정보를 보완해주며, iframe 내 요청 등 복잡한 시나리오에서도 효과적인 보안 정책을 적용할 수 있게 합니다. 다만, Fetch Metadata
는 비교적 최신 사양이므로 모든 브라우저에서 완벽하게 지원되는 것은 아니므로, 헤더가 존재하는 경우에만 검증하는 방식으로 구현하는 것이 현실적입니다.
세 번째 방안은 쿠키 자체의 전송 방식을 제어하는 SameSite
쿠키 속성을 활용하는 것입니다. SameSite
속성은 Lax
, Strict
, None
값을 가질 수 있으며, Lax
또는 Strict
로 설정할 경우 크로스 사이트 요청에서의 쿠키 전송을 제한할 수 있습니다. 이는 주로 서드파티 쿠키 제어를 통한 개인 정보 보호 목적으로 도입되었으나, 부수적으로 CSRF 방어에도 기여합니다. Strict
는 동일 사이트 요청에서만 쿠키를 보내고, Lax
는 일부 예외(예: GET 요청 네비게이션)를 허용합니다. SameSite=Lax
는 2분 이내의 특정 시나리오에서 쿠키가 전송되는 ‘2분 룰’이라는 예외가 존재하므로, 이 속성만으로는 완전한 CSRF 방어가 어렵습니다. 따라서 다른 방어 기법과 병행하는 것이 필수적입니다. Rails 6.1부터는 SameSite=Lax
가 기본값으로 설정되어 있어 별도 설정 없이도 기본적인 보호를 받을 수 있습니다.
Rails에서의 구현은 ApplicationController에서 요청을 가로채 Origin
헤더와 Sec-Fetch-Site
헤더를 검증하는 간단한 로직으로 이루어질 수 있습니다. HTTP 메서드를 확인하여 부작용이 있는 메서드(POST, PUT, DELETE 등)에 대해서만 검사를 수행하고, 허용된 출처 목록과 비교하거나 Sec-Fetch-Site
값이 ‘same-origin’ 또는 ‘same-site’인지 확인하는 방식으로 구현합니다. 이처럼 Rails API 모드에서는 토큰 방식의 복잡성 없이도 브라우저의 최신 기능을 활용하여 간단하고 효과적인 CSRF 방어 체계를 구축할 수 있습니다.
결론적으로, Rails API 모드에서 CSRF 방어를 위해서는 전통적인 토큰 방식보다는 브라우저가 제공하는 `Origin` 헤더, `Fetch Metadata` 헤더, 그리고 `SameSite` 쿠키 속성을 활용하는 것이 더 실용적이고 간단한 접근 방식입니다. 핵심은 요청의 출처를 검증하는 것에 있으며, `Origin` 헤더 검사를 기본적인 방어선으로 설정하고, 서비스의 보안 요구사항과 위험도를 고려하여 `Fetch Metadata` 및 `SameSite` 속성을 추가적으로 활용하여 방어 강도를 높일 수 있습니다. 반면, Rails의 View를 사용하는 풀스택 애플리케이션의 경우에는 프레임워크가 제공하는 토큰 방식을 사용하는 것이 여전히 가장 권장되는 방법입니다. Rails API 환경에서는 이러한 브라우저 기반의 새로운 방어 기법들을 이해하고 적용하는 것이 중요합니다.