반응형
Jake Seo
제이크서 위키 블로그
Jake Seo
전체 방문자
오늘
어제
  • 분류 전체보기 (715)
    • 일상, 일기 (0)
    • 백준 문제풀이 (1)
    • 릿코드 문제풀이 (2)
    • 알고리즘 이론 (10)
      • 기본 이론 (2)
      • 배열과 문자열 (8)
    • 데이터베이스 (15)
      • Planet Scale (1)
      • MSSQL (9)
      • 디비 기본 개념 (1)
      • SQLite 직접 만들어보기 (4)
    • 보안 (7)
    • 설계 (1)
    • 네트워크 (17)
      • HTTP (9)
      • OSI Layers (5)
    • 회고 (31)
      • 연간 회고 (2)
      • 주간 회고 (29)
    • 인프라 (52)
      • 도커 (12)
      • AWS (9)
      • 용어 (21)
      • 웹 성능 (1)
      • 대규모 서비스를 지탱하는 기술 (9)
    • 깃 (7)
    • 빌드 도구 (7)
      • 메이븐 (6)
      • 그레이들 (0)
    • Java (135)
      • 이펙티브 자바 (73)
      • 자바 API (4)
      • 자바 잡지식 (30)
      • 자바 디자인 패턴 (21)
      • 톰캣 (Tomcat) (7)
    • 프레임워크 (64)
      • next.js (14)
      • 스프링 프레임워크 (28)
      • 토비의 스프링 (6)
      • 스프링 부트 (3)
      • JPA (Java Persistence API) (5)
      • Nest.js (8)
    • 프론트엔드 (48)
      • 다크모드 (1)
      • 노드 패키지 관리 매니저 (3)
      • CSS (19)
      • Web API (11)
      • tailwind-css (1)
      • React (5)
      • React 새 공식문서 요약 (1)
      • HTML (Markup Language) (5)
    • 자바스크립트 (108)
      • 모던 자바스크립트 (31)
      • 개념 (31)
      • 정규표현식 (5)
      • 코드 스니펫 (1)
      • 라이브러리 (6)
      • 인터뷰 (24)
      • 웹개발자를 위한 자바스크립트의 모든 것 (6)
      • 팁 (2)
    • Typescript (49)
    • 리눅스와 유닉스 (10)
    • Computer Science (1)
      • Compiler (1)
    • IDE (3)
      • VSCODE (1)
      • IntelliJ (2)
    • 세미나 & 컨퍼런스 (1)
    • 용어 (개발용어) (16)
      • 함수형 프로그래밍 용어들 (1)
    • ORM (2)
      • Prisma (2)
    • NODEJS (2)
    • cypress (1)
    • 리액트 네이티브 (React Native) (31)
    • 러스트 (Rust) (15)
    • 코틀린 (Kotlin) (4)
      • 자바에서 코틀린으로 (4)
    • 정규표현식 (3)
    • 구글 애널리틱스 (GA) (1)
    • SEO (2)
    • UML (2)
    • 맛탐험 (2)
    • 리팩토링 (1)
    • 서평 (2)
    • 소프트웨어 공학 (18)
      • 테스팅 (16)
      • 개발 프로세스 (1)
    • 교육학 (1)
    • 삶의 지혜, 통찰 (1)
    • Chat GPT (2)
    • 쉘스크립트 (1)
    • 컴파일 (2)
    • Dart (12)
    • 코드팩토리의 플러터 프로그래밍 (4)
    • 플러터 (17)
    • 안드로이드 스튜디오 (1)
    • 윈도우즈 (1)
    • 잡다한 백엔드 지식 (1)
    • 디자인 패턴 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 이펙티브자바
  • 작업기억공간
  • 자바
  • 도커공식문서
  • 러스트
  • next js app
  • 메이븐 라이프사이클
  • 자바스크립트 면접
  • 싱글톤 패턴
  • 이펙티브 자바 item9
  • 스프링 검증
  • 팩터리 메서드 패턴
  • Java
  • 자바스크립트 인터뷰
  • 자바 검증
  • 싱글톤
  • 객체복사
  • 플라이웨이트패턴
  • 외래키 제약조건
  • 느린 쿼리
  • 디자인패턴
  • 서버리스 컴퓨팅
  • 슬로우 쿼리
  • 이펙티브 자바
  • serverless computing
  • 빈 검증
  • try-with-resources
  • 알고리즘
  • 메이븐 골
  • 추상 팩터리 패턴
  • rust
  • 프로그래머의 뇌
  • 메이븐 페이즈
  • 자바스크립트
  • 자바 디자인패턴
  • Next.js
  • item9
  • prerendering
  • 토비의 스프링
  • MSSQL
  • item8
  • pnpm
  • Javadoc 자바독 자바주석 주석 Comment
  • 참조 해제
  • item7
  • NEXT JS
  • bean Validation
  • Pre-rendering
  • 싱글턴
  • 자료구조

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jake Seo

