[Web Server] Browser security, CORS

5224 단어 Web ServerWeb Server

Browser security
CORS


Browser security

브라우저가 위협을 받는 이유는 브라우저가 자바스크립트를 구동하며, 자바스크립트로 할 수 있는 것들이 많기 때문이다.

XSS

  • 클라이언트가 서버를 신뢰하기 때문에 발생하는 이슈.
  • 서버가 Script 태그 사이에 코드를 넣고 (script injection) 브라우저로 보내면 브라우저는 그 코드를 실행하게 된다.
  • 기본적인 XSS 공격은 브라우저에서 막아 준다.

CSRF

  • 서버가 클라이언트를 신뢰하기 때문에 발생하는 이슈.
  • 서버는 인증정보를 가지고 오면 믿는다. 사용자는 인증 정보를 가진 체로 해커의 링크를 누르면, 해커는 인증정보를 가로채서 서버에 요청을 보내 버린다.

CORS

Cross-Origin Resource Sharing

CORS 는 HTTP header 을 사용하는 메커니즘으로, 서로 다른 origin(서버) 간에 HTTP reqeust 가 가능하도록 해 주는 표준(standard)이다.

HTTP request 는 기본적으로 Cross-Site HTTP Request 가 가능하다. 이는

<img src="other-domain.com">,
<script src="other-domain.com/script.js">

와 같이 웹 사이트가 다른 도메인에 존재하는 리소스(이미지, 스크립트)를 참조할 수 있음을 뜻한다.

하지만 보안상의 이유로 브라우저에서는 <script></script> 로 둘러쌓여 있는 스크립트에서 생성된 cross-origin HTTP request 를 제한하고 있다. 예를 들어 XMLHttpRequest 나 Fetch API 는 Same-Origin Policy 를 따르기 때문에 올바른 CORS Header 를 포함하지 않는 한 다른 origin 에 request 를 할 수 없다.

예를 들어 스크립트를 통해 사용자를 악성 사이트로 리디렉션해줄수도 있는데, 브라우저는 기본적으로 same-origin policy 이기 때문에 자동으로 차단된다.

때문에 서버 개발자는 CORS 를 이해하고 스펙을 따라 HTTP request 에 응답을 해야 한다.

옛날에는 한 웹사이트는 하나의 서버(back-server)만 사용했으나, 현대에 이르러 AJAX(React) 가 나오면서 front-server 를 사용하게 되어 2개의 서버를 사용하게 되었다. CORS 가 필요하게 되었다.

같은 서버의 기준

http://mozila.org:8080

Protocol(http), domain(mozila.org), port(8080) 가 같으면 같은 서버(origin)다.

CORS 의 작동 방식

CORS 표준은 HTTP header 에 새로운 header 를 추가하여 서버가 자신의 정보를 사용할 수 있는 서버 목록을 가지도록 한다.
또한 CORS 표준은, 만약에 어떤 HTTP request 가 서버에 side effect 를 일으키는 요청이라면(주로 GET 이외의 요청), 해당 요청을 보내기 전에 브라우저가 "preflight" 이라는 요청을 먼저 보내도록 강제하고 있다.
이 요청의 이름은 OPTIONS 인데, 이 요청을 통해 서버에 어떤 HTTP 메소드를 요청을 보낼 수 있는지 물어보는 작업이다.
서버가 답을 보내주면, 그 이후에 실제 요청을 하게 된다.
또한 서버는 클라이언트에 요청에 인증(쿠키, HTTP 인증 등)이 포함되어야 하는지도 알려줄 수 있다.

만약에 서버가 요청을 허락하지 않으면 에러를 보내게 되는데, 보안상의 이유로 자바스크립트로 에러에 접근할 수 없게 만들었다. 코드상으로는 그냥 에러가 났다는 사실만을 알 수 있다.
에러의 디테일을 알고 싶다면 브라우저의 콘솔로 확인할 수 밖에 없다.

CORS 작동 시나리오

1. Simple requests

CORS preflight 요청이 일어나지 않는 요청을 심플 리퀘스트라고 한다. 다음 조건을 만족하면 간단한 리퀘스트가 된다:

method : GET, HEAD, POST
Content-Type : application/x-www-form-urlencoded, multipart/form-data, text/plain

다른것도 있는데 생략.

https://foo.example 라는 웹사이트(서버)가 https://bar.other 라는 서버에 요청을 보내면:

그럼 서버는 response 를 보내게 되는데, 헤더에

Access-Control-Allow-Origin: *

식의 헤더가 들어가있다.

위의 저 헤더의 뜻은 서버의 리소스를 모든 서버가 다 사용할 수 있다는 뜻이다. (* 는 모두의 뜻)
만약에 리소스의 접근을 제한하고 싶다면 * 대신에 url 을 넣어주면 된다.

2. Preflight requests

프리플라잇 리퀘스트는 브라우저가 먼저 OPTIONS 라는 메소드로 미리 리퀘스트를 날려서 앞으로 보낼 요청을 보내도 괜찮은지를 서버에게 물어보는 것이다. 만약 METHOD 나 Content-Type 이 위 심플 리퀘스트 조건에 만족하지 않으면 브라우저는 자동으로 프리플라이트를 요청을 보낸다.

아래 MDN 예제는 POST, X-PINGOTHER, Content-Type : application/xml 인 요청을 보내기 때문에 먼저 preflight 요청을 보내본다.

Access-Control-Allow-Origin: http://foo.example // 허용할 origin
Access-Control-Allow-Methods: POST, GET, OPTIONS // 허용할 method
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type // 허용할 header
Access-Control-Max-Age: 86400 
// preflight request 를 cache 에 저장할 수 있는 시간 (단위: 초)

3. Request w/ credentials

later

좋은 웹페이지 즐겨찾기