CSRF 토큰이란 무엇입니까? 그 중요성은 무엇이며 어떻게 작동합니까?


628

응용 프로그램을 작성하고 있습니다 (Django, 그렇게됩니다). 실제로 "CSRF 토큰"이 무엇이며 어떻게 데이터를 보호하는지에 대한 아이디어가 필요합니다. CSRF 토큰을 사용하지 않으면 게시물 데이터가 안전하지 않습니까?


13
사이트 간 요청 위조를 방지하기 위해 모든 양식 제출 및 부작용 URL의 비밀 사용자 별 토큰입니다. 자세한 정보는 여기 : en.wikipedia.org/wiki/Cross-site_request_forgery
Robert Harvey

1
질문을 보호 하고 너무 광범위하다는 이유로 금지하는 것 사이에는 미세한 선이있는 것 같습니다 : D
anton1980

2
에서 OWASP 사이트 간 요청 위조 (CSRF) 방지 치트 시트 : " 사이트 간 스크립팅 작업에 CSRF 필요하지 않습니다하지만, 어떤 크로스 사이트 스크립팅 취약점이 모든 CSRF 완화 기술을 격파하는 데 사용할 수있는 [...].. 이는 XSS 페이로드가 XMLHttpRequest [...]를 사용하여 사이트의 모든 페이지를 간단하게 읽을 수 있기 때문입니다. CSRF 방어를 우회 할 수있는 XSS 취약점이 없어야합니다. "
toraritte

답변:


1497

간단한 단어로 된 CSRF (Cross-Site Request Forgery)

  • 현재 온라인 뱅킹에 로그인했다고 가정합니다. www.mybank.com
  • 에서 송금 mybank.com이 (개념적으로) 양식을 요청 한다고 가정합니다 http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (계정 번호는 로그인에 암시되어 있기 때문에 필요하지 않습니다.)
  • www.cute-cat-pictures.org사이트는 악의적 인 사이트임을 모르면서을 (를) 방문 합니다.
  • 해당 사이트의 소유자가 위의 요청 양식을 알고 (쉽게!) 귀하가 로그인 한 것으로 정확하게 추측하면 mybank.com(행운이 필요합니다!), 페이지에 http://www.mybank.com/transfer?to=123456;amount=10000( 123456케이맨 제도 계정의 수는 그리고 10000당신이 이전에 생각했던되는 양입니다 기쁜 ) 소유하기는.
  • 당신 이 검색 할 www.cute-cat-pictures.org수 있도록 페이지를 사용자의 브라우저가 해당 요청을 만들 것입니다.
  • 귀하의 거래 은행은이 요청의 출처를 인식 할 수 없습니다 : 귀하의 웹 브라우저는 www.mybank.com쿠키와 함께 요청을 보내며 완벽하게 합법적으로 보입니다. 돈이 간다!

이것이 CSRF 토큰이없는 세상 입니다.

이제 더 나은 하나 CSRF는 토큰 :

  • 전송 요청은 세 번째 인수로 확장됩니다 http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • 이 토큰은 거대하고 추측하기 어려운 임의의 숫자 mybank.com로, 사용자에게 웹 페이지를 제공 할 때 자체 웹 페이지에 포함됩니다. 그것은이다 다른 그들이 누구에 모든 페이지를 제공 할 때마다.
  • 공격자는 토큰을 추측 할 수없고, 웹 브라우저가 토큰을 항복하도록 설득 할 수 없으며 (브라우저가 올바르게 작동하는 경우) 공격자가 유효한 요청을 작성할 수 없습니다 . 에 의해 잘못된 토큰 (또는 토큰이 없음)이 거부됩니다 www.mybank.com.

결과 : 10000화폐 단위를 유지합니다 . 그 중 일부를 Wikipedia에 기부 할 것을 제안합니다.

(귀하의 마일리지가 다를 수 있습니다.)

읽을 가치가있는 주석에서 편집 :

