모바일 개발에서 CSRF: 정의, 공격 유형 및 보호 방법

저자: IT Sectr 게시일: 2026-04-06 읽는 시간: 9 분

CSRF(Cross-Site Request Forgery)는 공격자가 피해자의 브라우저를 강제로 인증된 사용자를 대신하여 목적 서버에 위조된 요청을 보내는 공격 유형입니다. OWASP, 2026에 따르면, CSRF는 웹 애플리케이션에 대한 가장 위험한 위험 10가지 중 하나입니다. 모바일 개발의 맥락에서 CSRF 공격은 쿼기 인증을 사용하는 REST API에 대해 특히 위험합니다. 크로스 사이트 요청 위조는 현대적인 보호 메커니즘의 구현에도 불구하고 여전히 안전에 영향을 미치는 위협으로 남아 있습니다.

중요 포인트

  • CSRF — 인증된 사용자의 브라우저에 대한 서버의 신뢰를 암용하는 공격
  • 주요 목적 — 피해자의 동의 없이 이름으로 작업 수행: 자금 송금, 비밀번호 변경, 데이터 삭제
  • 쿼기 인증 — 주요 벡터: 브라우저가 자동으로 요청에 쿼기를 첨부하고, 서버는 정상 요청과 위조된 요청을 구분하지 못함
  • CSRF 토큰 — 주요 보호 방법: 작업 수행 전에 서버에서 검증되는 고유한 비밀 토큰
  • SameSite — 크로스 도메인 요청에서 쿼기 전송을 제한하여 CSRF 위험을 크게 줄여주는 쿼기 속성

CSRF 공격이란?

CSRF(Cross-Site Request Forgery)는 공격자가 위조된 요청을 생성하고 피해자의 브라우저가 이를 목적 서버로 보내도록 강제하는 공격입니다. 서버는 사용자의 현재 세션으로부터 유효한 쿼기 직전화를 통한 인증 정보를 받기 때문에 요청을 수행합니다. 요청이 어느 페이지에서 보냄지에 관계없이 브라우저가 자동으로 목적 도메인에 대한 모든 요청에 쿼기를 추가하기 때문에 공격이 가능합니다. 사용자는 공격자의 페이지를 보지도 못할 수 있습니다. 앜의적인 URL이 있는 숨긴 <img>, <form> 또는 <iframe>을 로드하는 것만으로 붉윽니다. CSRF는 돁접 데이터를 휘치지 않습니다. 공격은 피해자를 대신하여 행동을 수행합니다(상태 변경 작업). 예를 들어, 자금 송금, 비밀번호 변경, 계정 삭제 등이 있습니다.

어떤 작업이 가장 취약한가?

CSRF 공격은 오직 상태 변경 작업만을 대상으로 합니다 — 부작용이 있는 GET 요청, POST, PUT, DELETE. 예를 들어, 개인 계정의 이메일 주소 변경 요청: 서버가 요청의 기원을 확인하지 않고 수락하는 경우, 공격자는 자신의 이메일을 대신 설정하고 비밀번호 재설정을 시작할 수 있습니다. 이 공격은 한 것의 행동이 심각한 결과를 초래하는 은행 시스템, 관리자 패널, 소셜 네트워크에 대해 특히 위험합니다. 인증에 쿼기를 사용하는 모바일 앱 API도 추가 검사를 수행하지 않으면 CSRF에 대해 취약합니다.

누가 위험에 노출되어 있나요?

인증이 쿼기에 기반하고 서버가 요청 기원을 확인하지 않는 모든 웹 애플리케이션 및 API는 취약합니다. 웹 폼을 통한 인증에 WebView를 사용하는 모바일 애플리케이션도 위험에 노출됩니다: 브라우저 컴포넌트가 자동으로 쿼기를 보내고, 공격자는 백그라운드 로드를 통해 알의적인 요청을 주입할 수 있습니다. HackerOne (2025)에 따르면, 웹 애플리케이션에서의 모든 취약점 보고서의 약 12%가 CSRF 보호 부재와 관련됩니다.

CSRF가 위험한 이유

