IIS Access-Control-Allow-Origin 설정 : CORS(Cross-Origin Resource Sharing)
PROGRAMING/HTML5 2011. 12. 15. 15:26 WCF RIA 서비스의 end point를 JSON으로 설정하고 Sencha touch로 구현한 클라이언트에서 데이타를 가져오기 위해서 Ajax 통신으로 Json 데이타를 가져오려고 시도 했더니 다음과 같은 에러가 발생하였다.
XMLHttpRequest cannot load [서버 URI]. Origin [클라이언트 도메인] is not allowed by Access-Control-Allow-Origin.
WCF RIA 서비스의 도메인 정책에 문제가 있는 것으로 판단되어 clientaccesspolicy.xml/crossdomain.xml 를 서버에 저장해도 같은 에러가 발생해서 알아보니 다음 내용과 관련된 문제 였다.
참조 : http://blog.iolo.pe.kr/category/hacking/web
Ajax에는 Same Origin Policy라는 원칙이 있다. 말 그대로, 현재 브라우져에 보여지고 있는 HTML을 내려준 웹서버(Origin)에게만 Ajax 요청을 보낼 수 있다.
MS가 XMLHttpRequest를 처음 만들 때만 해도 이런 제약은 당연한 것처럼 보였지만, 지금에 와서는 OpenAPI를 통한 매시업(Mashup)이 활성화되는 데 가장 큰 장애물이 되었다. 매시업이 아니더라도 여러 개의 도메인을 사용해야 하는 대규모 사이트를 개발할 때도 골치거리였다. Same Origin Policy를 우회하는 방법으로 JSONP, IFRAME IO, CrossDomain Proxy 등이 고안되었지만, 보안성이 취약하다거나, 동기 호출이 안되거나, 주고 받는 데이터 형식이 제한되거나, 직관적이지 못하거나(dirty hack), ... 등의 문제점 때문에 표준화되기엔 무리가 있었다.
(중략) 한 참 뒤에야 W3C는 (MS의 IE가 제공하는 방식을 수용하여) 크로스도메인간에도 Ajax요청을 주고 받을 수 있는 방법을 표준화 했는데, 그것이 바로 CORS다.
CORS를 한 마디로 요약하면, "요청을 받은 웹서버가 허락하면 크로스도메인이라도 Ajax로 통신할 수 있다"라는 정책이다. 기술적으로는 크로스도메인에 위치한 웹서버가 응답에 적절한 Access-Control-Allow-류의 헤더를 보냄으로써 크로스도메인 Ajax를 허용 수 있다.
말이 뺑뺑도는 느낌인데, 예를 들어 보자(코드를 줄이기 위해 jQuery를 사용했지만 XMLHttpRequest를 직접 사용해도 마찬가지다). Ajax 요청을 보내는 one.html을 내려 준 a.com이 오리진 웹서버다. 이 요청을 받는 b.com이 크로스도메인 웹서버다. a.com에서 b.com으로... 그래서 크로스-도메인이다.
대충 그려보면 이런 식인데, b.com은 크로스도메인이므로 Ajax 통신이 불가능하지만, CORS를 적용하면 가능하다:
XMLHttpRequest cannot load [서버 URI]. Origin [클라이언트 도메인] is not allowed by Access-Control-Allow-Origin.
WCF RIA 서비스의 도메인 정책에 문제가 있는 것으로 판단되어 clientaccesspolicy.xml/crossdomain.xml 를 서버에 저장해도 같은 에러가 발생해서 알아보니 다음 내용과 관련된 문제 였다.
참조 : http://blog.iolo.pe.kr/category/hacking/web
Ajax에는 Same Origin Policy라는 원칙이 있다. 말 그대로, 현재 브라우져에 보여지고 있는 HTML을 내려준 웹서버(Origin)에게만 Ajax 요청을 보낼 수 있다.
MS가 XMLHttpRequest를 처음 만들 때만 해도 이런 제약은 당연한 것처럼 보였지만, 지금에 와서는 OpenAPI를 통한 매시업(Mashup)이 활성화되는 데 가장 큰 장애물이 되었다. 매시업이 아니더라도 여러 개의 도메인을 사용해야 하는 대규모 사이트를 개발할 때도 골치거리였다. Same Origin Policy를 우회하는 방법으로 JSONP, IFRAME IO, CrossDomain Proxy 등이 고안되었지만, 보안성이 취약하다거나, 동기 호출이 안되거나, 주고 받는 데이터 형식이 제한되거나, 직관적이지 못하거나(dirty hack), ... 등의 문제점 때문에 표준화되기엔 무리가 있었다.
(중략) 한 참 뒤에야 W3C는 (MS의 IE가 제공하는 방식을 수용하여) 크로스도메인간에도 Ajax요청을 주고 받을 수 있는 방법을 표준화 했는데, 그것이 바로 CORS다.
CORS를 한 마디로 요약하면, "요청을 받은 웹서버가 허락하면 크로스도메인이라도 Ajax로 통신할 수 있다"라는 정책이다. 기술적으로는 크로스도메인에 위치한 웹서버가 응답에 적절한 Access-Control-Allow-류의 헤더를 보냄으로써 크로스도메인 Ajax를 허용 수 있다.
말이 뺑뺑도는 느낌인데, 예를 들어 보자(코드를 줄이기 위해 jQuery를 사용했지만 XMLHttpRequest를 직접 사용해도 마찬가지다). Ajax 요청을 보내는 one.html을 내려 준 a.com이 오리진 웹서버다. 이 요청을 받는 b.com이 크로스도메인 웹서버다. a.com에서 b.com으로... 그래서 크로스-도메인이다.
대충 그려보면 이런 식인데, b.com은 크로스도메인이므로 Ajax 통신이 불가능하지만, CORS를 적용하면 가능하다:
서버 프로그램의 Web Config 설정을 다음과 같이 바꾸어 주었더니 엑세스가 허용되었다. ^^ ( IIS 7.0 기준)
<system.webServer>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
자세한 내용은 다음 사이트를 참고하세요.
http://enable-cors.org/
추가 내용 / 2012.01.31
wcf rest service template 40를 사용해서 Restful service를 제공하는 project를 생성하였고 위 내용을 적용해도 엑세스가 허용되지 않았다.
그래서 다음과 같이 하였더니 허용되었다. ^^
Global.asax 에 다음 내용 추가
protected void Application_BeginRequest(object sender, EventArgs e)
{
자세한 내용은 다음 사이트를 참고하세요.
http://enable-cors.org/
추가 내용 / 2012.01.31
wcf rest service template 40를 사용해서 Restful service를 제공하는 project를 생성하였고 위 내용을 적용해도 엑세스가 허용되지 않았다.
그래서 다음과 같이 하였더니 허용되었다. ^^
Global.asax 에 다음 내용 추가
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
HttpContext.Current.Response.Cache.SetNoStore();
EnableCrossDmainAjaxCall();
}
}
private void EnableCrossDmainAjaxCall()
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // * 대신 접속 하는 site를 추가하면 될 듯.
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // * 대신 접속 하는 site를 추가하면 될 듯.
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods",
"GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
"Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
"1728000");
HttpContext.Current.Response.End();
}
}
------------------------------------------------------------------------------------------------------------------------------------------
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods",
"GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
"Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
"1728000");
HttpContext.Current.Response.End();
}
}
------------------------------------------------------------------------------------------------------------------------------------------