《回头再说:jQuery跨域原理》一文提到浏览器的同源策略以及使用JsonP的方式实现跨域;<wbr></wbr>在评论中金色海洋提出了一个问题:
我最近在用 uploadify + ashx 来做文件上传的功能。都测试成功了,<wbr></wbr>但是发现我可以提交到其他的网站里面。
我是在本地测试了。两个网站,IP地址相同,使用端口来区分。
一个端口是8001,另一个是8002 。
两个网站都有上传文件的程序,我发现,<wbr></wbr>如果我把8001端口的站点的
'script': '/_CommonPage/UploadHandler.<wbr></wbr>ashx',
改成
'script': 'http://192.168.0.1:8002/_<wbr></wbr>CommonPage/UploadHandler.ashx'<wbr></wbr>,
居然也能够成功上传文件,传到了8002对应的网站里面。
我不知道如果换成域名了,是否也是可以往不同的域名里上传文件?
如果是的话,是不是很危险?如何来验证呢?
我给出的错误解释
看到金色海洋的问题之后,<wbr></wbr>我下载下来Uploadify源码看了一下,<wbr></wbr>然后非常草率的给出了一个解释,点击这里;对于这个错误的解释,<wbr></wbr>园友mx1700提出了质疑;于是下班回家之后,<wbr></wbr>我开始动手模拟金色海洋的环境,试图一探究竟;
Uploadify工作机制
我在VS2010里面新建了一个webApplicatio<wbr></wbr>n,在页面上使用Uploadify,页面代码如下:
< script src ="Scripts/jquery-1.4.1.js" type ="text/javascript" ></ script >
< script src ="Scripts/jquery.uploadify.v2.1.0.js" type ="text/javascript" ></ script >
< script src ="Scripts/swfobject.js" type ="text/javascript" ></ script >
< script type ="text/javascript" >
// <![CDATA[
var id = " 55 " ;
var theString = " asdf " ;
$(document).ready( function () {
$( ' #fileInput ' ).uploadify({
' uploader ' : ' uploadify.swf ' ,
' script ' : ' http://www.b.com:84/Uploader.ashx ' ,
' scriptData ' : { ' id ' : id, ' foo ' : theString },
' cancelImg ' : ' cancel.png ' ,
' auto ' : true ,
' multi ' : true ,
' fileDesc ' : ' Image Files ' ,
' fileExt ' : ' *.jpg;*.png;*.gif;*.bmp;*.jpeg ' ,
' queueSizeLimit ' : 90 ,
' sizeLimit ' : 4000000 ,
' buttonText ' : ' Choose Images ' ,
' folder ' : ' /uploads ' ,
' onAllComplete ' : function (event, queueID, fileObj, response, data) {
}
});
});
// ]]></script>
< input id = " fileInput " name = " fileInput " type = " file " / >
通过排除,我们能有一个基本的判断:<wbr></wbr>文件上传是在Flash里面完成的.<wbr></wbr>那么Flash里面做了什么呢?还好有uploadify.<wbr></wbr>fla文件,使用Flex Builder打开这个文件来看,果然如此,<wbr></wbr>很多朋友没有Flex Builde,这里贴出完整代码;可以看到,
// Upload each file
function uploadFile(file:FileReference, index:int, ID:String, single:Boolean):
实际的上传操作,<wbr></wbr>而上传不同时机使用的很多函数都是定义在jquery.uploadify.v2.1.0.min.js文件里面.
2 Uploadify v2.1.0
3 Release Date: August 24, 2009
4
5 Copyright (c) 2009 Ronnie Garcia, Travis Nickels
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24 */
25
26 import flash.external.ExternalInterface;
27 import flash.net. * ;
28 import flash.events. * ;
29 import flash.display. * ;
30 import com.adobe.serialization.json.JSON;
31
32 // Align the stage to the top left and don't scale it
33 stage.align = StageAlign.TOP_LEFT;
34 stage.scaleMode = StageScaleMode.NO_SCALE;
35
36 // Create all the variables
37 var param:Object = LoaderInfo( this .root.loaderInfo).parameters;
38 var fileRefSingle:FileReference = new FileReference();
39 var fileRefMulti:FileReferenceList = new FileReferenceList();
40 var fileRefListener:Object = new Object();
41 var fileQueue:Array = new Array();
42 var fileItem:Object = new Object();
43 var activeUploads:Object = new Object();
44 var errorArray:Array = new Array();
45 var counter:Number = 0 ;
46 var filesSelected:Number = 0 ;
47 var filesReplaced:Number = 0 ;
48 var filesUploaded:Number = 0 ;
49 var filesChecked:Number = 0 ;
50 var errors:Number = 0 ;
51 var kbs:Number = 0 ;
52 var allBytesLoaded:Number = 0 ;
53 var allBytesTotal:Number = 0 ;
54 var allKbsAvg:Number = 0 ;
55 var allowedTypes:Array;
56 var scriptURL:URLRequest;
57 var variables:URLVariables;
58 var queueReversed:Boolean = false ;
59
60 // For debugging, alert any value to javascript
61 function debug(someValue) {
62 ExternalInterface.call( ' alert(" ' + someValue + ' ") ' );
63 }
64
65 // Trigger a javascript event
66 function $trigger(eventName:String, ... args): void {
67 // Add parenthesis
68 function p(s:String):String {
69 return ( ' ( ' + s + ' ) ' );
70 }
71 // Add quotes
72 function q(s:String):String {
73 return ( ' " ' + s + ' " ' );
74 }
75 var list:Array = [q(eventName)]; // Add the event to the array
76 if (args.length > 0 ) list.push(JSON.encode(args)); // Add arguments to the array as a JSON object
77 ExternalInterface.call([ ' jQuery ' + p(q( ' # ' + param.uploadifyID)), p(list.join( ' , ' ))].join( ' .trigger ' )); // Trigger the event
78 }
79
80 // Random string generator for queue IDs
81 function generateID(len:Number):String {
82 var chars:Array = [ ' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' , ' P ' , ' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' , ' Y ' , ' Z ' ];
83 var ID:String = '' ;
84 var index:Number;
85 for ( var n: int = 0 ; n < len; n ++ ) {
86 ID += chars[Math.floor(Math.random() * 25 )];
87 }
88 return ID;
89 }
90
91 // Load the button image
92 function setButtonImg(): void {
93 if (param.buttonImg) {
94 var btnLoader:Loader = new Loader();
95 var btnImage:URLRequest = new URLRequest(param.buttonImg);
96 browseBtn.addChild(btnLoader);
97 btnLoader.load(btnImage);
98 }
99 if ( ! param.hideButton && ! param.buttonImg) {
100 browseBtn.empty.alpha = 1 ;
101 }
102 }
103 setButtonImg();
104
105 // Hide or show the button
106 function hideButton(hideValue:Boolean): void {
107 if (hideValue) {
108 browseBtn.empty.alpha = 0 ;
109 } else {
110 browseBtn.empty.alpha = 1 ;
111 }
112 }
113
114 // Set the text on the button
115 function setButtonText(): void {
116 if (param.buttonText) {
117 browseBtn.empty.buttonText.text = unescape(param.buttonText);
118 }
119 }
120 setButtonText();
121
122 // This is important for clicking the button correctly
123 browseBtn.buttonMode = true ;
124 browseBtn.useHandCursor = true ;
125 browseBtn.mouseChildren = false ;
126
127 // Set the size of the button
128 function setButtonSize(): void {
129 if (param.hideButton) {
130 browseBtn.width = param.width;
131 browseBtn.height = param.height;
132 }
133 // Set the size of the button on the page
134 ExternalInterface.call( ' jQuery("# ' + param.uploadifyID + ' ").attr("width", ' + param.width + ' ) ' );
135 ExternalInterface.call( ' jQuery("# ' + param.uploadifyID + ' ").attr("height", ' + param.height + ' ) ' );
136 }
137 setButtonSize();
138
139 // Setup the rollover animation
140 if (param.rollover) {
141 browseBtn.addEventListener(MouseEvent.ROLL_OVER, function (event:MouseEvent): void {
142 event.currentTarget.y = - param.height;
143 });
144 browseBtn.addEventListener(MouseEvent.ROLL_OUT, function (event:MouseEvent): void {
145 event.currentTarget.y = 0 ;
146 });
147 browseBtn.addEventListener(MouseEvent.MOUSE_DOWN, function (event:MouseEvent): void {
148 event.currentTarget.y = - (param.height * 2 );
149 });
150 }
151
152 // create the scriptData variable if it doesn't exist
153 if ( ! param.scriptData) {
154 param.scriptData = '' ;
155 }
156
157 // Limit the file types
158 function setAllowedTypes(): void {
159 allowedTypes = [];
160 if (param.fileDesc && param.fileExt) {
161 var fileDescs:Array = param.fileDesc.split( ' | ' );
162 var fileExts:Array = param.fileExt.split( ' | ' );
163 for ( var n = 0 ; n < fileDescs.length; n ++ ) {
164 allowedTypes.push( new FileFilter(fileDescs[n], fileExts[n]));
165 }
166 }
167 }
168 setAllowedTypes();
169
170 // Set or get the variables
171 function uploadify_updateSettings(settingName:String, settingValue) {
172 if (settingValue == null ) {
173 if (settingName == ' queueSize ' ) {
174 return fileQueue.length;
175 }
176 return param[settingName];
177 } else {
17