CSRF의 주요 특징은 피해자에게 보이지 않는다는 점입니다. 사용자는 공격이 발생한 사실을 인지하지 못할 수도 있습니다. 위조된 요청은 백그라운드에서 실행되고, 애플리케이션 인터페이스에는 해킹의 증거가 나타나지 않습니다. CSRF를 감지하는 유일한 방법은 서버 로그를 모니터링하거나 계정에서 갑자기 변경 사항을 발견하는 것입니다. 또한, CSRF는 XSS나 오픈 리다이렉트와 같은 다른 취약점과 쉽게 결합되어 피해가 덧배로 달할 수 있습니다.

CSRF 공격의 작동 원리

CSRF 공격에는 세 가지 조건이 필요합니다: 피해자가 목적 사이트에 인증되어 있어야 하고, 서버가 쿼기 인증을 사용하며, 공격자의 요청이 액션 URL로 전달되어야 합니다. 공격자는 src 속성이 목적 URL을 가리키는 폼, 스크립트 또는 이미지가 있는 HTML 페이지를 생성합니다. 피해자의 브라우저가 이 페이지를 로드하고 자동으로 현재 세션 쿼기와 함께 서버로 요청을 보냙니다. 서버는 유효한 쿼기를 받고, 요청 출처를 확인하지 않으며, 작업을 수행합니다.

html
<!-- 숨겨진 양식을 통한 CSRF 공격 예시 -->
<form action="https://bank.example.com/transfer"
      method="POST" id="csrf-form">
    <input type="hidden"
           name="toAccount"
           value="attacker-account">
    <input type="hidden"
           name="amount"
           value="10000">
</form>
<script>document.getElementById("csrf-form").submit()</script>

페이지가 로드된 후, 스크립트가 곱장 폼을 제출합니다. 브라우저는 bank.example.com에 대한 POST 요청에 사용자의 세션 쿼기를 첨부합니다. 은행 서버는 쿼기를 확인하고, 사용자가 인증되었음을 확인하고, 공격자의 계정으로 송금을 수행합니다. 피해자는 빈 페이지나 정상 페이지를 보지만, 자금은 이미 손살된 상태입니다.

CSRF에서 브라우저의 역할

HTTP 프로토콜의 주요 특징은 요청 출처 검증 기능이 내재되지 않는 점입니다. 브라우저는 요청 도메인이 쿼기 도메인과 일치하는 경우 요청에 쿼기를 추가합니다. 공격자는 쿼기의 내용을 알 필요가 없습니다 — 브라우저가 이를 자동으로 수행합니다. 동일 기원 정책은 공격이 응답이 아닌 서버를 대상으로 하기 때문에 CSRF로부터 보호하지 못합니다. CORS와 같은 메커니즘도 무능합니다: CSRF 요청은 일반적으로 피해를 일으키기 위해 응답을 읽을 필요가 없습니다.

CSRF 공격의 주요 유형

CSRF 공격은 압의적인 요청을 전달하는 방법에 따라 분류됩니다. 각 유형은 요청을 보내기 위해 다른 HTML 요소를 사용하지만, 모두 브라우저에 의한 자동 쿼기 전송에 의존합니다. 방법의 선택은 공격자의 목적에 따라 달라집니다: GET 기반 공격은 더 적은 코드가 필요하고, POST 기반 공격은 일부 보호 조치를 더 신뢰성있게 우회할 수 있으며, XMLHttpRequest 기반 공격은 헤더 조작이 가능합니다.

공격 유형전달 벡터HTTP 메소드감지 난이도
GET 기반<img>, <script>, <iframe>GET높음
POST 기반숨긴 <form> + 자동 제출POST중간
XHR 기반CORS와 함께한 XMLHttpRequest임의낮음

GET 기반 CSRF

가장 간단한 방법: 공격자가 요청 매개변수가 들어있는 URL을 가진 <img>를 페이지에 배치합니다. 브라우저가 이미지를 로드하고 GET 요청을 서버로 보냙니다. 예를 들어, <img src="https://api.example.com/delete?postId=123" />는 서버가 GET을 통한 DELETE를 처리하는 경우 레코드를 삭제합니다. 명백한 위험에도 불구하고, 일부 API는 여전히 삭제나 업데이트 작업에 GET을 사용합니다.

POST 기반 CSRF

