同源策略

很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。

同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是 JSONP,JSONP 虽然能解决跨域但是有一个很大的局限性,那就是只支持 GET 请求,不支持其他类型的请求,而今天我们说的 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个 W3C 标准,它是一份浏览器技术的规范提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。

实践

首先,我们新建两个工程:

新建工程一:cors1 project

勾选Web模块 因为我们等下需要通过web接口进行测试 点击Finish完成构建

在cors1 中 我们新建一个HelloController,写上一个测试接口:

@RestController
public class HelloController { @GetMapping("/hello")
public String hello(){
return "hello cors1";
}
}

新建工程二:cors2 project



对应的勾选Web模块进行构建。

在cors2的static目录下,建立Index.html,并编写一个GET请求按钮,发起Ajax请求(前提:static目录下有jquery.js)

请求cors1 工程的 localhost:8080/hello接口

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery3.3.1.js"></script>
</head>
<body>
<div id="app"></div>
<input type="button" value="GET" onclick="getData()">
<input type="button" value="PUT" onclick="putData()">
<script>
function getData() {
$.get("http://localhost:8080/hello",function (msg) {
$("#app").html(msg);
})
}
</script>
</body>
</html>

并设定cors2 工程的项目端口:

server.port = 8081

分别启动cors1 和 cors2

访问 localhost:8081/index.html 点击按钮,发送请求:



访问报错,目前不支持跨域,验证了上面说的 同源策略

解决方案一:

1.在Controller类 或 接口方法上,使用 注解 @CrossOrigin 指定允许哪个域服务器访问

@RestController
public class HelloController { @GetMapping("/hello")
@CrossOrigin(origins = "http://localhost:8081")
public String hello(){
return "hello cors1";
}
}

重启 Cors1 项目,点击发送请求:

访问成功,浏览器控制台也没有报错

注意:

这种方式有一个弊端,就是我们需要在对外开放的每个接口或者类上都要写一遍,大大增加了开发的重复性和繁琐性

解决方案二

Spring Boot 中,可以通过全局配置一次性解决这个问题,全局配置只需要在 SpringMVC 的配置类中重写 **addCorsMappings **方法即可

