跨域访问和防盗链基本原理(二)
原文出处: 童燕群
(@童燕群)
- <script type=”text/javascript” src=”jquery.js”></script>
- <script type=”text/javascript”>
- $.getJSON(“http://crossdomain.com/services.php?callback=?“,
- function(result) {
- for(var i in result) {
- alert(i+”:”+result[i]);//循环输出a:1,b:2,etc.
- }
- });
- </script>
2、CORS(Cross-origin resource sharing)跨域访问
上述的JSONP由于有诸多限制,已经无法满足各种灵活的跨域访问请求。现在浏览器支持一种新的跨域访问机制,基于服务端控制访问权限的方式。简而言之,浏览器不再一味禁止跨域访问,而是需要检查目的站点返回的消息的头域,要检查该响应是否允许当前站点访问。通过HTTP头域的方式来通知浏览器:
JavaScript
Response headers[edit] Access-Control-Allow-Origin
Access-Control-Allow-Credentials Access-Control-Expose-Headers
Access-Control-Max-Age Access-Control-Allow-Methods
Access-Control-Allow-Headers
1
2
3
4
5
6
7
|
Response headers[edit]
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Expose-Headers
Access-Control-Max-Age
Access-Control-Allow-Methods
Access-Control-Allow-Headers
|
服务端利用这几个HTTP头域通知浏览器该资源的访问权限信息。在访问资源前,浏览器会先发出OPTIONS请求,获取这些权限信息,并比对当前站点的脚本是否有权限,然后再将实际的脚本的数据请求发出。发现权限不允许,则不会发出请求。逻辑流程图为:
浏览器也可以直接将GET请求发出,数据和权限同时到达浏览器端,但是数据是否交给脚本处理需要浏览器检查权限对比后作出决定。
一次具体的跨域访问的流程为:
因此权限控制交给了服务端,服务端一般也会提供对资源的CORS的配置。
跨域访问还有其他几种方式:本站服务端代理、跨子域时使用修改域标识等方法,但是应用场景的限制更多。目前绝大多数的跨域访问都由JSONP和CORS这两类方式组成。
1 赞 1 收藏
评论
1、JSONP跨域访问
利用浏览器的Referer方式加载脚本到客户端的方式。以:
<script type=”text/javascript”
src=”http://api.com/jsexample.js"></script>
1
|
<script type="text/javascript" src="http://api.com/jsexample.js"></script>
|
这种方式获取并加载其他站点的JS脚本是被允许的,加载过来的脚本中如果有定义的函数或者接口,可以在本地使用,这也是我们用得最多的脚本加载方式。但是这个加载到本地脚本是不能被修改和处理的,只能是引用。
而跨域访问需要正是访问远端抓取到的数据。那么能否反过来,本地写好一个数据处理函数,让请求服务端帮助完成调用过程?JS脚本允许这样。
<script type=”text/javascript”> var localHandler = function(data)
{
alert(‘我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:’
- data.result); }; </script> <script type=”text/javascript”
src=”http://remoteserver.com/remote.js"></script>
1
2
3
4
5
6
7
|
<script type="text/javascript">
var localHandler = function(data)
{
alert(‘我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:’ + data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
|
远端的服务器上面定义的remote.js是这样的:
JavaScript
localHandler({“result”:”我是远程js带来的数据”});
1
|
localHandler({"result":"我是远程js带来的数据"});
|
上面首先在本地定义了一个函数localHandler,然后远端返回的JS的内容是调用这个函数,返回到浏览器端执行。同时在JS内容中将客户端需要的数据返回,这样数据就被传输到了浏览器端,浏览器端只需要修改处理方法即可。这里有一些限制:1、客户端脚本和服务端需要一些配合;2、调用的数据必须是json格式的,否则客户端脚本无法处理;3、只能给被引用的服务端网址发送get请求。
<script type=”text/javascript”> var localHandler = function(data)
{
alert(‘我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:’
- data.result); }; </script> <script type=”text/javascript”
src=”http://remoteserver.com/remote.php?callBack=localHandler"></script>
1
2
3
4
5
6
7
|
<script type="text/javascript">
var localHandler = function(data)
{
alert(‘我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:’ + data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.php?callBack=localHandler"></script>
|
服务端的PHP函数可能是这样的:
PHP
<?php $data = “…….”; $callback = $_GET[‘callback’]; echo
$callback.'(‘.json_encode($data).’)’; exit; ?>
1
2
3
4
5
6
7
8
|
<?php
$data = "…….";
$callback = $_GET[‘callback’];
echo $callback.'(‘.json_encode($data).’)’;
exit;
?>
|
这样即可根据客户端指定的回调拼装调用过程。
Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web
站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web
应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest
函数获取数据,它是一种
API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多
mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。
二、跨域访问基本原理
在上一篇,介绍了盗链的基本原理和防盗链的解决方案。这里更深入分析一下跨域访问。先看看跨域访问的相关原理:跨网站指令码。维基上面给出了跨站访问的危害性。从这里可以整理出跨站访问的定义:JS脚本在浏览器端发起的请求其他域(名)下的网站数据的HTTP请求。
这里要与referer区分开,referer是浏览器的行为,所有浏览器发出的请求都不会存在安全风险。而由网页加载的脚本发起请求则会不可控,甚至可以截获用户数据传输到其他站点。referer方式拉取其他网站的数据也是跨域,但是这个是由浏览器请求整个资源,资源请求到后,客户端的脚本并不能操纵这份数据,只能用来呈现。但是很多时候,我们都需要发起请求到其他站点动态获取数据,并将获取到底数据进行进一步的处理,这也就是跨域访问的需求。
现在从技术上有几个方案去解决这个问题。
3、如何使用JSONP?
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP
服务返回打包在函数调用中的 JSON
响应,而函数调用是由浏览器执行的,这使宿主 Web
应用程序更容易受到各类攻击。如果打算使用 JSONP
服务,了解它能造成的威胁非常重要。
Js代码
此时,服务器先生成 json 数据。
然后以 javascript 语法的方式,生成一个function , function
名字就是传递上来的参数 jsonp.
$.getJSON
$.ajax
$.get
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。
- <meta content=”text/html; charset=utf-8″ http-equiv=”Content-Type” />
- <script type=”text/javascript”>
- function jsonpCallback(result) {
- alert(result.a);
- alert(result.b);
- alert(result.c);
- for(var i in result) {
- alert(i+”:”+result[i]);//循环输出a:1,b:2,etc.
- }
- }
- </script>
- <script type=”text/javascript” src=”http://crossdomain.com/services.php?callback=jsonpCallback"></script>
Jsonp原理:
正规网赌平台,首先在客户端注册一个callback, 然后把callback的名字传给服务器。
理解同源策略限制
Html代码
下边这一DEMO实际上是JSONP的简单表现形式,在客户端声明回调函数之后,客户端通过script标签向服务器跨域请求数据,然后服务端返回相应的数据并动态执行回调函数。
- <script type=”text/javascript” src=”jquery.js”></script>
- <script type=”text/javascript”>
- $.ajax({
- url:”http://crossdomain.com/services.php“,
- dataType:’jsonp’,
- data:”,
- jsonp:’callback’,
- success:function(result) {
- for(var i in result) {
- alert(i+”:”+result[i]);//循环输出a:1,b:2,etc.
- }
- },
- timeout:3000
- });
- </script>
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script
tags返回至客户端,通过javascript
callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
JSON is a subset of the object literal notation of JavaScript. Since
JSON is a subset of JavaScript, it can be used in the language with no
muss or fuss.
2、JSONP有什么用?
主要提示:
1、什么是JSONP?
服务端PHP代码 (services.php):
- JSON在服务端语言的支持不像XML那么广泛,不过JSON.org上提供很多语言的库。
- 如果你使用eval()来解析的话,会容易出现安全问题。
- jsonpCallback({msg:’this is json data’})
- <?php
- //服务端返回JSON数据
- $arr=array(‘a’=>1,’b’=>2,’c’=>3,’d’=>4,’e’=>5);
- $result=json_encode($arr);
- //echo $_GET[‘callback’].'(“Hello,World!”)’;
- //echo $_GET[‘callback’].”($result)”;
- //动态执行回调函数
- $callback=$_GET[‘callback’];
- echo $callback.”($result)”;
- <meta content=”text/html; charset=utf-8″ http-equiv=”Content-Type” />
- <script type=”text/javascript”>
- function jsonpCallback(result) {
- //alert(result);
- for(var i in result) {
- alert(i+”:”+result[i]);//循环输出a:1,b:2,etc.
- }
- }
- var JSONP=document.createElement(“script”);
- JSONP.type=”text/javascript”;
- JSONP.src=”http://crossdomain.com/services.php?callback=jsonpCallback“;
- document.getElementsByTagName(“head”)[0].appendChild(JSONP);
- </script>
客户端浏览器,解析script标签,并执行返回的 javascript
文档,此时数据作为参数,传入到了客户端预先定义好的 callback
函数里.(动态执行回调函数)