JavaScript(XMLHttpRequest)跨域访问解决办法及安全性问题

原文地址: http://kennylee26.iteye.com/blog/359399
关于具体的JavaScript安全机制,推荐请查看《JavaScript.The.Definitive.Guide.5th.Edition》。 

网上解决跨域问题的文章不少,但都笼统的说了一下“因为JavaScript的安全框架”直接就跳过原因了,本着寻根问底的心态钻研了下。 

关于JavaScript的安全性请记住一下几点,是简短的从《JavaScript.The.Definitive.Guide.5th.Edition》(我叫她"大犀牛")转述一下...注意不同浏览器也有不同限制: 

    1. JavaScript不能增删改查用户客户端的任何数据。  

    2. 无法打开socket或者接受其他主机请求。  

     注:如果没有了上面两条的话,网络变成什么世界就无法想象了。 

    3. 新建窗口事件只有在用户鼠标点击事件才能触发。  

    4. 鼠标移动到连接地址时,状态栏要显示确切地址。  

      这个几年前比较常常看到的网页特效,在状态栏写着日期或者"欢迎之类",其实这样的后果是访问者无法查看当前鼠标停放的url的地址。有可能造成触碰到钓鱼陷阱。 

    5. 无法打开边距小于100像素的窗口。  

    6. fileupload属性value值无法设置。  
      也许这个不好理解,但是如果可以设置的话,将有可能造成把你的某指定文件上传到服务器的后果。 

    7. 同源策略(The Same-Origin Policy)注意对于cookie也同样适用。  


关于JavaScript跨站访问(Cross-Site) 

跨域访问的问题在于第7点,首先理解脚本本身的来源与同源策略不相关。即B域调用A域的脚本(通过script的src),可以完全的访问B域的文档内容。但如果访问A域或者C域的话同源策略就发挥作用。 


同源指的是: 同协议同域名并且同端口。缺一不可 。 
(我解释一下,假设A服务器上的index.htm中引用了B服务器上的xmlrequest.js, 在xmlrequest.js中,就只能访问处A服务器上的内容,并且端口也一样才能访问。written by ryz)

    某些情况下,同源策略会显得太严谨了。但在安全性的前提下,我们还是可以有解决办法的。这些解决办法跟安全性框架没任何冲突,除非它是浏览器的一个漏洞。 

1、主域相同,子域之间的访问。  

使用document的domain属性,默认情况下存放装载文档的服务器主机名。 

例如,现在两个域,home.example.com和developer.example.com。 

这两个域之间想互相装载文档属性的话是完全符合需求的,可以把document.domain属性设置为"example.com"。另注意domain的值至少要有一个点号。 

此时文档就有同源性可以互相访问了。 


2、主域不相同。  

目前有两种解决办法,但是归根到底还是通过proxy实现。 


proxy的作用: 

proxy位于文档本域,作用是用来访问远程的资源并且返回给JavaScript。 


一、使用AJAX XMLHttpRequest. 

使用JavaScript构造XMLHttpRequest请求然后通过proxy获取资源。 


二、使用script标签. 

通过使用script标签设置src为proxy获取资源,然后可以得到得到远程数据。 

其实以上两种解决办法还是基于“发送请求的操作然后获取服务端的数据”。比较推荐使用AJAX,但直接使用script标记的话会很方便,并且门槛应该相对低点。 

另,还有一些是关于iframe的解决办法和情况没考虑,但暂时没遇到,先不考虑了,而且觉得情景也比较少。 