package org.taoguoguo;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /**
* @author taoguoguo
* @description WebMvcConfig
* @website https://www.cnblogs.com/doondo
* @create 2020-09-01 21:31
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer { /**
* 跨域全局配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
//addMapping 允许哪些接口跨域
//allowedOrigins 允许哪个域服务器访问
//allowedHeaders 允许通过的请求头
//maxAge 服务器在发送一些请求(例如put)会先发一个探测请求,避免每次都需要发送探测请求 可以设置有效期
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(30*1000);
}
}

/** 表示本应用的所有方法都会去处理跨域请求,allowedMethods 表示允许通过的请求数,allowedHeaders 则表示允许的请求头。经过这样的配置之后,就不必在每个方法上单独配置跨域了

现在再去页面访问,也是没有问题的

探测请求

我们在跨域设置中

maxAge 服务器在发送一些请求(例如put)会先发一个探测请求,避免每次都需要发送探测请求 可以设置有效期

先举一个例子:

我们在Cors1中添加一个put请求

@RestController
public class HelloController { @GetMapping("/hello")
@CrossOrigin(origins = "http://localhost:8081")
public String hello(){
return "hello cors1";
} @PutMapping("/doput")
public String doput(){
return "doput";
}
}

在cors2中增加put请求发送按钮

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery3.3.1.js"></script>
</head>
<body>
<div id="app"></div>
<input type="button" value="GET" onclick="getData()">
<input type="button" value="PUT" onclick="putData()">
<script>
function getData() {
$.get("http://localhost:8080/hello",function (msg) {
$("#app").html(msg);
})
} function putData() {
$.ajax({
type:'put',
url: 'http://localhost:8080/doput',
success:function (msg) {
$("#app").html(msg);
}
}) }
</script>
</body>
</html>

启动cors1 cors2 发送put请求:



我们看到请求一次 浏览器会发送两次请求,其中Request Methods 为 options 的即为探测请求

因为我们设置了探测请求的有效期,因此当我们再次发送时,浏览器只会发送一次请求

了解了整个 CORS 的工作过程之后,我们通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法

假如一家银行用以运行转账操作的URL地址如下:**http://icbc.com/aa?bb=cc**,那么,一个恶意攻击者可以在另一个网站上放置如下代码:**<img src="http://icbc.com/aa?bb=cc">**,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。

基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个 options 探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免 csrf 攻击。

Spring Boot 通过CORS实现跨域的更多相关文章

  1. 前端页面调用Spring boot接口发生的跨域问题

    最近要重构一个基于spring boot的后端API服务,需要再本地测试.在本地测试时,运行在本地的前端页面发送一个ajax请求访问后端API,然后浏览器报错blocked CORS policy. ...

  2. Spring Boot+AngularJS中因为跨域导致Session丢失

    http://blog.csdn.net/dalangzhonghangxing/article/details/52446821 如果还在为跨域问题烦恼,请查看博主的 解决angular+sprin ...

  3. Spring MVC使用Cors实现跨域

    在开发APP过程中,APP调用后端接口有跨域的问题,只要在spring-mvc.xml 文件中加入下面的配置即可: <!-- 解决API接口跨域问题配置 Spring MVC 版本必须是 4.2 ...

  4. spring boot 中通过CORS实现跨域

    一.跨域问题出现的原因 出现跨域问题的原因是同源策略. 同源策略 主要是三同:同协议.同域名.同端口, 同源策略目的 保证用户信息安全,防止恶意网站窃取数据.同源策略是必须的,否则cookie可以共享 ...

  5. Spring Boot中通过CORS解决跨域问题

    今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由Netscap ...

  6. spring boot:解决cors跨域问题的两种方法(spring boot 2.3.2)

    一,什么是CORS? 1,CORS(跨域资源共享)(CORS,Cross-origin resource sharing), 它是一个 W3C 标准中浏览器技术的规范, 它允许浏览器向非同一个域的服务 ...

  7. Spring Boot2 系列教程(十四)CORS 解决跨域问题

    今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netsca ...

  8. SpringBoot配置Cors解决跨域请求问题

    一.同源策略简介 同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 什么是源 源[or ...

  9. 前后端分离 开发环境通过CORS实现跨域联调

    通过JSONP实现跨域已是老生常谈,JSONP跨域限制多,最近了解了一下CORS. 参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Acce ...

随机推荐

  1. 初学编程丨从零开始学习编程的基本路线,BAT程序员亲手总结!

    编程并不是说代码怎么写,框架怎么用,业务怎么转换为代码逻辑,这些都不是编程的要素(但却是工作的刚需......).我认为按照下面这个路线来学习编程,会使自己在学习的路途上少去很多问题(比如为啥会有多线 ...

  2. spring中IOC入口与加载步骤

    ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-context.xml&q ...

  3. 【PA2014】Bohater 题解(贪心)

    前言:一道经典贪心题. -------------------------- 题目链接 题目大意:你有$z$滴血,要打$n$只怪.打第$i$只怪扣$d_i$滴血,回$a_i$滴血.问是否存在一种能够通 ...

  4. C#LeetCode刷题之#455-分发饼干(Assign Cookies)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4034 访问.. 假设你是一位很棒的家长,想要给你的孩子们一些小饼 ...

  5. C#LeetCode刷题之#189-旋转数组(Rotate Array)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3700 访问. 给定一个数组,将数组中的元素向右移动 k 个位置, ...

  6. 跳转语句—break,continue,goto

    #define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h&g ...

  7. JS实例-全选练习

    <!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" ...

  8. Golang Gtk+3教程:开始

    GTK+是一个控件工具包.每个通过GTK+创建的用户界面由一些控件组成. 控件是层级式的,window控件是主容器,通过在window中添加按钮.下拉菜单.输入字段等其他控件构成用户界面. 如果是复杂 ...

  9. Mybatis-03-日志

    日志 1 日志工厂 如果一个数据库操作,出现了异常,需要排错,此时需要日志. 曾经:sout debug 现在:日志工厂 logImpl SLF4J/log4j(掌握)/log4j2 设置中可以设定日 ...

  10. Web安全攻防(简)学习笔记

    Web安全攻防-学习笔记 本文属于一种总结性的学习笔记,内容许多都早先发布独立的文章,可以通过分类标签进行查看 信息收集 信息收集是渗透测试全过程的第一步,针对渗透目标进行最大程度的信息收集,遵随&q ...