Javascript跨站点访问

本文介绍了浏览器的同源策略(SOP)及其对JavaScript跨域访问的限制。探讨了多种突破SOP的方法,包括服务端集成、服务端代理、JSONP、CORS及iframe等,并分析了各自的优缺点。

如何让javascript访问一个和自己所在网站的域名不一样网站?

什么是SOP

在浏览器的设计上有一个SOP (Same Origin Policy),就是相同源政策,是指浏览器只允许javascript访问与当前页面有相同源服务器的资源。这里所谓的同源服务器,是指协议端口和域名都一样。这一政策的目的是为了让浏览器更安全。下面一个例子演示了SOP。为了测试方便,通过修改hosts文件把 test1.com test2.com都指向本机。在apache的htdocs下放以下程序。 sop.php

<html> 
    <head> 
        <script src="js/jquery.js" type="text/javascript"></script> 
    </head> 
    <body> 
        <div id="container"></div> 
        <script type="text/javascript"> 
        $(document).ready(function(){ 
            $.get( "http://test2.com/data.txt", function(data){ 
                $("#container").html(data); 
            } ); 
        }); 
        </script> 
    </body> 
</html>

 data.txt test2.com data 通过浏览器访问 http://test1.com/sop.php,如果没有sop的话,那么应该能在页面里看到test2.com data字样,因为这个程序里面用ajax读取http://test2.com/data.txt的内容放到了id是container的元素内。但是事实上在ie, firefox, chrome几个浏览器下面均看到不到,而且在chrome下面,还会有明确的出错提示: XMLHttpRequest cannot load http://test2.com/data.txt. Origin http://test1.com is not allowed by Access-Control-Allow-Origin.

如何突破SOP

如果真的需要在当前页面里面显示和当前页面非同源的资源,那该怎么办呢?有以下几种方案。

服务端集成

在服务器上,用程序读取远程信息,然而生成到页面中。困为是在服务端,所以当然不会用浏览器的SOP限制了。但是这样一来会增加服务端的集成难度,没有在客户端集成灵活,生成页面的响应时间也更长,因为用户必须等到服务端接收并处理完非同源的资源后,才能收到页面。

服务端代理

这个方法就是建一个同源的反向代理服务器,把非同源的资源转化成了同源的。这样做不违反SOP,也能做客户端集成了,但是要搭建专用的服务器,而且比直接访问资源更慢,当然你可以通过增加缓存来提高性能。

采用JSONP

JSONP利用了script元素的一个例外来实现的。尽管你不能在javascript程序里面直接访问非同源资源,但是却可以通过script载入非同源的资源,比如:

<script type="text/javascript" src="http://test2.com/jsonpdata.php" ></script> 

就算这个段代码所在的页面是test1.com,也能载入这个js。但是很多时候,我们是要数据,而不是要javascript程序,如果http://test2.com/jsonpdata.php只返回一段json的话,那么在当前页面我们并没有办法使用它。怎么办呢?前人想到的办法是在请求json的时候约定一个函数名,返回的json数据直接被个函数调用。看下面的例子,就明白了。

jsonp.php

<html> 
<head></head> 
<body> 
<div id="container"></div> 
<script type="text/javascript"> 
function myfunc(data) { 
	document.getElementById("container").innerHTML = data; 
} 
var remoteUrl = "http://test2.com/jsonpdata.php?callback=myfunc"; 
var scriptElement = document.createElement("script"); 
scriptElement.type = "text/javascript"; 
scriptElement.src = remoteUrl; 
document.body.appendChild(scriptElement); 
</script> 
</body> 
</html> 

 jsonpdata.php

<?php echo $_REQUEST['callback'] ?>('test2.com data');

 上面的例子中,

  1. 先设定好回调函数myfunc
  2. 再组装一个script元素,并在src地址后面加上callback=myfunc
  3. 把这个元素放到dom里面,不论是不是同源,浏览器都会自动地载入src所指的javascript
  4. jsonpdata.php生成的代码是 myfunc('test2.com data'); 
  5. 浏览器立即执行这段javascript,前面定义的好的myfunc就被调用了

这个方法巧妙地绕过了SOP,但是要求服务端必须支持jsonp,即在生成的数据前面加上回调函数的名字。如果非同源的资源并不支持jsonp,那这招就没用了。

CORS

jsonp有些旁门左道的感觉,于是有人针对性地提出对http协议的改进,就是Cross Origin Resource Sharing。这个要求服务器和客户端都支持才行。客户端在请求非同源资源时在HTTP头部加上 Origin: test1.com类似的信息,然后非同源服务器返回的头部带上诸如Access-Control-Allow-Origin样的头部,来指明是否可以共享。这个好像比较复杂,我在本地测试了一下,chrome 12.0.742.100 好像还是有问题,明明我已经在Response头部加上了 Access-Control-Allow-Origin: test1.com,但是还是没有成功。看来这个技术还有待于被各家浏览器接受和实现。更多信息参看 http://www.w3.org/TR/cors/

利用iframe

这个没有违返SOP,实现了在当前页面里显示非同源的资源,尽管事实上不是在一个frame里面,也没有用javascript跨源访问,但是看起来像是在同一个页面就行了。google adsense就是这么做的,可见这个技术是成熟可靠的。具体怎么做,就不说了。

总结

如果可以的话,jsonp是最简单灵活方便的,cors还需要时间成长,iframe用来处理单纯地嵌入页面展示最方便了,但也要非同源资源处理好展示效果。实在不行就在server端集成,或者搞个代理算了。

转载于:https://my.oschina.net/komodo/blog/919179

跨站访问被禁止通常有以下原因: - **跨站请求伪造(CSRF)风险**:攻击者可通过设置陷阱,强制已认证用户进行非预期的状态更新,如个人信息变更等,为保障用户信息安全,系统可能禁止跨站访问以避免此类攻击发生[^1]。 - **同源策略限制**:浏览器的同源策略旨在防止不同源的网页之间的不安全交互。若站的请求来自不同源(协议、域名、端口任一不同),浏览器会默认禁止该跨站请求,以此来保护用户数据不被非法获取和篡改。 - **安全配置要求**:网站管理员为增强安全性,会在服务器端设置严格的访问控制规则,阻止来自不信任源的跨站请求,以降低潜在的安全威胁。 相应的解决方法如下: - **CSRF防护**: - **使用验证码**:在关键操作(如用户信息修改、资金交易等)时要求用户输入验证码,确保是用户本人在操作,而不是攻击者伪造的请求。 - **验证请求来源**:服务器端检查请求的来源,只允许来自可信域名的请求通过。可以通过检查HTTP头中的Referer字段或Origin字段来实现。 - **使用CSRF令牌**:在表单或请求中添加一个随机生成的令牌,服务器端在处理请求时验证该令牌的有效性。例如在HTML表单中添加一个隐藏字段存储CSRF令牌。 - **跨域资源共享(CORS)配置**:服务器端配置CORS,明确允许哪些源可以访问其资源。通过设置响应头(如Access - Control - Allow - Origin)来指定允许访问的域名,允许浏览器进行跨站请求。例如在Node.js的Express框架中可以这样配置: ```javascript const express = require('express'); const app = express(); app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', 'https://example.com'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); }); ``` - **JSONP(JSON with Padding)**:对于不支持CORS的旧浏览器,可以使用JSONP技术。JSONP利用`<script>`标签的src属性不受同源策略限制的特,通过动态创建`<script>`标签来实现跨站数据请求。但JSONP只支持GET请求,且存在一定的安全风险。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值