서버가 POST 요청만 수락하는 경우, 공격자는 POST 메소드로 숨긴 폼을 생성하고 JavaScript를 통해 자동으로 제출합니다. 폼이 화면에 표시되지 않고(모든 <input>이 type="hidden"), autofocus + .submit()가 사용자 클릭 없이 작동합니다. POST 기반 공격은 서버가 Content-Type 헤더를 확인하는 경우 작동하지 않지만, 대부분의 API는 표준 application/x-www-form-urlencoded를 수락합니다.

XHR 기반 CSRF (CORS 사용)

XMLHttpRequest 또는 Fetch API는 임의의 헤더를 가진 요청을 보낼 수 있습니다. 서버가 CORS를 너무 폭넣게 구성한 경우(Access-Control-Allow-Origin: *), 공격자는 임의의 요청을 보내고 응답을 읽을 수 있습니다. 그러나 CSRF 공격에는 응답을 읽을 필요가 없습니다 — 단지 작업을 수행하는 것만으로 붉윽니다. 현대 브라우저는 비표준 요청 전에 preflight 요청 OPTIONS을 보내서, 서버가 올바르게 구성된 경우 XHR 기반 CSRF를 차단할 수 있습니다.

모바일 애플리케이션에서 CSRF

모바일 애플리케이션은 웹 사이트보다 CSRF에 덜 더 취약하지 않습니다. 이는 네이티브 앱이 쿼기 인증을 거의 사용하지 않기 때문입니다. 대신, 모바일 API는 Authorization 헤더(Bearer 토큰, JWT)에 토큰을 더 자주 사용합니다. 그러나 CSRF 공격이 가능한 상황이 있습니다: 웹 로그인이 있는 WebView, 하이브리드 애플리케이션, 쿼기 기반 세션이 있는 API. TechCrunch (2025)에 따르면, 공개 모바일 앱 API의 약 18%가 여전히 세션 쿼기를 지원합니다.

WebView를 통한 CSRF

많은 앱이 WebView에서 웹 페이지를 엽니다 — OAuth 인증, 결제 폼, 콘텐츠 보기 등. WebView는 세션 쿼기를 저장하는 앱 내의 완전한 브라우저입니다. 공격자가 오픈 리다이렉트나 딥 링크를 통해 WebView에 자신의 URL을 로드하는 방법을 찾은 경우, 일반 브라우저와 마찬가지로 CSRF 공격을 수행할 수 있습니다. 보호 방법 — 중요한 작업에는 WebView 대신 Chrome Custom Tabs나 SFSafariViewController를 사용하세요.

JWT 인증을 사용하는 API에서 CSRF

JWT 토큰은 일반적으로 localStorage나 앱의 메모리에 저장되며 자동으로 전송되지 않습니다 — 개발자가 명시적으로 각 요청에 Authorization 헤더를 추가합니다. 이를 통해 고전적인 CSRF 공격은 불가능해집니다. 그러나 앱이 JWT를 쿼기에 저장하는 경우(듀물하지만 가능함), 위험이 돌아옵니다. 추가 보호 — azp 또는 aud 클레임을 통해 JWT를 특정 요청 기원에 바인딩하여 다른 도메인에서의 토큰 사용을 방지합니다.

javascript
// Express에서 서버 측 CSRF 토큰 검증 예시
const csrfProtection = (req, res, next) => {
    const token = req.headers['x-csrf-token'];
    if (!token || token !== req.session.csrfToken) {
        return res.status(403).json({ error: 'CSRF validation failed' });
    }
    next();
};

// 로그인 시 CSRF 토큰 생성
app.post('/api/login', (req, res) => {
    const csrfToken = crypto.randomBytes(32).toString('hex');
    req.session.csrfToken = csrfToken;
    res.json({ csrfToken: csrfToken });
});

CSRF 보호 방법

현대적인 CSRF 보호는 세 단계로 구축됩니다: 서버 측 CSRF 토큰, 쿼기에 대한 SameSite 속성, Origin 헤더 확인. 이 방법을 조합하면 UX에 중대한 영향을 주지 않고 CSRF 공격의 99%를 차단할 수 있습니다. 접근 방법의 선택은 애플리케이션 아키텍처에 따라 달라집니다: 웹 사이트는 SameSite=Lax만 필요할 수 있지만, 모바일 앱 API는 헤더에 토큰이 필요합니다.

CSRF 토큰 (동기화기)

