서론
CORS는 SOP 보안 정책을 우회하여 Cross Origin간 자원을 공유하기 위한 방법 중 하나이다.
SOP의 한계를 극복하고 Origin 간 자원 공유를 돕기 위해 postMessage, JSONP 및 CORS 정책 기술이 도입되었다.
SOP를 우회하기 위해 설계된 만큼 CORS는 잘못 사용될 경우 사이트 간 공격이 가능해지는 취약점이 발생할 수 있다. 이는 웹 상에 있는 서비스에만 제약되는 것이 아니며, 일부 P2P 파일 공유 소프트웨어에서 localhost를 통해 제어판을 웹 인터페이스로 제공하였는데 CORS 정책이 제대로 설정되어 있지 않아 CSRF 취약점이 발생한 사례가 있음.
현재 사이트에서 다른 사이트로 정보 유출 (기밀성)
CORS는 모든 정보를 공개하는 Open API뿐만 아니라 특정 대상에게만 자원을 공유하고자 하는 사이트에서도 사용될 수 있으며, 만일 다른 사이트로부터 CORS 요청을 받을 때 그 Origin에 대한 검사가 진행되지 않고 응답하거나 Origin에 제약이 없는 경우 사용자의 신원 등 민감한 정보가 다른 사이트에 노출될 수 있음.
다른 사이트에서 현재 사이트 변조 (무결성)
CORS 요청의 Origin이 신뢰할 수 있는 출처인지 확인 또는 제한하지 않거나 CORS 응답을 그대로 사용할 경우 XSS 등 보안 문제가 발생할 수 있음.
postMessage 취약점
Window.postMessgeAPI
웹 초창기에는 프레임과 창들은 자유롭게 서로의 코드를 호출할 수 있었으나, SOP가 도입되면서 서로 다른 오리진들은 직접적으로 리소스를 공유하지 못하게 되었다. => 이를 해결하기 위해 서로 다른 Origin 간에 메시지를 주고받을 수 있는 API가 고안되었다.
메시지를 전송할 때에는 대상 윈도우의 postMessage 메소드를 호출하며, 수신하는 윈도우는 message 전역 윈도우를 청취하여 메시지를 받을 수 있음.
targetWindow.postMessage(targetOrigin, [transfer])
| 변수 | 설명 |
| targetWindow | 메시지를 보낼 대상 Window |
| message | 메시지 객체 (함수, DOM 객체 등은 보낼 수 없음) |
| targetOrigin | 메시지 송신 시점에 targetWindow의 Origin이 targetOrigin과 일치하여야 함. |
| transfer | 소유권을 전이할 객체의 배열을 지정 |
MessageEvent
| 고유 속성 | 설명 |
| origin | 메시지를 송신한 Origin 반환 |
| source | 메시지를 송신한 Window 객체 반환 |
| data | 복사된 메시지 객체 또는 값 반환 |
// 메시지 송신
targetWindow.postMessage(message, targetOrigin);
// 메시지 수신
window.onmessage = function (e) {
if (e.origin === 'https://dreamhack.io') {
console.log(e.data);
e.source.postMessage('Hello, world!', e.origin);
}
}
postMessage를 통해 message로 문자열뿐만 아니라 객체 또한 주고 받을 수 있으나, 보안을 위해 함수, DOM 노드 객체, 프로토타입 및 get/set 속성 정보는 보낼 수 없음.
또한, 전송되는 모든 객체는 복사되므로 소인 후 객체를 변경하여도 수신하는 윈도에서는 변경 내용을 볼 수 없음.
Origin 미확인
Window.postMessage API 사용 시 Origin을 명확히 지정 및 검사해야 한다. 특정 윈도우는 모든 Origin에서 오는 메시지를 수신할 수 있는데, 이때 message 이벤트 핸들러에서 origin 속성을 검사하지 않고 메시지의 내용을 신뢰하면 보안 문제가 발생할 수 있음.
Origin 전환 경합 조건
postMessage를 사용할 때 한 가지 기억해 두어야 할 점은 메시지를 보내는 대상이 웹 문서가 아닌 창 (윈도우)라는 것임. 웹 문서는 일반적으로 출처가 고정되어 있는 반면, 창의 경우에는 사용자가 하어퍼링크를 방문하거나 스크립트가 다른 문서로 리다이렉트시켜 Origin이 변경될 수 있음.
JSONP 취약점
JSONP는 JSON with Padding의 준말로, CORS 기술이 도입되기 전 SOP를 우회하기 위해 흔히 쓰였던 방식임. JSONP API는 JSON API와 유사하나, 응답 데이터를 특정 콜백 함수를 호출하는 코드로 감싸고 요청시 XHR이 아니라 스크립트로 포함시켜 동작한다는 점이 다르다.
<script src="https://api.test/request.jsonp?id=123&callback=onAPIResponse">
응답은 onAPIResponse({...}); 식으로 생성되어 최종적으로 본래 문서의 함수를 호출하게 된다.
Origin 검사 부재로 인한 CSRF
JSONP에 한정된 취약점은 아니지만, 전적으로 HTTP GET 메소드에 의존하는 JSONP 특성상 CSRF공격에 더 취약한 특성이 있음.
예를 들어 민감한 정보를 반환하거나 권한이 필요한 작업을 수행하는 /users/get_user_info?callbck= JSONP API가 존재한다고 가정하면 피해자가 CSRF 공격에 노출되었을 경우 JSONP API를 이용해 추가적인 정보 유출 및 피해가 발생할 수 있음.
콜백 함수명 검증 부재로 인한 제공자 XSS
JSONP API 대다수는 사용자가 콜백 함수명을 직접 지정할 수 있도록 하고 있는데, 콜백명에 HTML 코드를 삽입한다면 브라우저는 이를 HTML로 인식할 수 있고, 이 경우 XSS 취약점이 발생하게 된다.
콜백 HTML 삽입을 막기 위해서는 콜백명에 필터를 적용하는 것이 좋으며, 추가적으로 JSONP 요청을 처리할 때
HTTP Accept 헤더에 text/javascript MIME 타입이 포함되어 있는지 검사하고, Content-Type: text/javascript 설정 및 X-Content-Type-Options: nosniff 헤더로 자바스크립트가 아닌 다른 콘텐츠로 인식되는 경우를 방지하여야 함.
JSONP API 침해 사고 발생 시 이용자 XSS
JSONP는 API 제공자의 코드를 그대로 사용자의 웹 문서에서 실행한다. 만약 JSONP API가 침해 사고를 당해 악의적인 응답이 돌아온다면 이를 이용하는 모든 사이트는 XSS 공격에 노출된다.
이는 JSONP 사용을 피하고 CORS 정책 헤더를 대신 사용하여야 하는 이유이다.
| 헤더 | 설명 |
| Access-Control-Allow-Origin | 헤더에 작성된 출처만 접근 허용, *로 설정되어 있으면 모든 도메인에서 접근을 허용함. |
| Access-Control-Allow-Methods | 서버가 허용하는 HTTP 메서드를 나타낸다. |
| Access-Control-Allow-Headers | 서버에서 허용하는 헤더를 나타낸다. |
| Access-Control-Allow-Credentials | 요청에 인증 정보를 포함할 수 있는지 여부를 true 또는 false로 나타낸다. |
'웹해킹 > 개념' 카테고리의 다른 글
| [Dreamhack-web] Exploit Tech: CSS Injection (1) | 2024.12.11 |
|---|---|
| [Dreamhack-web] Exploit Tech: Client Side Template Injection (1) | 2024.12.11 |
| [Dreamhack-Web] Exploit Tech: CSRF Token 오용 (0) | 2024.12.10 |
| [Dreamhack-web] Cookie & Session (5) | 2024.12.09 |
| [Dreamhack-Web] Background - Web (4) | 2024.12.09 |