제이크서 위키 블로그

보안

CSRF 공격 정리 (feat. 스프링 시큐리티)

2022. 5. 3. 21:50

CSRF 란?

Cross-Site Request Forgery 라고 불리는 공격 방법이다. 웹사이트 취약점 공격의 일종이다. 특정 웹사이트에 로그인된 상태에서 해커가 원하는 URL 에 접근하게 만든다.

공격 주요 개념 정리

  • 브라우저가 SESSION ID 등의 인증정보를 가지고 있는 것을 활용하는 것이다.
  • 브라우저를 사용하지 않으면, 요청 시마다 인증정보를 수동으로 입력해줘야 하기 때문에 보통은 CSRF 공격에 당하지 않는다.
    • 그러나 이 역시도 애플리케이션에서 인증 상태를 저장하고 있다면, 브라우저와 동일하게 취약하다.

해킹 시나리오

시나리오 1. GET 요청의 경우

  • 피해자는 브라우저를 통해 https://any-bank-site.com/ 웹사이트에 접속하고 로그인한 상태이다.
  • 브라우저에는 로그인을 통해 생성된 인증정보를 가지고 있다. ex) JESSIONID=xxxx
    • 이로 인해 이용자는 로그인을 한번만 해도 모든 페이지에서 로그인된 효과를 받을 수 있다.
  • 이 웹사이트에는 게시판이 있고, 게시판은 HTML 태그가 허용되어 있다.
  • 사이트 이용 도중 피해자는 해커가 올린 게시물을 보게 된다.
  • 게시물에는 이미지가 있었고, 이미지는 다음과 같은 태그를 가지고 있다.
    <img src="https://any-bank-site.com/sendMoney?to=hacker&amount=100000">
  • 이는 사실 해커가 미리 알아낸 송금 URL이다. hacker 에게 100000 원을 보내게 만드는 행위를 하게 만드는 것이다.
  • img 태그의 src 에 있는 주소는 브라우저에 의해 해석될 때 자동으로 GET 요청이 가게 된다.
  • 브라우저는 은행 인증에 필요한 인증정보를 저장하고 있었기 때문에 위의 요청은 정상적으로 수행된다.
  • 피해자는 자신도 모르는 사이에 돈이 송금되어 버린다.

시나리오 2. POST 요청의 경우

  • 피해자는 이번에도 브라우저를 통해 https://any-bank-site.com/ 웹사이트에 로그인한 상태이다.

  • 브라우저에는 피해자가 로그인하면서 생성한 인증정보를 가지고 있다. ex) JESSIONID=xxxx

  • 은행 웹사이트에서 보안에 대한 고려를 하여, GET 이 아닌 POST 요청을 날렸을 때만 송금이 이루어지게 했다.

  • 은행 웹사이트에서는 송금을 위해 다음과 같은 폼을 제공한다.

    <form method="post"
      action="/transfer">
    <input type="text"
      name="amount"/>
    <input type="text"
      name="routingNumber"/>
    <input type="text"
      name="account"/>
    <input type="submit"
      value="Transfer"/>
    </form>
  • 위의 폼을 제출하면 아래와 같은 HTTP 요청이 발생하여 송금이 되는 형태이다.

POST /transfer HTTP/1.1
Host: any-bank-site.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876
  • 해커는 이 구조를 이해하고 자신이 작성한 게시글에 숨겨진 폼을 만들어놓는다.
<form method="post"
    action="https://any-bank-site.com/transfer">
<input type="hidden"
    name="amount"
    value="100.00"/>
<input type="hidden"
    name="routingNumber"
    value="evilsRoutingNumber"/>
<input type="hidden"
    name="account"
    value="evilsAccountNumber"/>
<input type="submit"
    value="Win Money!"/>
</form>
  • 해커는 피해자가 댓글 작성 시에 저 폼이 함께 제출되도록 해놓은 상태이다.
  • 만일 피해자가 해커의 게시글에서 댓글을 달게 되면, 의도치 않게 돈이 송금될 것이다.

CSRF 방지의 핵심

핵심은 공격자 도메인에서의 외부 요청과 서비스 웹사이트 상의 실제 요청을 구분하는 것이다. 이 두 요청을 구분할 수 없다면 CSRF 공격에 취약해질 수 있다.

