CORS란?
CORS는 SOP 보안정책을 우회하여 Cross Origin간 자원을 공유하기 위한 방법 중 하나이다.
SOP의 한계를 극복하고자 Origin 간 자원 공유를 돕기 위해 postMessage, JSONP 및 CORS 정책 기술이 도입되었다.
SOP를 우회하기 위해 설계되어 CORS를 잘못 사용하게 되면 사이트 간 공격이 가능해져 취약점이 발생할 수 있다.
SOP란?
Same-Origin Policy의 약자이다. SOP는 동일 출처 정책이란 뜻이다.
URL의 프로토콜, 호스트, 포트가 모두 동일하지 않을 때 일어날 문제를 대비해 만들어진 기술이다.
CORS 취약점 종류
현재 사이트에서 다른 사이트로 정보 유출(기밀성)
CORS는 모든 정보를 공개하는 Open API뿐만 아니라 특정 대상에게만 자원을 공유하고자 하는 사이트에서도 사용될 수 있다. 만일 다른 사이트로부터 CORS 요청을 받을 때 Origin에 대한 검사가 제대로 이루어지지 않거나 Origin 제약이 없는 경우 예민한 정보가 노출될 수 있다.
다른 사이트에서 현재 사이트 변조(무결성)
CORS 요청의 Origin이 신뢰할 수 있는 출처인지 확인 또는 제한하지 않거나 CORS 응답을 그대로 사용할 경우 XSS 등 보안 문제가 발생할 수 있다. CORS 기술을 도입할 때 어떤 사이트를 얼마나 신뢰하는지 결정되어야 하며, XSS 필터 등 신뢰하지 않는 입력에 대한 방어 또한 병행되어야 한다.
postMessage 취약점
window.postMessage API
웹 초장기에 프레임과 창들의 코드를 자유롭게 호출할 수 있었다. SOP가 도입되면서 서로 다른 오리진들의 리소스들은 공유가 불가해졌다.
postMessage API는 이를 해결하기 위해 만들어진 API 중 하나이다.
메세지를 전송할 때 대상 윈도우의 postMessage 메소드를 호출하고, 수신하는 윈도우는 message 전역 이벤트를 메세지를 통해 받을 수 있다.
targetWindows.postMessage(message, targetOrigin[transfer])
변수 | 설명 |
targetWindow | 메세지를 보낼 대상 Window |
messge | 메세지 객체 (함수, DOM 객체 등은 보낼 수 없음) |
targetOrigin | 메세지 송신 시점에 targetWindow의 Origin이 targetOrigin과 일치하여야 함. |
transfer | ArrayBuffer나 canvas context 등 소유권을 전이할 객체에 배열을 지정 |
MessageEvent
고유 속성 | 설명 |
origin | 메시지를 송신한 Origin 반환 |
source | 메시지를 송신한 Window 객체 반환 |
data | 복사된 메시지 객체 또는 값 반환 |
postMessage를 통해 message로 문자열뿐만 아니라 객체 또한 주고받을 수 있지만, 보안 때문에 함수, DOM 노드 객체, 프로토타입 및 get/set 속성 정보는 보낼 수 없다.
Origin 미확인
Window.postMessage를 이용할 때는 Origin 검증이 필요하다. 따라서 Origin을 지정하거나 검사를 해야된다.
Origin 전환 경합 조건
postMessage를 사용할 때 한 가지 기억해 두어야 할 점은 메시지를 보내는 대상이 웹문서가 아닌 윈도우라는 것이다. 웹 문서는 일반적으로 출처가 고정되어 있는 반면, 창의 경우에는 사용자가 하이퍼링크를 방문하거나 스크립트가 다른 문서로 리다이렉트시켜 Origin이 변경될 수 있다. 이 상태에서 메시지를 보내게 되면 의도하지 않은 Origin으로 메시지가 전송되는 문제가 발생한다.
따라서 targetOrigin에 대상 Origin을 명시해야된다.
JSONP 취약점
JSONP는 JSON with Padding의 준말이다. CORS가 만들어 지기 이전에 SOP를 우회하기 위해 사용되었다. JSONP API는 JSON API와 유사하다. 차이점이라고 하면 응답 데이터를 특정 콜백 함수를 호출하는 코드로 감싸고 요청 시에는 XHR이 아니라 다음과 같이 스크립트로 포함시켜 동작한다.
<script src="https://api.test/request.jsonp?id=123&callback=onAPIResponse"> //response example onAPIResponse({...});
XHR이란?
XMLHttpRequest의 약자이다. XHR은 Ajax를 구현할 때 사용된다.
XHR의 기능은 서버와 상호작용할 떄 사용된다. XHR를 사용하게 되면 페이지의 새로고침 없이 URL에서 데이터를 가져올 수 있다.
이름에 XML이 들어가지만 XML 이외에도 모든 종류의 데이터를 가져올 수 있다.
Origin 검사 부재로 인한 CSRF
JSONP에 한정된 취약점은 아니다. 전적으로 HTTP GET 메소드에 의존하는 JSONP의 특성 상 CSRF공격에 더욱 취약하다. 취약점의 보안 방법은 Origin 검사 및 CSRF Token을 사용하는 방법이 있다.
콜백 함수명 검증 부재로 인한 제공자 XSS
JSONP는 대부분 콜백 함수명을 직접 지정할 수 있다. 만약에 콜백명에 HTML을 입력하게 되면 브라우저는 HTML로 판단할 수 있고, 이 경우 XSS의 취약점이 발생할 수 있다.
방지하기 위해서는 HTTP Accept 헤더에 text/javascrip MIME 타입이 포함되어 있는지 검사하고, Content-Type: text/javascript 설정 및 X-Content-Type-Options: nosniff 헤더로 응답이 자바스크립트 만 받도록 하여야 합니다.
MIME Type Sniffing
브라우저가 서버에서 받은 Content-Type을 신뢰하지 않고 해당 리소스 데이터를 분석하여 적절한 형식으로 해석하는 것을 말합니다. 이렇게 되면 의도치 않은 해석으로 인하여 XSS가 발생할 수 있습니다. 따라서 X-Content-Type-Options 헤더를 nosniff로 설정하여 서버에서 전달 받은 Content-Type만을 믿을 수 있도록 해야합니다.
JSONP API 침해 사고 발생 시 이용자 XSS
JSONP는 API 제공자의 코드를 그대로 사용자의 웹 문서에서 실행합니다. 만약 JSONP API가 침해 사고를 당해 악의적인 응답이 돌아온다면 이를 이용하는 모든 사이트는 XSS 공격에 노출됩니다. 이는 JSONP의 가장 큰 단점으로, CSP를 사용하고 JSONP를 제공하는 웹 서비스를 신뢰하는 것 외에는 별다른 방법이 없습니다.
헤더 | 설명 |
Access-Control-Allow-Origin | 헤더에 작성된 출처만 접근 허용, * 로 설정되어있으면 모든 도메인에서 접근을 허용. |
Access-Control-Allow-Methods | 서버가 허용하는 HTTP 메서드를 나타냄. |
Access-Control-Allow-Headers | 서버에서 허용하는 헤더를 나타냄. |
Access-Control-Allow-Credentials | 요청에 인증 정보(e.g. 쿠키, HTTP 인증 등)를 포함할 수 있는지 여부를 true 또는 false로 나타냄. |