赞
踩
同源策略(Same Origin Policy): 同源是指域名,协议,端口完成一致,那么这两个url就是同源。同源策略是一种约定,它是浏览器最核心也最基本的安全功能,也是浏览器故意设置的一个功能限制。如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。使用代码window.origin或者location.origin可以获取当前的源。源 = 协议+域名+端口号。
同源情况下的限制行为:
但是有三个标签是允许跨域加载资源:
<img src=XXX>
, <link href=XXX>
, <script src=XXX>
跨域指的是协议(protocol ),域名(host),端口号(post)都不相同的资源之间尝试着进行交互通信,而由于受浏览器同源策略的限制,无法正常进行交互通信。
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js 访问 http://www.a.com/b.js | 同一域名 | 允许 |
http://www.a.com/user/a.js 访问 http://www.a.com/order/b.js | 同域名不同路径 | 允许 |
http://www.a.com:8000/a.js 访问 http://www.a.com/b.js | 同域名不同端口 | 不允许 |
http://www.a.com/a.js 访问 https://www.a.com/b.js | 同域名不同协议 | 不允许 |
http://www.a.com/a.js 访问 http://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.js 访问 http://m.a.com/b.js | 主域相同,子域不同 | 不允许(cookie这种情况下也不允许访问) |
http://www.a.com/a.js 访问 http://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.baidu.com/a.js 访问 http://www.csdn.com/b.js | 不同域名 | 不允许 |
限制跨域的原因:
例如一个用户登录网银,进行操作,Cookie会生成,并存储在浏览器中。接着,用户无意点入一个钓鱼网址,这个钓鱼网站得到网银的Cookie, 读取你的用户信息,然后通过跨域请求网银,对用户的网银账号进行操作。
钓鱼网站的JS请求和网银网站的JS请求几乎没有区别,referrer有区别,但是如果后台程序员不做检查,就完全没有区别。
结论:如果浏览器不限制跨域,这种情况下,用户的信息安全得不到保障,任何网站都有可能任意访问,请求到用户的信息,操作行为等等。
JSONP是利用浏览器对script的资源引用没有同源限制,通过动态插入一个script标签,当资源加载到页面后会立即执行的原理实现跨域的。JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
JSONP只支持GET请求而不支持POST等其它类型的HTTP请求,它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题,JSONP的优势在于支持老式浏览器,弊端也比较明显:需要客户端和服务端定制进行开发,服务端返回的数据不能是标准的Json数据,而是callback包裹的数据。
前端请求:
$.ajax({ url: "http://otherdomain.com/manage/role/get", async: false, type: "get", 5 dataType: "jsonp", data:{ "id":1 }, jsonp: "callback", jsonpCallback:"fn", success: function(data){ alert(data.code); }, error: function(){ alert('fail'); } })
后端响应:
@RequestMapping("/manage/role/get") @ResponseBody public String get(HttpServletRequest request, HttpServletResponse response) { BaseOutput outPut = new BaseOutput(); try { QueryFilter filter = new QueryFilter(request); logger.info(filter.toString()); String id = filter.getParam().get(MainConst.KEY_ID); if(!StringUtil.isEmpty(id)) { ImRole role = roleService.getByPk(filter); outPut.setData(role); } else { outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL); outPut.setMsg("The get id is needed."); } } catch (Exception e) { logger.error("获取角色数据异常!", e); outPut.setCode(OutputCodeConst.UNKNOWN_ERROR); outPut.setMsg("获取角色数据异常! " + e.getMessage()); } return "fn("+JsonUtil.objectToJson(outPut)+")"; }
注意:
1.Ajax请求需要设置请求类型为Jsonp
dataType: "jsonp"
2.Ajax请求需要设置回调函数,当前函数值必须与服务器响应包含的callback名称相同
jsonpCallback:"fn"
3.Ajax请求可以设置jsonp(可选),传递给请求处理程序或页面,用以获得jsonp回调函数名的参数名,默认为:callback
jsonp: "callback"
4.服务端返回Json数据必须使用jsonpCallback设置的值进行包裹
return "fn("+JsonUtil.objectToJson(outPut)+")"
CORS是现代浏览器支持跨域资源请求的一种方式,全称是"跨域资源共享"(Cross-origin resource sharing),当使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
CORS与JSONP的使用目的相同,但是比JSONP更强大,CORS支持所有的浏览器请求类型,承载的请求数据量更大,开放更简洁,服务端只需要将处理后的数据直接返回,不需要再特殊处理。
前端请求:
function test() { $.ajax({ url: "http://localhost:8080/AdsServer/manage/role/get", type: "get", async: false, data:{ "id":1 }, dataType:"json", withCredentials:true, success: function(data){ alert(data); alert(data.code); }, error: function(){ alert('fail'); } }) }
后端响应:
@RequestMapping("/manage/role/get") @ResponseBody public String get(HttpServletRequest request, HttpServletResponse response) { BaseOutput outPut = new BaseOutput(); try { QueryFilter filter = new QueryFilter(request); logger.info(filter.toString()); String id = filter.getParam().get(MainConst.KEY_ID); if(!StringUtil.isEmpty(id)) { ImRole role = roleService.getByPk(filter); outPut.setData(role); } else { outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL); outPut.setMsg("The get id is needed."); } } catch (Exception e) { logger.error("获取角色数据异常!", e); outPut.setCode(OutputCodeConst.UNKNOWN_ERROR); outPut.setMsg("获取角色数据异常! " + e.getMessage()); } return JsonUtil.objectToJson(outPut); }
服务端增加过滤拦截器(web.xml):
<filter>
<filter-name>crossDomainFilter</filter-name>
<filter-class>com.luwei.core.filter.CrossDomainFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossDomainFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
服务端增加过滤拦截器(java):
package com.luwei.core.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.luwei.console.mg.constant.ApplicationConfiConst; /** */ public class CrossDomainFilter implements Filter { private Logger logger = LoggerFactory.getLogger(getClass()); public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { ApplicationConfiConst confiConst = (ApplicationConfiConst) ContextUtil.getBean("applicationConfiConst"); HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; String referer = request.getHeader("referer"); String origin = null; if (null != referer) { String[] domains = confiConst.getCanAccessDomain().split(","); for (String domain : domains) { if (StringUtils.isNotEmpty(domain) && referer.startsWith(domain)) { origin = domain; break; } } } response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); // 是否支持cookie跨域 response.addHeader("Access-Control-Allow-Credentials", "true"); String requestURI = ((HttpServletRequest) req).getRequestURI(); long begin = System.currentTimeMillis(); chain.doFilter(req, res); if (logger.isDebugEnabled()) { logger.debug("[Request URI: " + requestURI + "], Cost Time:" + (System.currentTimeMillis() - begin) + "ms"); } } }
增加设置能够通过跨域访问的服务器地址:
#设置能够访问接口的域(多个通过都好分割)(不能配置127.0.0.1)
CAN_ACCESS_DOMAIN=http://localhost:8020,http://localhost:9999,http://localhost:8080
注意:
1.Ajax请求必须要设置withCredentials属性为true
withCredentials:true
2.服务端需要配置过滤器,讲配置能够进行跨域访问服务器的地址进行配置
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
// 是否支持cookie跨域
response.addHeader("Access-Control-Allow-Credentials", "true");
3.withCredentials设置成true时,Access-Control-Allow-Origin不支持通过*的方式进行统配
4.Access-Control-Allow-Origin不能直接配置多个请求服务器,但是可以通过静态配置多个的方式,然后根据referer匹配,匹配到哪个则设置Access-Control-Allow-Origin为哪个的方式来配置多个
5.jqGrid配置跨域请求的方式为:
ajaxGridOptions: {
xhrFields: {
withCredentials: true
}
},
当网站通过 JSONP 的方式来跨域传递用户认证后的敏感信息时, 如果 服务端对 JSONP 的请求来源校验不严格,那么攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者访 问达到截取用户敏感信息的目的。
jsonp 与 csrf 类似,都是需要用户登录帐号,身份认证还没有被消除的情况下访问攻击者精心设计好的的页面。就会获取 json 数据,把 json 数据发送给攻击者。
利用过程:寻找敏感 json 数据 api 接口,构造恶意的代码。 发送给用户,用户访问有恶意的页面,数据会被劫持发送到远程服务器。
产生漏洞的原因 : 网站没有对 JSONP 请求来源进行校验和过滤导致任意域都能够获取数据。
因为同源策略的存在,不同源的客户端脚本不能访问目标站点的资源,如果目标站点 CORS 配置不 当,没有对请求源的域做严格限制,导致任意源都可以访问时,就存在cors 跨域漏洞题。
原理:攻击者可以利用 Web 应用对用户请求数据包的 Origin 头校验不严格,诱骗受害者访问攻击者制作 好的恶意网站,从而跨域获取受害者的敏感数据。
注意关键字:
Access-Control-Allow-Origin :指定哪些外域可以访问本域资源;
Access-Control-Allow-Credentials :指定浏览器是否将使用请求发送 Cookie 。仅当设置 true
时,才会发送 Cookie ;默认是 false
Access-Control-Allow-Methods :指定可以使用哪些 HTTP 请求方法( GET 、 POST 、 PUT 、 DELETE 等)来访问资源;
Access-Control-Allow-Headers :指定可以在请求报文中添加的 HTTP 头字段;
Access-Control-Max-Age :指定超时时间;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。