by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

CORS (Cross-Origin Resource Sharing)

Version 1 by study.gurubee
on 11월 30, 2015 20:23.


 
compared with
Current by study.gurubee
on 11월 30, 2015 20:44.


 
Key
These lines were removed. This word was removed.
These lines were added. This word was added.

View page history


There are 5 changes. View first change.

  
 h1. CORS (Cross-Origin Resource Sharing)
  
  
 h2. CORS (Cross-Origin Resource Sharing) 란 무엇인가?
  
 h4. Ajax에는 Same Origin Policy라는 원칙이 있음
* 현재 브라우져에 보여지고 있는 HTML 내려준 웹서버(Origin- 동일도메인,동일port,동일프로토콜)에게만 Ajax 요청을 보낼 수 있음
  * 현재 브라우져에 보여지고 있는 HTML을 내려준 웹서버(Origin- 동일도메인,동일port,동일프로토콜)에게만 Ajax 요청을 보낼 수 있음
  * CORS가 미 구현된 웹브라우저에서는 다른 도메인간 통신이 불가능
* 우회 방법으로 JSONP, IFRAME IO, CrossDomain Proxy 등이 고안됨 (Get만 허용 및 보안취약, 동기호출안됨 등...)
 * HTML5 에서 다른 도메인 간 통신이 가능한 스펙이 추가되었는데 바로 CORS 와 postMessage 이다.
  * 우회 방법으로 JSONP, IFRAME IO, CrossDomain Proxy 등이 고안됨 (Get만 허용 및 보안취약, 동기호출안됨 등 문제있음)
 * HTML5 에서 다른 도메인 간 통신이 가능한 스펙이 추가되었는데 바로 CORS 이다.
  
  
 h2. Preflight Request
  
  |!cors_flow.png!|
  
  * 실제 요청을 보내도 안전한지 판단하기 위해 preflight 요청을 먼저 보낸다.
  * Preflight Request는 actual 요청 전에 인증 헤더를 전송하여 서버의 허용 여부를 미리 체크하는 테스트 요청이다.
  * 이 요청으로 트래픽이 증가할 수 있는데 서버의 헤더 설정으로 캐쉬가 가능
  * 브라우저에서는 다른 도메인으로 보내게 될 때 해당 도메인에서 CORS 를 허용하는지 알아보기 위해 preflight 요청을 보내는데 이에대한 처리가 필요
  ** https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
  * preflight 요청은 OPTIONS 메서드를 사용하며 "Access-Control-Request-*" 형태의 헤더로 전송
  {code}
 ...
 User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
 Access-Control-Request-Method: POST
 Access-Control-Request-Headers: charset, x-requested-with, if-modified-since, content-type
 Accept: */*
 ...
  {code}
  
  * Access-Control-Request-*
  ** Access-Control-Request-Method : actual 요청 시에 사용하는 메서드를 지정
  ** Access-Control-Request-Headers : actual 요청 시에 전송하는 헤더를 지정
  
  
  h4. preflight 단계
  * ① 동일한 URI 에 OPTION method 로 요청을 보냄. (preflight)
  * ② ① 요청에 대해 서버에서는 허용되는 method , 허용하는 헤더, 쿠키 허용여부 등을 응답
  * ③ ② 요청의 응답이 요청을 허용하는 조건이라면 실제로 요청을 보냄
  
  h4. preflight 없이 actual 만 요청되는 경우
  * GET, HEAD, POST (Content-type 이 application/x-www-form-urlencoded, multipart/form-data, text/plain 인 경우) 메서드 를 사용하는 경우
  * custom header 를 추가하지 않는 경우
  
h4. preflight 와 actual 의 request,response
  ||type||request||response||
  ||actual| {code} 별도 인증 헤더 없음{code} | {code}
  Access-Control-Allow-Origin: http://www.gurubee.net
  Access-Control-Allow-Credentials: true
  {code}|
  ||preflight|{code}
  Access-Control-Request-Method: POST
  Access-Control-Request-Headers: charset, x-requested-with, if-modified-since, content-type
  {code} | {code}
  Access-Control-Allow-Methods: POST
  Access-Control-Allow-Headers: x-requested-with, charset, if-modified-since
  Access-Control-Allow-Origin: http://www.gurubee.net
  Access-Control-Allow-Credentials: true
  {code}|
  
  
 h2. CORS 적용 방법 : 클라이언트
  
  * 클라이언트는 기존 Ajax 요청과 동일하게 구현
 * 요청하는 URL 의 출처 (origin) 가 다른 경우 XMLHttpRequest 객체가 preflight, actual 요청을 자동으로 처리 함.+
  * 요청하는 URL 의 출처 (origin) 가 다른 경우 XMLHttpRequest 객체가 preflight, actual 요청을 자동으로 처리 함.
  
 {note}
 쿠키를 전송해야 하는 경우 XMLHttpRequest의 withCredentials 를 true 로 설정해야 하고 서버에서 "Access-Control-Allow-Credentials" 헤더를 true 로 설정해야만 서버와 클라이언트 간 쿠키 전송이 가능.
 {note}
  
  
 h2. CORS 적용 방법 : 서버
  * CORS 에서 preflight 요청은 OPTIONS 메서드를 사용하기 때문에 웹서버에서 OPTIONS 메서드를 허용하는지 확인이 필요 함
  
  h4. Apache httpd.conf에 적용 예
  
 {code}
 <IfModule mod_headers.c>
  SetEnvIf Origin "http://(.+\.)?(gurubee.net|oracleclub.com)$" AccessControlAllowOrigin=$0
  Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
  Header set Access-Control-Allow-Credentials "true"
  Header set Access-Control-Allow-Headers "Charset, Content-Type, X-Requested-With, Accept"
  Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, HEAD"
 </IfModule>
 {code}
  
  
  
  h4. JAVA 적용 예
  * 참고자료 : [Cross-Origin Resource Sharing (CORS) requests with Spring MVC|http://patrickgrimard.com/2013/12/12/cross-origin-resource-sharing-cors-requests-with-spring-mvc/]
  
 {code}
 public class CorsFilter extends CORSRequestFilter {
  
  @Override
  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException
  {
  //logger.info ("[Filter] CorsFilter called");
  HttpServletResponse response = (HttpServletResponse) httpServletResponse;
  
  response.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
  response.setHeader("Access-Control-Allow-Credentials", "true");
  response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE, HEAD");
  response.setHeader("Access-Control-Allow-Headers", "Charset, Content-Type, X-Requested-With, Accept");
  
  
  filterChain.doFilter(httpServletRequest, httpServletResponse);
  }
 }
  
 {code}
  
  
 h2. 참고
  * [W3C Cross-Origin Resource Sharing| http://www.w3.org/TR/cors/]
  * [Spring CORS Support|http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#cors]