详解跨域(JSONP和CORS)

一、同源策略

同源策略(Same Origin Policy): 同源是指域名,协议,端口完成一致,那么这两个url就是同源。同源策略是一种约定,它是浏览器最核心也最基本的安全功能,也是浏览器故意设置的一个功能限制。如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。使用代码window.origin或者location.origin可以获取当前的源。源 = 协议+域名+端口号。

同源情况下的限制行为:

  • Cookie、LocalStorage 和 IndexDB 无法读取
  • DOM 和 Js对象无法获得
  • AJAX 请求不能发送

但是有三个标签是允许跨域加载资源:
<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和CORS)

1.JSONP

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)+")"

2.CORS

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}
},

四、跨域应注意漏洞

1.JSONP劫持漏洞

当网站通过 JSONP 的方式来跨域传递用户认证后的敏感信息时, 如果 服务端对 JSONP 的请求来源校验不严格,那么攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者访 问达到截取用户敏感信息的目的。
jsonp 与 csrf 类似,都是需要用户登录帐号,身份认证还没有被消除的情况下访问攻击者精心设计好的的页面。就会获取 json 数据,把 json 数据发送给攻击者。
利用过程:寻找敏感 json 数据 api 接口,构造恶意的代码。 发送给用户,用户访问有恶意的页面,数据会被劫持发送到远程服务器。
产生漏洞的原因 : 网站没有对 JSONP 请求来源进行校验和过滤导致任意域都能够获取数据。

2.CORS漏洞

因为同源策略的存在,不同源的客户端脚本不能访问目标站点的资源,如果目标站点 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 :指定超时时间;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/665066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【开源】JAVA+Vue+SpringBoot实现就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

酷开系统 | 酷开科技智慧AI带你领略神奇的世界

在这个科技日新月异的时代&#xff0c;AI已成为我们生活中不可或缺的一部分。它不仅改变了我们的生活方式&#xff0c;更让我们对未来充满期待。说起酷开系统中智慧AI的强大&#xff0c;着实让人叹为观止。无论是语音识别、数据整理还是语言处理&#xff0c;智慧AI都在不断地突…

MySQL数据库①_MySQL入门(概念+使用)

目录 1. 数据库的概念 1.1 数据库的存储介质 1.2 主流数据库 2. MySQL的基本使用 2.1 链接数据库 2.2 服务器管理 2.3 数据库&#xff0c;服务器和表关系 2.4 简单MySQL语句 3. MySQL架构 4. SQL分类 5. 存储引擎 本篇完。 1. 数据库的概念 数据库是按照数据结构来…

交换机 路由器 网卡 MAC

1. 交换机 (Switch): 交换机是一种局域网设备&#xff0c;用于连接多台计算机和其他网络设备。与集线器不同&#xff0c;交换机能够学习和记忆设备的MAC地址&#xff0c;并且只将数据包发送到目标设备&#xff0c;提高了网络的效率和性能。 逐层转发 (Layer 2 Switching): 交换…

测试大佬是怎么看待测试用例设计的

前言 最近干的最多的事情就是设计测试用例、评审测试用例了&#xff0c;于是我不禁又想到了一个经典的问题&#xff1a;如何设计出优秀的测试用例&#xff1f; 可能有些童鞋看到这个问题会有些不以为然&#xff0c;这有什么好想的&#xff1f;干个测试谁还不会设计测试用例&…

C++(10)——类与对象(最终篇)

目录 static成员 概念 特性 友元 友元函数 友元类 内部类 匿名对象 经过这么多天的分享&#xff0c;C的类与对象终于要结束了。结束也意味着C快要入门了。 static成员 概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之…

mysql二叉树排序例子

⼆叉排序树&#xff0c;理想情况下是⼆分&#xff0c;可能创建时⽐较深&#xff0c;和⼀条线差不多&#xff0c;性能并不⾼。 如果你想在 MySQL 中实现二叉树的排序&#xff0c;一种常见的方法是使用递归查询。以下是一个简单的例子&#xff0c;展示如何对一个具有父子关系的二…

放空自己和终端的clear

clear 造物无言却有情&#xff0c;每于寒尽觉春生。 张维屏《新雷》 没有啥说的&#xff0c;就是放空一下自己&#xff0c;也清空一下终端&#xff0c;仅此而已。 $ clear

基于YOLOv8算法的照片角度分类项目实践