HTTP 액세스 제어로 인해 www.cute-cat-pictures.org일반적으로 스크립트가 안티 CSRF 토큰에 액세스 할 수 없다는 점에 유의해야합니다 www.mybank.com. 이 메모는 Access-Control-Allow-Origin: *다른 웹 사이트의 API를 사용할 수 없기 때문에 모든 웹 사이트 응답에 대한 헤더 를 부당하게 보내는 것이 중요합니다 .


36
그리고 분명히 토큰 의 이름은 anti- CSRF 토큰으로 지정되지만 이름은 아마도 복잡 할 것입니다.
Lutz Prechelt

3
@LutzPrechelt 감사합니다. Javascript가 브라우저에서 인증 토큰을 얻을 수없는 이유는 무엇입니까?
BKSpurgeon

72
HTTP 액세스 제어로 인해 www.cute-cat-pictures.org일반적으로 스크립트가 안티 CSRF 토큰에 액세스 할 수 없다는 점에 유의해야합니다 www.mybank.com. 이 메모는 Access-Control-Allow-Origin: *다른 웹 사이트의 API를 사용할 수 없기 때문에 모든 웹 사이트 응답에 대한 헤더 를 부당하게 보내는 것이 중요합니다 .
SOFe

9
@AugustinRiedinger 침입자가 로그인 한 사용자의 쿠키가 없기 때문에 자신의 컴퓨터에서 웹 페이지를 열면 해당 csrf 토큰을받지 못합니다 (각 csrf 토큰은 특정 사용자 세션에 대해서만 유효해야 함). 공격자가 cute-cat-pictures 웹 사이트에 스크립트를 사용하여 사용자 컴퓨터에 토큰이 포함 된 웹 페이지를로드하려고 시도하면 브라우저에서 웹 사이트를 통해 www.mybank.com (및 토큰)을 읽지 못하게됩니다. 동일한 원산지 정책.
Marcel

13
@LutzPrechelt 토큰이 항상 다르면 충분하지 않다고 생각합니다. 세션과 쌍을 이루어야하며 서버는 수신 된 쿠키로 서버가 식별하는 세션에 대해 토큰이 수신했는지 확인해야합니다. 그렇지 않으면 해커가 mybank를 직접 방문하여 유효한 토큰을 얻을 수 있습니다. 따라서 모든 양식에 새 토큰을 사용하는 경우 서버의 sessionid와 쌍으로 저장해야합니다. 세션 당 동일한 토큰을 사용하는 것이 더 쉽습니다.
Marcel

222

예, 게시물 데이터는 안전합니다. 그러나 그 데이터의 기원은 아닙니다. 이런 식으로 누군가가 JS를 사용하는 사용자가 침입자의 웹 페이지를 탐색하면서 사이트에 로그인하도록 속일 수 있습니다.

이를 방지하기 위해 django는 쿠키와 양식 데이터 모두에서 임의의 키를 보냅니다. 그런 다음 사용자가 POST를 수행하면 두 개의 키가 동일한 지 확인합니다. 사용자가 속인 경우 타사 웹 사이트에서 사이트 쿠키를 얻을 수 없으므로 인증 오류가 발생합니다.


@DmitryShevchenko 안녕하세요,이 쿠키 + 양식 입력 방법이 서버 측에서 리퍼러를 확인하는 것과 어떻게 다른지 이해하려고합니까? 내가 찾은 모든 예제는 사용자가 자신의 사이트에서 실제 사이트로 게시하도록 속이는 해커와 관련이 있습니다.
Ethan

좋아, 리퍼러가 사용되지 않는 이유를 알았습니다. 민감한 정보를 간혹 보유하는 것으로 간주되어 많은 경우 차단됩니다. 기업과 프록시는 일반적으로 그렇게합니다. 그러나 HTTPS가 사용되면 차단되지 않을 가능성이 높습니다.
Ethan

