응용 프로그램을 작성하고 있습니다 (Django, 그렇게됩니다). 실제로 "CSRF 토큰"이 무엇이며 어떻게 데이터를 보호하는지에 대한 아이디어가 필요합니다. CSRF 토큰을 사용하지 않으면 게시물 데이터가 안전하지 않습니까?
응용 프로그램을 작성하고 있습니다 (Django, 그렇게됩니다). 실제로 "CSRF 토큰"이 무엇이며 어떻게 데이터를 보호하는지에 대한 아이디어가 필요합니다. CSRF 토큰을 사용하지 않으면 게시물 데이터가 안전하지 않습니까?
답변:
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를 사용할 수 없기 때문에 모든 웹 사이트 응답에 대한 헤더 를 부당하게 보내는 것이 중요합니다 .
www.cute-cat-pictures.org
일반적으로 스크립트가 안티 CSRF 토큰에 액세스 할 수 없다는 점에 유의해야합니다 www.mybank.com
. 이 메모는 Access-Control-Allow-Origin: *
다른 웹 사이트의 API를 사용할 수 없기 때문에 모든 웹 사이트 응답에 대한 헤더 를 부당하게 보내는 것이 중요합니다 .
예, 게시물 데이터는 안전합니다. 그러나 그 데이터의 기원은 아닙니다. 이런 식으로 누군가가 JS를 사용하는 사용자가 침입자의 웹 페이지를 탐색하면서 사이트에 로그인하도록 속일 수 있습니다.
이를 방지하기 위해 django는 쿠키와 양식 데이터 모두에서 임의의 키를 보냅니다. 그런 다음 사용자가 POST를 수행하면 두 개의 키가 동일한 지 확인합니다. 사용자가 속인 경우 타사 웹 사이트에서 사이트 쿠키를 얻을 수 없으므로 인증 오류가 발생합니다.
사이트는 양식 페이지를 만들 때 고유 한 토큰을 생성합니다. 이 토큰은 서버에 데이터를 다시 게시하거나 가져 오는 데 필요합니다.
토큰은 사이트에서 생성되고 양식이있는 페이지가 생성 될 때만 제공되므로 다른 사이트는 양식을 모방 할 수 없습니다. 토큰이 없어서 사이트에 게시 할 수 없습니다.
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로부터 보호하는 한 가지 방법이며 다른 방법은 리퍼러 헤더를 확인하는 것입니다.