HTTPS와 CORS
- HTTPS는 웹 통신 내 요청, 응답에 대한 암호화를 진행한다.
- CORS는 웹 브라우저에서 악의적 웹 요청(CSRF)에 대한 ‘부분적’ 방어 정책이다.
- ‘부분적’의 의미 : 완벽하게 CORS를 방어하지 못한다는 의미이다.
HTTPS (HTTP Secured, TLS)
=> 웹 통신 내 End-to-End 회선 보호
HTTPS는 인터spt 상에서 정보를 암호화하는 SSL 프로토콜을 이용하여 웹브라우저와 웹 서버간의 데이터나 자원을 주고 받는 통신규약을 의미한다.
-
MITM (Man-In-The-Middle) 공격 방지
-
단일 서버 : 다수 클라이언트 (웹 브라우저 혹은 웹 서버)
- 단일 서버만 사용 가능한 키 : 비공개키(Private Key)
- 다수 클라이언트 모두 사용 가능한 키 : 공개키(Public Key)
-
HTTPS 는 대칭키 암호화 방식과 비대칭키 암호화 방식의 장점만을 사용
CSRF (XSRF, Cross-Site Request Forgery) : 크로스 사이트에 대한 의도치 않은 요청
A 사이트를 이용하는 유저가 A 사이트와 전혀 상관없는 B 사이트(크로스사이트)에 의도치 않은 요청을 보내는 것
공격자가 사용자가 이미 인증된 웹 애플리케이션에 대해 원하지 않는 요청을 보내는 공격
- 꼭, 웹 브라우저에서만 가능한것뿐만 아니라 네이티브 앱에서도 가능하다.
- 웹 브라우저에서 CSRF 형태
= 유저가 의도하지 않은 요청이 자바스크립트 실행을 통해 서버에 전송된다.
=> 서버에 요청을 보내는 자바스크립트 = AJAX
사용자가 뱅킹 사이트에 로그인한 상태에서 공격자가 만든 맬리셔스 웹사이트를 방문하면, 그 사이트는 사용자의 브라우저를 이용해 뱅킹 사이트에 비밀번호 변경 요청을 보낼 수 있습니다. 이러한 요청은 사용자의 의도와 무관하게 이루어진다.
⚠️ CSRF 와 CORS 가 헷갈릴 수 있다. 근데 무엇보다도 여기서 CS__와 CO__는 더 헷갈린다.
CS__ (Cross-Site) 와 CO__ (Cross-Origin) 차이는 무엇인가
- Origin 와 Site 의 차이
- Origin : Scheme + Host Name (Domain Name) + Port
- Site : 바로 TLD 다음 도메인 + TLD
- 예시) www.hello.com → 여기서 Site = hello.com | TLD = .com
- eTLD+1 까지 Site 라고 불러줄 수 있다.
- effective TLDs(eTLD) : mypage.github.io or www.hello.co.kr
CORS(Cross-Origin Resource Sharing)
AJAX 통한 크로스사이트 웹 서버에 대한 요청 방어를 위한 웹 브라우저의 정책
- 웹브라우저에서 자바스크립트 AJAX를 통한 CSRF (크로스사이트에 대한 악의적 요청) 방지한다.
- 1. 웹브라우저 : 네이티브 앱에서는 CSRF 방어하기 위해 XSRF Token 사용 (임의 난수 + 세션 활용)
- 2. 자바스크립트 AJAX : 웹 브라우저에서 AJAX가 아닌 FORM을 통한 POST 요청 방어 불가
CORS의 유형
CORS 1) 웹브라우저 비동기 지원 AJAX
- FORM (Synchronous) = 보내고 끝 (HTML 페이지 반환 = 페이지 리렌더 O)
- AJAX (Asynchronous JavaScript and XML) = XHR (XML 객체 반환 = 페이지 리렌더 X)
- 비동기 = XHR 객체 활용 시 서버에 데이터를 요청하거나, 데이터를 전송받을 수 있다.
- 즉, 웹 페이지 전체를 다시 로딩하지 않고 일부분만을 갱신할 수 있게 된다.
- XHR (XmlHttpRequest) : W3C 표준이 아님 (브라우저마다 설계 방식 차이)
- 현재 대부분의 주요 웹 브라우저는 서버에 데이터를 요청하기 위한 XHR 객체 활용
CORS 2) 웹브라우저 보안 정책 SOP (Same-Origin Policy)
웹브라우저에서 HTTP Resource 를 갖고오기 위한 모든 HTTP 요청은 기본적으로 SOP
- 웹브라우저는 SOP (Same Origin Policy) 정책을 갖는다.
- Same Origin 의 의미 - 예시) https://www.hello.com:8080
- Scheme = https://
- Host = www.hello.com
- Port = 8080
- 하지만 웹브라우저는 이미지, 아이콘처럼 외부에서 정보를 가져오는 경우가 있기 때문에
- SOP (Same-Origin Policy) 정책은 ‘Same-Origin’ 이름과 달리 부분적으로 Cross-Origin 도 허용
- Cross-Origin ’가져오기’ (
<img/>
, <script/>
) : 의도된 조회 = 서버 상태 변경 불가
- Cross-Origin ’제출하기’ (FORM) : 개발자가 설계한 의도된 제출 = 의도된 서버 상태 변경
- Cross-Origin ’요청하기’ (AJAX - 예, POST) : 서버 상태 변경 가능 → SOP 에서 불허
- Cross-Origin 에 대한 AJAX 는 Cross-Origin 서버 상태를 바꿀 수 있는 보안 위험성 존재
CORS 3) SOP 보완 정책 = CORS (Cross Origin Resource Policy)
- Cross-Origin ’요청하기’ (AJAX - 예, POST) : 서버 상태 변경 가능 → SOP 에서 불허
- Cross-Origin 에 대한 AJAX 는 Cross-Origin 서버 상태를 바꿀 수 있는 보안 위험성 존재
- 하지만, AJAX 는 표준 기술이 아님에도 사실상 표준으로써 AJAX 를 막게되면 모든 API 호출 불가
- 그래서 결국, SOP 를 보완하여 AJAX 를 부분적으로 허용할만한 추가 정책 필요 = AJAX 는 CORS 정책에 맞을시에만 조건부 허용
- 브라우저에서 처리하는것이기에 서버-서버 통신시에는 CORS 이슈는 전혀 발생하지 않는다.
CORS 서버 측 적용 방법
서버는 브라우저로부터 어떤 요청만 받을지 3가지 CORS 헤더 설정으로 호출가능 요청을 제약한다
CORS(Cross-Origin Resource Sharing) 정책에서 사용되는 헤더들은
웹 애플리케이션의 보안을 강화하고, 다른 출처의 리소스 요청을 효과적으로 관리하기 위해 사용된다.
- 허용된 Origin (예, a.com)
- Origin (브라우저) - 브라우저가 요청할때 보낸다.
- Access-Control-Allow-Origin (서버)
- 이 헤더는 서버가 어떤 출처(origin)의 요청을 허용할지를 지정한다.
출처는 프로토콜, 호스트, 포트를 포함한 URL이다.
예를 들어, 서버가 Access-Control-Allow-Origin: https://example.com을 설정하면, 오직 https://example.com에서 온 요청만 서버에 의해 허용된다.
만약 모든 출처에서의 요청을 허용하고자 한다면, 이 헤더를 Access-Control-Allow-Origin: *로 설정할 수 있다. 그러나 보안상의 이유로 모든 요청을 허용하는 것은 권장되지 않는다.
- 허용된 Method (예, GET, HEAD 만 허용하고 POST 외 제외)
- Access-Control-Request-Method (브라우저) - 요청 시 보냄
- Access-Control-Allow-Method (서버)
- 이 헤더는 서버가 허용하는 HTTP 메소드(예: GET, POST, DELETE 등)를 지정한다.
예를 들어, 서버가 오직 GET과 POST 요청만을 허용하려면, Access-Control-Allow-Methods: GET, POST로 설정할 수 있다.
이 설정은 사전 요청(Preflight Request)에 대한 응답에서 특히 중요하며, 실제 요청에서 사용될 메소드를 서버가 승인하는 역할을 한다.
- 허용된 Header
- Access-Control-Request-Headers (브라우저) - 요청 시 보냄
- Access-Control-Allow-Headers (서버)
-
이 헤더는 서버가 허용하는 특정 HTTP 헤더를 지정한다.
클라이언트가 요청에 포함할 수 있는 헤더(예: X-Custom-Header, Content-Type 등)를 서버가 명시적으로 허용해야 할 때 사용된다.
예를 들어, Access-Control-Allow-Headers: X-Custom-Header, Content-Type는 클라이언트가 이 두 헤더를 요청에 포함시킬 수 있음을 의미한다.
-
추가 : 자격증명 Header 허용
- allowCredentials = true (브라우저) - 요청 시 보내야함
- 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션
- 자격증명 = Cookie, Authorization Headers 또는 TLS 클라이언트 인증
- Access-Control-Allow-Credentials = true (서버)
브라우저는 서버에서 설정한 위 3가지 CORS 설정을 알기 위해서 서버에게 호출하여 알아낸다
-
Simple Request — 서버 상태 조회 : GET, HEAD
- 허용된 Origin 체크 절차
- 브라우저가 서버에게 원 요청 을 보내면
- 서버는 “결과”와 함께 “CORS 헤더”를 같이 보내준다.
- 브라우저는 “CORS 헤더” 가 요청과 부합하지 않으면, 반환 결과 를 폐기한다.
-
Preflight Request — 서버 상태 변경 : POST, PATCH, PUT + GET, HEAD w/ 커스텀 Header
- 허용된 Origin 체크 + 허용된 Method 체크 + 허용된 Header 체크 절차
- 브라우저가 서버에게 임시 요청 을 보내면 = Preflight (OPTION)
- 서버는 “CORS 헤더”만 보내준다.
- 브라우저는 “CORS 헤더” 가 요청과 부합하지 않으면, 원 요청 을 보내지 않는다.