附上java写的Proxy代码(jsp) 
Java代码   收藏代码
  1. <%@ page language="java" pageEncoding="UTF-8"%>  
  2. <%@ page import="java.util.Map,java.util.HashMap,java.util.Enumeration"%>  
  3. <%--  
  4. /** 
  5.  * 为解决JavaScript跨域访问资源时,遇到因同源策略而造成访问资源失败的问题。 
  6.  * (而实际上,使用AJAX的XMLHttpRequest时碰到这种情况的几率居多。) 
  7.  * 
  8.  * 使用此代理可以实现请求转发: 
  9.  *      把跨域的资源信息获取回本域,然后再把该信息响应给本域提交请求的对象。 
  10.  * 
  11.  * 中文编码问题: 跨域资源返回时都做了decode操作,默认UTF8编码。 
  12.  * 
  13.  * 参数问题: 访问此代理的参数中必须含有url的参数,作为跨域访问的目标url对象。 
  14.  *          除了url参数外的其他参数,将生成为跨域访问时目标url的参数,共同转发过去。 
  15.  * 
  16.  * @author KennyLee E-mail:kennylee26@gmail.com 2009-2-25 
  17.  *  
  18.  */  
  19.  --%>  
  20. <%  
  21.     String url = null;  
  22.     Map<String, String> req_map = new HashMap<String, String>();  
  23.     Enumeration<?> _enum = request.getParameterNames();  
  24.     while (_enum.hasMoreElements()) {  
  25.         String paramName = (String) _enum.nextElement();  
  26.         String paramValue = request.getParameter(paramName);  
  27.         req_map.put(paramName, paramValue);  
  28.     }  
  29.     if (!req_map.isEmpty())  
  30.         url = req_map.remove("url");  
  31.     if ((url != null) && (url.length() > 0)) {  
  32.         if (!req_map.isEmpty()) {  
  33.             StringBuffer url_sbf = new StringBuffer(url);  
  34.             for (Map.Entry<String, String> entry : req_map.entrySet()) {//generate parameters  
  35.                 String _par_key = entry.getKey();  
  36.                 String _par_value = entry.getValue();  
  37.                 if (_par_key != null && _par_key != "") {  
  38.                     if (url_sbf.indexOf("?") == -1)  
  39.                         url_sbf.append("?");  
  40.                     else  
  41.                         url_sbf.append("&");  
  42.                     url_sbf.append(_par_key).append("=").append(  
  43.                             _par_value);  
  44.                 }  
  45.             }  
  46.             url = url_sbf.toString();  
  47.         }  
  48.         java.net.URL _url = new java.net.URL(url);  
  49.         java.net.URLConnection urlcon = _url.openConnection();  
  50.         java.io.InputStream is = urlcon.getInputStream();  
  51.         java.io.BufferedReader buffer = new java.io.BufferedReader(  
  52.                 new java.io.InputStreamReader(is));  
  53.         StringBuffer bs = new StringBuffer();  
  54.         String lineStr = null;  
  55.         while ((lineStr = buffer.readLine()) != null) {  
  56.             String stri = java.net.URLDecoder.decode(lineStr, "UTF-8");  
  57.             bs.append(stri).append("\n");  
  58.         }  
  59.         if (bs.toString().indexOf("<?xml version=") != -1) {//if XML file, for AJAX  
  60.             response.setContentType("text/xml; charset=UTF-8");  
  61.             response.setHeader("Cache-Control""no-cache");  
  62.             out.println(bs.toString());  
  63.         } else  
  64.             out.println(bs.toString());  
  65.     }  
  66. %>  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 跨域访问是指在浏览器中,通过JavaScript代码从一个域名的网页去请求另一个域名的资源时,会被同源策略所限制而无法正常访问。为了解决这个问题,我们需要通过设置HTTP响应标头来允许跨域访问。 在HTTP响应中,我们可以设置一些特殊的标头,如"Access-Control-Allow-Origin"、"Access-Control-Allow-Methods"、"Access-Control-Allow-Headers"等来控制在跨域请求时的行为。 "Access-Control-Allow-Origin"标头用于指定允许访问该资源的域,可以设置为具体的域名或通配符"*",表示允许任何域进行访问。 "Access-Control-Allow-Methods"标头用于指定允许的请求方法,如GET、POST、PUT等。 "Access-Control-Allow-Headers"标头用于指定允许的请求头,如Content-Type、Authorization等。 除了以上标头,还可以使用其他一些标头来进一步控制跨域请求。此外,在前端代码中,还需要使用XMLHttpRequest对象或Fetch API发送请求时,设置"withCredentials"为true,并在后端服务器中作出相应的处理,允许发送带有身份凭证的跨域请求。 需要注意的是,在设置跨域访问的时候,应该明确指定允许访问的域名,避免未经授权的域名访问可能引发的安全问题。 通过设置HTTP响应标头,我们可以解决跨域访问问题,实现不同域名之间的数据交互与资源共享。 ### 回答2: 跨域访问是指在Web开发中,浏览器执行JavaScript代码请求不同源的资源时,由于浏览器的同源策略限制,会导致请求失败。为了实现跨域访问,我们需要在服务器端设置HTTP响应标头。 常见的跨域访问解决方案是使用CORS(跨域资源共享)。在服务器端设置CORS标头,允许特定的源发起跨域请求。通过设置标头中的"Access-Control-Allow-Origin"字段,可以指定允许请求的源。例如,设置为"*"表示允许任何源发起请求。 另一个常见的解决方案是使用JSONP(JSON with Padding)。JSONP利用了script标签不受同源策略限制的特性。通过在服务器端返回一个回调函数的调用,将数据作为参数传递给回调函数,实现跨域数据的获取。 除了CORS和JSONP,还可以使用代理服务器来解决跨域访问问题。在客户端发送请求时,将请求发送至代理服务器,然后代理服务器再将请求转发至目标服务器,并将响应返回给客户端。这种方式绕过了浏览器的同源策略限制。 在设置HTTP响应标头的时候,需要注意安全性的考虑。过于宽松的设置可能导致跨域攻击。因此,我们应该根据需求明确允许的来源,并考虑设置其他相关的CORS标头字段,比如"Access-Control-Allow-Methods"和"Access-Control-Allow-Headers"等。 总之,跨域访问需要通过在服务器端设置HTTP响应标头来解决限制问题。CORS、JSONP和代理服务器是常见的实现跨域访问解决方案。合理设置标头字段可以确保安全性和功能的平衡。 ### 回答3: 跨域访问是指在Web开发中,浏览器中运行的一个网页,向另一个域名下的资源发起请求,但是由于浏览器的同源策略限制,跨域请求是被禁止的。为了解决这个问题,需要在服务器的http响应标头中进行设置。 首先,服务器需要在响应中设置Access-Control-Allow-Origin标头,该标头指定了被允许进行跨域访问的原始域名。可以设置为"*"表示允许来自所有域名的访问,也可以设定为特定的域名,例如"www.example.com"。 其次,服务器还可以设置其他的Access-Control-Allow-*标头,来进一步控制跨域请求的细节。例如,Access-Control-Allow-Methods标头可以指定允许的HTTP方法,Access-Control-Allow-Headers标头可以指定允许的HTTP头,Access-Control-Max-Age标头可以设定预检请求的有效期等。 此外,如果在跨域请求中使用了携带身份凭证的cookie,还需要设置Access-Control-Allow-Credentials标头为true,以允许携带凭证。 综上所述,跨域访问需要在服务器的http响应标头中设置相关的Access-Control-*标头,以允许来自其他域名的请求访问服务器的资源。通过设置合适的标头,就可以在一定程度上解决跨域访问的限制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值