[Javascript Deep Dive] Cross Domain Problem (ft. SOP, JSONP, CORS)

강민혁·2022년 10월 28일
1

Javascript Deep Dive

목록 보기
4/6

Cross Domain 문제

서로 다른 도메인간의 통신을 시도할 때, 보안 문제가 발생하는 것이다. 이 것은 자바스크립트 엔진 표준 스펙의 Same-Origin Policy라는 보안 방식에 의해 발생하며, 웹 브라우저에 의해서 판단된다.

Same-Origin Policy

동일 출처 정책은 웹 브라우저 보안을 위해 프로토콜, 호스트, 포트가 동일한 서버로만 Ajax 요청을 주고 받을 수 있도록 제한하는 보안 방식이다.

MDN에서 정의하는 SOP

어떤 Origin에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식이다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여준다.

Origin

Origin은 URL의 프로토콜, 호스트(도메인), 포트로 정의된다.
(ex. 프로토콜 : https, 호스트: velog.io, 포트: 3000)

같은 Origin을 가졌다는 것의 의미는 "두 객체의 프로토콜, 호스트, 포트가 모두 일치한다"는 것을 말한다.

만약 이러한 정책이 없다면, 공격자에게 예상치 못한 스크립트 코드가 삽입되어 민감한 정보가 탈취되는 등 보안 취약점이 발생할 수 있다. 그래서 SOP 정책 덕분에, XSS(Cross-Site Scripting, 사이트 간 스크립팅)나 CSRF(Cross-Site Request Fogery, 사이트 간 요청 위조)와 같은 보안 취약점 공격을 대비할 수 있다.

XSS(Cross-Site Scripting, 사이트 간 스크립팅)

가장 기초적인 취약점 공격 방법의 일종으로, 악의적인 사용자가 공격하려는 사이트에 스크립트를 넣는 기법이다. 이 취약점은 웹 어플리케이션이 사용자로부터 입력 받은 값을 제대로 검사하지 않고 사용할 경우 나타나며, 공격에 성공하면 사이트에 접속한 일반 사용자들은 삽입된 코드를 브라우저에서 실행하게 되고, 쿠키나 세션 토큰 등의 민감한 정보를 탈취당한다.

CSRF(Cross-Site Request Fogery, 사이트 간 요청 위조)

사용자가 자신의 의지와 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격이다. 공격자가 만든 악성 페이지를 통해 사용자는 의도치 않게 공격을 수행한다.

클라이언트에서 서버로 요청시에는 쿠키에 저장된 sessionID를 함께 전달하여, 인증된 사용자임을 증명한다.

이 점을 이용하면, 해당 브라우저의 사용자가 서버로부터 인증을 받은 상태에서 악성 스크립트 페이지를 누르도록 유도하면 자동으로 사용자의 sessionID가 공격자의 요청과 함께 넘어가면서 의도치 않은 요청이 전송된다.

그리고 서버는 이것을 인증된 사용자로부터의 요청으로 인지하고 처리한다.

하지만 서로 다른 도메인끼리의 통신이 필요한 순간들이 있다. 외부 API를 가져다가 쓸 경우가 그 예시가 되겠다.
그렇다면 서로 다른 도메인 끼리 통신하고 데이터를 주고 받기 위해서는 어떻게 해야할까?

JSONP(JSON with Padding)

JSONP는 HTML의 <script> 요소로부터 요청되는 호출에는 보안 정책이 적용되지 않는 점을 이용한 우회방법이다.

JSONP는 <script> 안에 있는 callback 함수로 인식하여 데이터 호출 시 보안 정책의 영향을 받지 않는다.

<script type="application/javascript"
        src="http://server.example.com/Users/1234?callback=parseResponse">
</script>

즉, 콜백 함수를 외부 서비스에서 받아와서 그것을 실행하고, 그 콜백 함수에는 JSON 데이터가 패딩되어있는 방식이다.

하지만 resource 파일은 GET 메서드를 통해 받아오기 때문에, GET 방식의 API만 요청이 가능하다는 단점이 있다.

//-- JSON
$.ajax({ 
    url: url, 
    dataType: 'json', 
    data: data, 
    success: callback 
}); 
$.getJSON(url, data, callback);

//-- JSONP
$.ajax({ 
    url: url, 
    dataType: 'jsonp', 
    jsonpCallback: "myCallback", 
    success: callback 
}); 
$.getJSON(url + "?callback=?", data, callback);

Ajax를 통해 JSON 데이터를 요청하는 코드와 JSONP를 이용해 데이터를 받아오는 코드이다. 차이점은 dataType과 url 뒤에 콜백 파라미터가 붙는다는 점이다.

CORS (Cross-Origin Resource Sharing, 교차 출처 리소스 공유)

JSONP가 일종의 편법이자 우회방법이었다면, CORS 프로토콜은 외부 도메인 서버와 통신하기 위한 방식을 표준화한 스펙이다.

즉, 서버와 클라이언트가 약속된 Header를 통해 요청과 응답에 반응할지 결정하는 방식이다.

CORS 프로토콜은 cross-origin간 어떤 응답이 공유될 수 있는지를 나타내는 Header의 집합으로 구성되어있다. 그래서 요청을 받는 웹 서버의 허용이 있는 응답에 대해서는 cross-origin간의 자원 공유가 가능해진다.

preflight request (사전 요청)

웹 브라우저는 요청 URL이 외부 도메인일 경우에, preflight 요청을 먼저 보낸다.
preflight 요청을 통해, 미리 요청을 해보고 응답이 가능한지 확인하는 과정을 거친다.

이 때문에, 서버 측에서는 이 preflight request를 처리하는 기능이 존재해야한다.

CORS 프로토콜은 이 외에도 상당히 복잡한 부분이 많아 나중에 따로 정리해보도록 하겠다.

Reference

[javascript deep dive] 도서
https://mosei.tistory.com/entry/JSONP%EC%99%80-CORSCrossOrigin-Resource-Sharing-%ED%81%AC%EB%A1%9C%EC%8A%A4%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%82%AC%EC%9A%A9
https://lucete1230-cyberpolice.tistory.com/23
https://junhyunny.github.io/information/security/spring-boot/spring-security/cross-site-reqeust-forgery/
https://ngio.co.kr/9615
https://blog.kingbbode.com/26
https://fetch.spec.whatwg.org/#http-cors-protocol

profile
with programming

0개의 댓글