스프링 시큐리티에서의 CSRF 방지 방법

스프링에서는 2가지 매커니즘으로 CSRF 공격을 막는다.

  • Synchronizer Token Pattern
  • 세션 쿠키에 SameSite 속성 주기

멱등성을 지켜야 한다

멱등성을 지킨다는 것은 GET, HEAD, OPTIONS, TRACE 요청이 있을 때, 애플리케이션의 상태를 변화시키지 않는 것을 말한다. 이 요청을 몇번이고 수행해도 애플리케이션의 상태는 동일해야 한다. 그래야 이후에 설명할 Synchronizer Token Pattern 을 적용하는 효과가 있다.

Synchronizer Token Pattern 알아보기

Synchronizer Token Pattern 은 CSRF 방지를 위해 가장 많이 쓰이는 방법이다. 각 HTTP 요청이 세션 쿠키와 더불어 랜덤으로 생성된 CSRF 토큰을 포함하고 있는지 확인하는 방법이다.

요청이 왔을 때, 서버에서 CSRF 토큰을 확인하지 못하면, HTTP 요청이 거부된다.

다만 멱등성이 보장되어야 이 방법이 효과가 있다. 그래야 다른 곳에서 들어온 GET 요청을 수용할 수 있고, 우리가 GET 요청을 할 때는 CSRF 토큰이 필요 없으므로, CSRF 토큰의 유출도 막을 수 있다.

<form method="post"
    action="/transfer">
<input type="hidden"
    name="_csrf"
    value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
<input type="text"
    name="amount"/>
<input type="text"
    name="routingNumber"/>
<input type="hidden"
    name="account"/>
<input type="submit"
    value="Transfer"/>
</form>

위와 같이 _csrf 라는 토큰 값을 함께 보내야 요청이 유효하다.

POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2d9f86721

해커는 올바른 _csrf 값을 생성할 수 없을 것이다.

SameSite Attribute 알아보기

외부 사이트에서 들어오는 경우, 쿠키가 함께 보내지지 않을 것이라고 나타내는 SameSite 속성을 명시할 수 있다.

스프링 시큐리티의 경우엔 세션 쿠키의 생성을 직접 다루지 않기 때문에, SameSite 속성을 지원하진 않는다. 그러나 Spring Session은 서블릿을 기반으로 한 애플리케이션에 SameSite 속성을 지원한다. 스프링 프레임워크의 CookieWebSessionIdResolver 는 WebFlux 를 베이스로 한 애플리케이션에서 SameSite 속성을 지원한다.

Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax

CSRF 보호를 비활성화(disable) 하는 경우?

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

일반 웹사이트처럼 브라우저 유저가 요청을 하는 것이 아니라, 브라우저가 아닌 애플리케이션의 클라이언트가 이용하는 경우에는 CSRF 를 비활성화 할 수 있다. 그러나 이 경우에도 CSRF 의 위협에서 무조건 안전하다고 할 수만은 없다. 만일 상태가 있는 어플리케이션인 경우에는 CSRF 공격을 받으면 브라우저에서 공격을 받는 것과 동일한 효과를 가지기 때문에 조심해야 한다.

레퍼런스

CODEPATH CSRF
스프링 시큐리티 CSRF

반응형
저작자표시 (새창열림)

'보안' 카테고리의 다른 글

스프링 시큐리티에서 Authority 와 Role 의 차이는?  (2) 2023.12.05
리프레시 토큰 (refresh token) 을 사용하는 이유를 알아보자  (0) 2022.10.13
Method Security of 스프링 시큐리티  (0) 2022.05.07
JWT(Json Web Token) 이란 무엇이며 왜 사용하는가?  (0) 2022.05.03
인증 (Authentication) 과 인가 (Authorization) 의 차이를 알아보자.  (0) 2022.05.02
    '보안' 카테고리의 다른 글
    • 리프레시 토큰 (refresh token) 을 사용하는 이유를 알아보자
    • Method Security of 스프링 시큐리티
    • JWT(Json Web Token) 이란 무엇이며 왜 사용하는가?
    • 인증 (Authentication) 과 인가 (Authorization) 의 차이를 알아보자.
    Jake Seo
    Jake Seo
    ✔ 잘 보셨다면 광고 한번 클릭해주시면 큰 힘이 됩니다. ✔ 댓글로 틀린 부분을 지적해주시면 기분 나빠하지 않고 수정합니다. ✔ 많은 퇴고를 거친 글이 좋은 글이 된다고 생각합니다. ✔ 간결하고 명료하게 사람들을 이해 시키는 것을 목표로 합니다.

    티스토리툴바