目录 一、任务概述二、YOLOv8算法简介2.1 算法改进2.2 算法特点2.3 网络结构2.4 性能比较 三、工程实践3.1 安装算法框架库ultralytics3.2 库存照片预处理3.2.1 提取所有图片3.2.2 去除冗余的相同照片3.2.3 去除无车辆照片3.2.4 随机提取指定数量的图片 3.3 照片朝向分类3.3.1 …

STM32--USART串口(2)串口外设

一、USART简介 可配置数据位&#xff1a;不需要校验就是8位&#xff0c;需要校验就选9位&#xff1b; 停止位&#xff1a;决定了帧的间隔; STM32F103C8T6USART&#xff1a;USART1挂载在APB2总线上&#xff0c;USART2和USART3挂载在APB1总线上&#xff1b; 二、USART框图 TXE…

excel给数据库初始化/旧数据处理(自动sql拼装)

思路&#xff1a; 首先导出数据到excel编写单条数据操作的sql利用excel CONCATENATE 函数自动生成&#xff0c;每一行数据的操作sql 小技巧:对于需要套娃的字段值&#xff0c;可以加一个临时列同样使用CONCATENATE函数进行sql拼装 案例&#xff1a; 1.临时列:CONCATENATE(C2, …

分库分表 21 条法则,hold 住!

大家好&#xff5e;今天给大家分享分库分表的 21 条法则 我们结合具体业务场景&#xff0c;以t_order表为例进行架构优化。由于数据量已经达到亿级别&#xff0c;查询性能严重下降&#xff0c;因此我们采用了分库分表技术来处理这个问题。具体而言&#xff0c;我们将原本的单库…

【Python小游戏】五子棋小游戏(完整代码)

文章目录 写在前面Tkinter简介五子棋小游戏游戏介绍程序设计运行结果注意事项写在后面写在前面 本期内容:基于tkinter开发一个五子棋小游戏 实验环境 python3.11及以上pycharmtkinterTkinter简介 Tkinter是Python中最常用的图形用户界面(GUI)库之一,用于创建窗口、对话框…

如何搭建私有云盘SeaFile并实现远程访问本地文件资料

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-hsDnDEybLME85dTx {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Web项目利用OSS进行图像存储服务

一、OSS介绍 在Web项目中&#xff0c;一些常见的功能&#xff0c;比如展示图片&#xff0c;修改头像等&#xff0c;都需要进行图片的上传操作&#xff0c;但是如果是存储在Web服务器中&#xff0c;在读取图片的时候会占用比较多的资源&#xff0c;影响服务器的性能。 常…

【数据结构】双向带头循环链表实现及总结

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 1. 双向带头循环链表的实现2. 顺序表和链表的区别 1. 双向带头循环链表的实现 List.h #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h>typede…

fastDFS客户端实现文件上传

一、准备工作 请确保fastDFS的tracker服务和storage服务都是处于启动状态&#xff0c;防火墙是关闭的&#xff1b; 二、具体步骤 1、pom.xml 2、让当前的微服务成为fdfs的客户端 package com.qf.config;import com.github.tobato.fastdfs.FdfsClientConfig; import org.sprin…

爬虫工作量由小到大的思维转变---<第四十三章 Scrapy Redis mysql数据连通问题(2)>

前言: 接上一章的爬虫工作量由小到大的思维转变---&#xff1c;第四十一章 Scrapy Redis 转mysql数据连通问题&#xff1e;-CSDN博客 这一章主要是讲关于多机连上sql要注意的问题! 正文: 会遇到哪些问题: 数据重复写入&#xff1a;当多个Scrapy-Redis实例同时运行并将数据写…

直播相关——腾讯直播SDK(一)

梳理了下项目中使用的腾讯直播SDK相关&#xff0c;为再接入一套声网RTC SDK做些准备工作。 1.sdk集成 dependencies {implementation com.tencent.liteav:LiteAVSDK_Professional:latest.release }初始化与摄像头推流相关 初始化与摄像头推流相关 2.给 SDK 配置 License 授…

寒假刷代码随想录

数组 二分 在循环中 始终坚持根据查找区间的定义来做边界处理。 第一种写法&#xff0c;我们定义 target 是在一个在左闭右闭的区间里&#xff0c;也就是[left, right] &#xff08;这个很重要非常重要&#xff09;。 区间的定义这就决定了二分法的代码应该如何写&#xff0…