4
리퍼러를 변경하는 것은 쉽지만 신뢰할만한 정보라고는 말할 수 없습니다. 그러나 CSRF 토큰은 서버 비밀 키를 사용하여 생성되며 일반적으로 사용자와 연결되어 있습니다.
Dmitry Shevchenko

1
이것이 왜 보안 위협인지 이해하지 못합니다. 사용자는 다른 사이트에 로그인 할 수 있지만 원래 사이트에는 해당 정보를 검색 할 수있는 방법이 없습니다. 권리?
Aakil Fernandes

6
예를 들어 Facebook.com 에 " bank.com/transfer?from=x&to=y " 의 악성 iframe을 삽입한다고 가정하겠습니다 . bank.com의 고객이고 Facebook으로 이동하면 iframe은 쿠키와 함께 은행 페이지를로드하고 (브라우저가 알려진 도메인으로 쿠키를 전송하기 때문에) 송금합니다. 당신이 아무것도 몰라도
Dmitry Shevchenko

74

사이트는 양식 페이지를 만들 때 고유 한 토큰을 생성합니다. 이 토큰은 서버에 데이터를 다시 게시하거나 가져 오는 데 필요합니다.

토큰은 사이트에서 생성되고 양식이있는 페이지가 생성 될 때만 제공되므로 다른 사이트는 양식을 모방 할 수 없습니다. 토큰이 없어서 사이트에 게시 할 수 없습니다.


10
사용자가 소스 내에서 토큰 출력을 가져 와서 보낸 쿠키를 가져온 다음 타사 사이트에서 제출할 수 있습니까?
Jack Marchetti

9
@JackMarchetti 예. 그러나 타사 사이트에서 양식을 제출할 때마다 페이지를로드하고 토큰을 파싱해야하므로 비용이 많이 듭니다. CSRF 토큰은이 공격 벡터에 관심이있는 경우 다른 형태의 보안과 이상적으로 결합되어야합니다.
tkone

4
@JackMarchetti와 동일한 질문이 있습니다. 각 로그인마다 CSRF 토큰이 변경되면 명확하지 않습니다. 동일하게 유지되면 공격자가 먼저 로그인하여 요청 토큰을 잡고 공격에 해당 토큰을 삽입하지 못하게하는 방법은 무엇입니까?
Paul Preibisch

7
@PaulPreibisch 각 로그인이 아닌 각 페이지로드마다 변경되어야합니다. 이런 식으로 공격자는 양식을 제출할 때마다 페이지를 요청해야합니다. 훨씬 더 어렵게 만듭니다.
tkone

9
@ tkone, 그것은 실제로 훨씬 더 어렵게하지 않습니다. 노력과 시간을 두 배로 늘리면 금지 처리를 추가하지 않습니다. 이 트릭은 CSRF 토큰을 도메인 별 쿠키에 연결하고이 쿠키를 양식과 함께 전송합니다. 쿠키와 양식 게시 데이터는 모두 POST 요청시 서버로 전송되어야합니다. 이런 식으로 쿠키 하이재킹 공격이 합법적 인 요청을 에뮬레이트 할 수 있어야합니다.
Pedro Cordeiro

55

Cloud Under 블로그에는 CSRF 토큰에 대한 좋은 설명이 있습니다.

a.com에서 호스팅되는 간단한 Twitter와 같은 웹 사이트가 있다고 가정합니다. 로그인 한 사용자는 POST 요청으로 서버에 전송되는 양식에 일부 텍스트 (트위트)를 입력하고 제출 버튼을 눌렀을 때 게시 할 수 있습니다. 서버에서 사용자는 고유 한 세션 ID가 포함 된 쿠키로 식별되므로 사용자는 트윗을 게시 한 사람을 알 수 있습니다.

형식은 다음과 같이 간단 할 수 있습니다.

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

