跨域服务调用基本概念及解决方法
2013-09-18 09:01
351 查看
综述
出于防范跨站脚本攻击的同源安全策略,浏览器禁止客户端脚本(如Javascript)对不同域名的服务进行跨域调用。同源策略(Same Origin)中的源有着严格的定义,参见RFC6454,第4章节。一般而言,Origin由{protocol, host, port}三部分组成。
下面是同源检查的一些实例:
可能有点意外的是,一般我们会认为不同的子域名应该被当做同域名,是安全的调用,但实际上浏览器同源策略甚至禁止了不同子域名和端口的服务之间的调用。
解决方法
有时候上述限制过于严格,为了在两个不同Origin的网页(服务)之间进行通讯,我们可以采用如下的一些技术方法:
1、服务代理模式
即在web服务器上封装第三方服务,然后给自己同源的web页面调用。
2、跨子域名的调用
如果想从www.example.com调用api.example.com的html/xml数据服务,那么可以通过使用iframe,并在document和iframe中均设置相同的document.domain属性,那么document和iframe所对应的页面直接就可以通信而不会有任何安全冲突(security violation),注意必须设置相同的一级域名(document.domain="example.com"),不要设置子域名。代码示例如下:t.html
[html] view
plaincopy
<html>
<head>
<script type="text/javascript">
document.domain = "example.com";
function update_me(result) {
document.getElementById('update-me').innerHTML = "Result: " + result;
}
function load() {
var c<
16472
span style="margin:0px;padding:0px;border:none;background-color:inherit;"> = document.createElement('iframe');
c.style.display = "none";
c.src = "http://api.example.com/cross-subdomains-ajax/t-frame.html#" + document.domain;
document.body.appendChild(c);
}
</script>
</head>
<body onload="load();">
<div id="update-me"></div>
</body>
</html>
t-frame.html
[html] view
plaincopy
<html>
<head>
<script type="text/javascript">
function spoof(status, headers, result) {
var old_domain = document.domain;
document.domain = example.com;
window.parent.update_me("Ok, got it from the frame !");
try {
document.domain = old_domain;
} catch (e) { }
}
spoof();
</script>
</head>
</html>
3、跨源资源共享
这是已经标准化的技术方法,参见W3规范文档Cross Origin Resouce Sharing:http://www.w3.org/TR/cors/通过在服务端设置
Access-Control-Allow-Origin响应头(一般回填$_SERVER['HTTP_ORIGIN']),
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
来告诉浏览器该服务允许来自特定源的访问或者允许所有人访问。
尽管该规范支持使用origin list的形式,但实际浏览器实现只支持了单个origin、*、null,如果要配置多个访问源,可以在代码中处理如下(PHP):
[php] view
plaincopy
$allowed_origins = array(
"http://www.example.com" ,
"http://app.example.com" ,
"http://cms.example.com" ,
);
if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)){
@header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
或者在httpd配置或.htaccess文件(如果使用的是Apache服务器)中添加如下语句:
[plain] view
plaincopy
SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
如用的是nginx,配置类似如下:
[plain] view
plaincopy
location / {
# this will echo back the origin header
if ($http_origin ~ "example.com$") {
add_header "Access-Control-Allow-Origin" $http_origin;
}
}
4、使用JSONP协议
出于同源策略,HTML禁止在两个页面之间进行通讯,但<script>元素是个例外,JSONP利用这个开放特性来实现跨域调用,在客户端调用提供JSONP支持的URL Service,获取JSONP格式数据,然后在callback函数中处理返回的json协议数据:
[html] view
plaincopy
<script type="text/javascript" src="http://api.example.com/getdata?jsonp=callback"></script>
如使用jQuery的ajax调用方式,示范代码如下:
[javascript] view
plaincopy
$.ajax({
dataType: 'jsonp',
data: 'id=10',
jsonp: 'jsonp_callback',
url: 'http://api.example.com/getdata',
success: function () {
// do stuff
},
});
5、跨文档消息(Cross-document Messaging)
这个是HTML5引入的一个在跨域页面之间通讯的方法,参见W3规范 http://dev.w3.org/html5/postmsg/ postMessage API应用范围主要有2个,1是文档和内嵌frame之间的消息通信,2是文档和自身通过脚本打开的windows之间的消息通信
http://blog.csdn.net/iefreer/article/details/11394515
相关文章推荐
- 跨域服务调用基本概念及解决方法
- c/c++中利用gsoap调用webservice服务的一个诡异问题解决方法
- c#调用百度地图web服务api-----该方法可用在js跨域请求上
- Silverlight2 跨域调用Web服务的方法
- c#调用百度地图web服务api-----该方法可用在js跨域请求上
- 网站调用其他域名的静态文件导致的跨域问题、CORS错误解决方法
- 解决调用Iframe引入跨域访问页js方法问题
- vs自动生成的WebService配置文件在部署到IIs6后,服务调用失败的解决方法
- 调用、方法-Android的一些基本概念小整理(一)-by小雨
- 只能从脚本中调用在类定义上有[ScriptService]属性的 Web 服务问题的解决方法
- 调用天气查询webservice服务的两种基本方法
- Dubbo服务重载方法在JDK1.8上调用出错的问题(待解决)
- silverlight调用webservice跨域导致问题的解决方法
- WCF服务发布到IIS6.0跨域访问的解决方法
- 解决 Silverlight 调用 WCF 服务 跨域访问 和 Silverlight 引用服务后配置文件不加载的问题
- Silverlight2 跨域调用Web服务的方法
- 关于WCF的“调用方未由服务进行身份验证”的另一解决方法