표준 방법: 서버가 고유한 토큰을 생성하고, 사용자의 세션에 바인딩한 후 클라이언트에 전송합니다. 클라이언트는 상태 변경 요청마다 토큰을 포함시킵니다(숨긴 폼 필드 또는 X-CSRF-Token 헤더). 서버는 수신된 토큰과 세션에 저장된 토큰을 비교합니다. 토큰은 암호학적으로 강력하고, 무작위이며, 최소 32 바이트 길이여야 하고, 세션 또는 작업마다 변경되어야 합니다. 토큰의 수명 시간은 몇 시간을 넘어서는 안 됩니다.

SameSite Cookie

쿼기에 대한 SameSite 속성은 크로스 도메인 요청에서 쿼기 전송을 제한합니다. Lax 값은 상위 레벨 네비게이션 GET 요청에만 쿼기를 허용합니다 — 대부분의 웹 사이트에 촉합니다. Strict는 네비게이션을 포함하여 모든 크로스 도메인 요청에 대해 쿼기를 차단합니다: 다른 사이트에서 앤수하는 경우 사용자가 재인증해야 합니다. Chrome Platform Status (2026)에 따르면, SameSite=Lax는 모든 현대 브라우저에서 기본으로 사용으로 설정되어 있으며, CSRF 공격 수를 67% 감소시켰습니다.

Origin 및 Referer 확인

서버는 수신 요청의 Origin 또는 Referer 헤더를 확인할 수 있습니다. 요청이 다른 도메인에서 온 경우 차단됩니다. Origin은 Referer보다 더 신뢰할 수 있습니다. POST 요청에 항상 존재하고 브라우저 정책으로 비활성화할 수 없기 때문입니다. 구현 방법: 허용된 Origin의 화이트 리스트를 만들고 현재 헤더 값과 비교합니다. 이 방법은 효과적이지만, Origin 헤더가 없거나 위조될 수 있는 모바일 앱에서는 구현이 어력습니다.

kotlin
// Spring Boot에서 CSRF 토큰 검증 예시
@Configuration
@EnableWebSecurity
class SecurityConfig {
    @Bean
    fun securityFilterChain(
        @Autowired http: HttpSecurity
    ): SecurityFilterChain {
        return http
            .csrf { it.csrfTokenRepository(
                CookieCsrfTokenRepository.withHttpOnlyFalse()
            ) }
            .sessionManagement {
                it.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            }
            .build()
    }
}

Double Submit Cookie

서버 측 토큰 저장이 필요없는 방법: 서버가 무작위 값으로 쿼기를 설정하고, 클라이언트가 쿼기에서 값을 읽어 헤더 또는 요청 본문에 담아 보냙니다. 서버는 두 값을 비교합니다. 공격자가 쿼기를 읽을 수 없는 경우(동일 기원 정책), 토큰을 위조할 수 없습니다. 이 방법은 동기화기보다 구현하기 쉽지만, 쿼기를 가도으로부터 보호하기 위해 HTTPS가 필요합니다.

  • CSRF 토큰 — 고다 표준: 신뢰할 수 있고, 검증되었으며, 모든 프레임워크에서 지원됨
  • SameSite=Lax — 웹 앱에 대한 최소 보호: 무료, 자동, 코드 필요 없음
  • Origin 확인 — 추가 계층: 토큰 검증 전에 공격 차단
  • Double Submit — 서버 측 세션이 없는 REST API용: HTTPS에서 효과적
  • 사용자 정의 헤더 — X-Requested-With: XMLHttpRequest가 단순 CSRF 폼 차단

CSRF와 XSS의 차이

CSRF와 XSS는 종종 혼동되는 다른 유형의 공격입니다. CSRF는 사용자의 브라우저에 대한 서버의 신뢰를 앜용합니다: 요청이 유효한 쿼기와 함께 도착하기 때문에 서버가 공격자의 명령을 수행합니다. XSS는 서버의 콘텐츠에 대한 브라우저의 신뢰를 앜용합니다: 브라우저가 공격자에 의해 페이지에 주입된 스크립트를 실행합니다. CSRF는 목적 사이트에 코드를 주입할 필요가 없습니다 — 다른 도메인에서 요청을 보내면 됩니다. XSS는 반대로 페이지의 HTML 코드에 JavaScript를 주입할 방법을 찾아야 합니다. 그러나 XSS는 CSRF 보호를 우회할 수 있습니다: 주입된 스크립트가 페이지에서 CSRF 토큰을 읽어 요청과 함께 보냙니다.

