Cross-Site Request Forgeries - 7, 8
Automatic support from frameworks
CSRF 방지
- Angular : 인터셉터가 기본적으로 XSRF-TOKEN 쿠키에서 토큰을 읽고 HTTP 헤더(X-XSRF-TOKEN)로 설정
- 내부에서만 확인 가능한 쿠키를 외부에서 알 수 없기 때문에 csrf 방지가 가능하다고 한다.
- 세션은 http-only flag로 되어 있으면 js로 열람 불가능하다. => httponly를 설정하면 보안측면에서 더 유리하다.
Custom headers not safe
- header에 custom request header를 추가한다.
- 이 헤더 없으면 요청 거부한다.
- but 회피 가능하다는 사실 알려짐.
But I only have JSON APIs and no CORS enabled, how can those be susceptible to CSRF?
많은 웹 응용 프로그램은 CSRF에 대한 보호기능을 구현하지 않으며 컨텐츠 유형으로 application/json만 지정하여 보호한다. 브라우저에서 이 컨텐츠 유형을 사용하여 요청하는 유일한 방법은 XHR을 이용하는 것이다.
브라우저가 이러한 요청을 하기전에 서버를 향해 pre-flight(사전요청)을 전송한다. 만약 pre-flight 요청에 대한 응답에 cross origin를 허용하지 않는다는 내용이 있다면, 브라우저는 XHR 요청을 보내지 않게 된다.
=> json만 받겟다고 지정했다는게 csrf를 막을 수 있다는 것을 의미하진 못한다.
* XHR : XMLHttpRequest 객체로 통신 - AJAX 요청을 생성하는 JS API. XHR 메서드로 브라우저와 서버간의 네트워크 요청 전송 가능
* AJAX : Asyschronous JS and XML - 서버와 비동기 통신, 전체 페이지가 다시 로드되지 않고 일부분만 업데이트 가능
* pre-flight 요청 : HTTP 메소드 중 OPTIONS 메소드 사용, 원하는 경로에 CORS 활성화 여부 확인
* CORS : 한 origin에서 다른 origin으로 접근 가능한 권한을 부여하도록 브라우저에 알려주는 체제
Navigator.sendBeacon()이 요청 전송 시 POST 메소드와 임의의 content-type을 사용하여 CORS 활성화를 우회할 수 있다. (https://bugs.chromium.org/p/chromium/issues/detail?id=490015)
function postBeacon() {
var data= new Blob([JSON.stringify({"author" :"WebGoat"})], {type : 'application/json'});
navigator.sendBeacon("http://localhost:8083", data)
}
이렇게 json만 가능하도록 지정해뒀기 때문에 CORS 활성화를 했다면 막혀야하는게 맞는데 안 막히고 우회 가능하더라~
Content-Type 제한(application/json)은 CSRF에 대해 우연히 안전해지는 것으로 생각된다. XML 혹은 JSON 타입의 페이로드만 허용하기 때문이다.
* 정리 (inflearn) : 이전 실습대로라면 GET과 POST 방식으로 CSRF를 시도했었고 성공하였다. 그런데 서버에서 JSON이나 XML만 받는다면 XHR을 이용하여 요청을 전송해야 할 것인데, 이 방식은 pre-flight 요청을 먼저 보내게 될 것이고 이 때 CORS가 활성화 되어 있다면 거부 응답을 받을 것이므로, 반드시 cross origin이 요구되는 CSRF 공격은 불가능해진다. 그러나 navigator.sendBeacon() 함수를 사용하면 JSON 형태로 데이터를 전송하면서도 CORS 활성화 설정이 우회된다.
[ 문제 ]
content-type이 CSRF에 대한 보호가 아니다. 이 섹션에서는 CSRF에 대해 보호되지 않는 API에 대해 CSRF 공격을 수행할 수 있는 다른 방법을 살펴본다.
이 과제에서 다음 JSON 메시지를 엔드포인트에 게시하려면 다음을 수행해야한다.
POST /csrf/feedback/message HTTP/1.1
{
"name" : "WebGoat",
"email" : "webgoat@webgoat.org",
"content" : "WebGoat is the best!!"
}
다른 origin에서 호출되도록 만들어야한다는 것을 기억해라.
application/json을 text/plain
Login CSRF attack
로그인 CSRF 공격 시, 공격자는 자신의 ID/PW를 이용하여 희생자로 하여금 로그인 요청 메시지를 전송하게 만든다. 만약 공격이 성공하면, 서버는 헤더에 "Set-Cookie" 항목(브라우저에 세션 쿠키 저장을 지시)을 포함하여 희생자에게 응답한다.
그러면 희생자는 공격자의 계정으로 로그인한다. 이 세션 쿠키는, 이후의 요청 메시지를 대상으로, 희생자의 세션과 공격자의 인증 정보를 묶을 때 사용된다.
1) 공격자가 구글 계정을 만들었다고 가정
2) 희생자가 악성 사이트를 방문
3) 공격자의 계정으로 로그인 (username value = attacker 등)
4) 공격자는 희생자의 활동 이력 수집
[ 문제 ]
login CSRF 공격 취약점 확인 / 다른 탭을 열고 csrf- 접두어가 붙은 새로운 계정을 생성하라 (ex. 계정명이 tom이라면 csrf-tom) / 새로 생성한 계정으로 희생자가 로그인하도록 만들어라.
진짜 거의 한 2일 내내 잡고 있었는데 안됀다.... 다른 사람들 솔루션대로 했는디ㅠㅠㅠㅠㅠㅠ
<form id="abc" action="http://127.0.0.1:8080/WebGoat/login" method='POST'>
<input type="hidden" name="username" value="csrf-qwer1"/>
<input type="hidden" name="password" value="12341234"/>
// 회원가입했던 csrf 아이디를 미리 value로 입력
</form>
<script>document.querySelector("#abc").submit()</script>
// id "abc"가 자동으로 submit되는 script 구문
바보다 바보,,,, 아이디에 csrf를 제대로 붙여야하는데,,,,csrf-qwer1234로 회원가입다시했다..
username의 value를 csrf-qwer1234로 바꾸니 성공,,,
해당 공격 구문을 html로 저장해서 새로운 탭에 오픈하고 원래 탭으로 가서 solved하면 성공,,,
CSRF 대응 방안
https://grooveshark.tistory.com/73
1) Referer 검증
- Domain이 일치하는지 확인 (XSS 취약점이 있으면 방어 불가능?)
2) Security Token (CSRF Token)
- 난수값을 세션에 저장하여 사용자 요청마다 해당 난수값을 확인 (XSS 취약점이 있으면 방어 불가능?)
3) Double Submit Cookie 검증
- 웹브라우저 Same Origin 정책으로 JS에서 타 도메인의 쿠키값을 확인하거나 수정하지 못한다.
- 이것을 이용해, script 단에서 요청시 난수 생성 -> 쿠키에 저장 / 파라미터에도 동일한 난수값 => 서버로 전송
- 서버는 쿠키의 난수와 파라미터의 난수가 일치하는 지 검사한다. (서버가 토큰값을 저장하지 않아서 세션보다 가볍)
(쿠키에서 한번, 파라미터에서 한번, Double로 전송되는 cookie 난수값!)
4) Spring Security
* naver lucy (xss filtering)
https://www.youtube.com/watch?v=6bhF5o4gAOs&list=PL93mKxaRDidECgjOBjPgI3Dyo8ka6Ilqm
스프링 부트 따라하면 좋을 듯