이제 나쁜 사람이이 양식을 자신의 악성 웹 사이트에 복사하여 붙여 넣는다 고 상상해 봅시다. b.com이라고 가정하겠습니다. 양식은 여전히 ​​작동합니다. 사용자가 Twitter에 로그인 한 경우 (즉, a.com에 유효한 세션 쿠키가있는 http://a.com/tweet경우) 사용자가 제출 버튼을 클릭 할 때 POST 요청이 평소와 같이 보내 지고 처리됩니다.

지금까지 사용자가 양식이 정확히 무엇을하는지 알고있는 한 큰 문제는 아니지만 나쁜 사람이 다음과 같이 양식을 조정하면 어떻게됩니까?

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

이제 사용자 중 한 명이 나쁜 사람의 웹 사이트에 접속하여 "클릭하여 승리하십시오!" 버튼을 클릭하면 양식이 웹 사이트에 제출되고 쿠키의 세션 ID로 사용자가 올바르게 식별되고 숨겨진 트윗이 게시됩니다.

우리의 나쁜 사람이 더 나쁘다면, 그는 무고한 사용자가 JavaScript를 사용하여 웹 페이지를 열 자마자이 양식을 제출하게 할 것입니다. 심지어 보이지 않는 iframe에 완전히 숨겨져있을 수도 있습니다. 이것은 기본적으로 사이트 간 요청 위조입니다.

어디서나 쉽게 양식을 제출할 수 있습니다. 일반적으로 이는 일반적인 기능이지만 해당 도메인에서만 양식을 제출하도록 허용하는 것이 더 중요한 경우가 더 많습니다.

웹 애플리케이션이 POST 요청과 GET 요청을 구분하지 않으면 상황이 더욱 악화됩니다 (예 : $ _POST 대신 $ _REQUEST를 사용하여 PHP에서). 하지마! 데이터 변경 요청은 <img src="http://a.com/tweet?tweet=This+is+really+bad">악의적 인 웹 사이트 나 이메일에 포함 된 것처럼 쉽게 제출할 수 있습니다 .

내 웹 사이트에서만 양식을 제출할 수 있도록하려면 어떻게해야합니까? 이것은 CSRF 토큰이 들어오는 곳입니다. CSRF 토큰은 추측하기 어려운 무작위 문자열입니다. 보호하려는 양식이있는 페이지에서 서버는 임의 문자열 인 CSRF 토큰을 생성하여 양식에 숨겨진 필드로 추가하고 세션에 저장하거나 쿠키를 설정하여 어떻게 든 기억합니다. 값을 포함합니다. 이제 양식은 다음과 같습니다.

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

사용자가 양식을 제출하면 서버는 게시 된 필드 csrf-token (이름은 중요하지 않음)의 값을 서버가 기억하는 CSRF 토큰과 비교하기 만하면됩니다. 두 문자열이 같으면 서버가 양식을 계속 처리 할 수 ​​있습니다. 그렇지 않으면 서버는 즉시 양식 처리를 중지하고 오류로 응답해야합니다.

왜 이것이 작동합니까? 위의 예제에서 나쁜 사람이 CSRF 토큰을 얻을 수없는 데는 몇 가지 이유가 있습니다.

숨겨진 필드의 값이 각 사용자마다 다르기 때문에 정적 소스 코드를 페이지에서 다른 웹 사이트로 복사하는 것은 쓸모가 없습니다. 나쁜 사용자의 웹 사이트가 현재 사용자의 CSRF 토큰을 알지 못하면 서버는 항상 POST 요청을 거부합니다.

악의적 인 사용자의 악의적 인 페이지가 사용자의 브라우저에 의해 다른 도메인 (a.com 대신 b.com)에서로드되기 때문에 악의적 인 사용자는 JavaScript를 코딩 할 기회가 없으므로 콘텐츠를로드하여 사용자의 현재 CSRF 토큰을 귀하의 웹 사이트. 웹 브라우저는 기본적으로 도메인 간 AJAX 요청을 허용하지 않기 때문입니다.

도메인이 일치하지 않기 때문에 악의적 인 사용자도 서버에서 설정 한 쿠키에 액세스 할 수 없습니다.

교차 사이트 요청 위조로부터 언제 보호해야합니까? 위에서 설명한대로 GET, POST 및 기타 요청 방법을 혼합하지 않도록하려면 기본적으로 모든 POST 요청을 보호하는 것이 좋습니다.

PUT 및 DELETE 요청을 보호 할 필요는 없습니다. 위에서 설명한 것처럼 표준 HTML 양식은 이러한 방법을 사용하여 브라우저에서 제출할 수 없기 때문입니다.

반면에 JavaScript는 실제로 jQuery의 $ .ajax () 함수를 사용하여 다른 유형의 요청을 할 수 있지만 AJAX 요청이 작동하려면 도메인이 일치해야합니다 (웹 서버를 명시 적으로 구성하지 않는 한) .

즉, POST 요청 인 경우에도 AJAX 요청에 CSRF 토큰을 추가 할 필요는 없지만 POST 요청이 실제로는 웹 애플리케이션 인 경우 CSRF 검사 만 우회해야합니다. AJAX 요청. AJAX 요청에 일반적으로 포함되는 X-Requested-With와 같은 헤더가 있는지 찾아서이를 수행 할 수 있습니다. 다른 사용자 정의 헤더를 설정하고 서버 측에 존재하는지 확인할 수도 있습니다. 브라우저가 일반 HTML 양식 제출에 사용자 정의 헤더를 추가하지 않기 때문에 안전합니다 (위 참조).

AJAX 요청에 대해 확실하지 않은 경우 어떤 이유로 X-Requested-With와 같은 헤더를 확인할 수 없으므로 생성 된 CSRF 토큰을 JavaScript에 전달하고 토큰을 AJAX 요청에 추가하십시오. 이를 수행하는 몇 가지 방법이 있습니다. 일반 HTML 양식처럼 페이로드에 추가하거나 AJAX 요청에 사용자 정의 헤더를 추가하십시오. 서버가 들어오는 요청에서 찾을 위치를 알고 세션 또는 쿠키에서 기억하는 원래 값과 비교할 수있는 한 정렬됩니다.


자세한 정보에 감사드립니다. 게시 요청 중에 사이트는 csrf 토큰을 서버로 보내야하므로 클라이언트는 언제이 csrf 토큰을 서버로 보냅니 까? 프리 플라이트 옵션을 요청하는 동안입니까? 이 부분에 elablorate하십시오 ..
SM 스리 칸스에게

@Dan 어떻게 b.com이 다른 사이트 a.com의 쿠키에 액세스 할 수 있습니까?
zakir

8

그 근원은 요청이 사이트의 실제 사용자로부터 오는 것인지 확인하는 것입니다. 양식에 대해 csrf 토큰이 생성되며 사용자 세션에 연결되어야합니다. 토큰이 요청을 확인하는 서버로 요청을 보내는 데 사용됩니다. 이것은 csrf로부터 보호하는 한 가지 방법이며 다른 방법은 리퍼러 헤더를 확인하는 것입니다.


7
참조 헤더에 의존하지 마십시오. 쉽게 위조 될 수 있습니다.
kag

3
이것이 정답입니다! 토큰은 반드시 서버의 세션에 연결되어야합니다. 가장 많이 투표 된 답변과 같은 쿠키 + 양식 데이터를 비교하는 것은 완전히 잘못되었습니다. 이 구성 요소는 모두 클라이언트가 구성하는 요청의 일부를 구성합니다.
Lee Davis

3
사실은 아닙니다. 토큰은 서버에 대한 각 요청에 연결되어야합니다. 세션에만 연결하면 세션 토큰을 훔쳐 해당 토큰으로 요청을 제출할 위험이 있습니다. 따라서 최대 안전을 위해 토큰은 각 http 요청에 연결되어야합니다.
chrisl08
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.