특정CSRFXSS
공격 목표서버클라이언트 (브라우저)
벡터요청 위조스크립트 주입
피해자 사이트에 JavaScript가 필요한가?아니오
데이터 도용아니오 (작업만 가능)가능
보호CSRF 토큰, SameSite, Origin출력 탈피, CSP

CSRF와 XSS의 차이를 이해하는 것은 다층 보호를 구축하는 데 중요합니다. CSRF 토큰은 XSS로부터 보호하지 못하고, CSP(Content Security Policy)는 CSRF로부터 보호하지 못합니다. 모든 방법의 조합만이 두 유형의 공격으로부터 애플리케이션의 보안을 보장합니다. WebView가 있는 모바일 앱에서는 위험이 더욱 덧배로 달하므로, 개발자는 API 요청에 최소한 CSRF 토큰과 웹 콘텐츠에 Content Security Policy를 적용할 것을 권장합니다.

자주 묻는 질문

CSRF는 크로스 사이트 스크립팅과 어떻게 다른가요?

CSRF는 서버가 사용자를 대신하여 작업을 수행하도록 하는 반면, XSS는 피해자의 브라우저에 압의스크립트를 주입합니다. CSRF는 목적 사이트에 코드를 주입할 필요가 없습니다 — 다른 도메인에서 요청을 보내면 됩니다. XSS는 CSRF와 달리 데이터를 휘치고 페이지 콘텐츠를 읽을 수 있습니다.

제 애플리케이션이 CSRF에 대해 취약한지 어떻게 알 수 있나요?

쿼기 인증을 사용하는지, 그리고 상태 변경 작업에 대한 요청 기원 확인이 있는지 확인하세요. API가 CSRF 토큰, Origin 확인 또는 SameSite 없이 POST/PUT/DELETE를 수락하는 경우 취약합니다. 자동 스캔에는 OWASP ZAP 또는 Burp Suite를 사용하세요.

CORS가 CSRF로부터 보호하나요?

아니오, CORS는 CSRF로부터 보호하지 않습니다. CORS는 크로스 도메인 응답을 안전하게 읽기 위한 메커니즘이며, CSRF 공격은 응답을 읽을 필요가 없습니다. <form> 또는 <img>를 통한 CSRF 요청은 CORS 제한을 받지 않습니다.

모바일 앱 REST API에 CSRF 보호가 필요한가요?

API가 쿼기 인증을 사용하는 경우 CSRF 보호가 필수입니다. API가 Authorization 헤더에 Bearer 토큰을 사용하는 경우, 토큰이 브라우저에 의해 자동으로 전송되지 않기 때문에 CSRF 위험이 매우 낮습니다. 그러나 WebView가 있는 하이브리드 앱의 경우 보호가 여전히 권장됩니다.

브라우저가 SameSite를 지원하지 않는 경우 어떻게 해야 하나요?

SameSite는 2020년부터 모든 현대 브라우저에서 지원됩니다. 구 브라우저에는 주요 보호 방법으로 CSRF 토큰을 사용하세요. CSRF 토큰 + SameSite 존합은 레거시 브라우저에서 SameSite가 비활성화되어도 최대 보호를 제공합니다.

요약

  • CSRF — 인증된 사용자의 브라우저에 대한 서버의 신뢰를 앜용하는 크로스 사이트 요청 위조 공격
  • 공격 메커니즘 — 브라우저가 자동으로 요청에 쿼기를 보내고, 서버는 정상 요청과 위조된 요청을 구분하지 못함
  • 주요 유형 — GET 기반 (<img> 통해), POST 기반(숨긴 폼 통해), XHR 기반(CORS 통해)
  • 모바일 특정 — 하이브리드 앱에서 WebView와 쿼기 인증이 CSRF 위험을 생성함
  • CSRF 토큰 — 모든 프레임워크에서 지원되는 가장 신뢰할 수 있는 보호 방법
  • SameSite=Lax — 브라우저 레벨의 자동 보호, 기본으로 사용으로 설정됨
  • 조합 보호 — 토큰 + SameSite + Origin 확인으로 CSRF 공격의 99% 차단

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기