什么是跨域

指从一个域名网页去请求另一域名页面的资源,比如 baidu.com 请求 google.com 中的资源,但是这种情况是不允许的,因为由浏览器的同源策略,使浏览器对js增加安全限制,即就是阻止不同域下的js进行交互。判断域是否相同是通过判断协议、域名、端口中有任何一个不同,则为不同的域。

什么是同源策略

1、同源策略(Same origin policy)是一种约定,是由Netscape提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

2、举例:

当一个浏览器的两个tab页中分别打开来 百度谷歌的页面

当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,

即检查是否同源,只有和百度同源的脚本才会被执行。

如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。

3、同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

4、同源指:协议、域名、端口都相同。

5、同源策略是基于安全方面的考虑提出的,这个策略本身没有问题,但是在实际开发中,由于其他原因经常有跨域的需求,所以需要跨域的解决方案。

传统的跨域解决凡是 jsonP,jsonP 虽然能解决跨域问题但缺点就是只支持 get 请求。所以有了 cors 来解决 不同请求下跨域资源共享问题。

6、CORS 是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,它是w3c标准,是一份浏览器技术的规范,提供了web服务从不同网域js交互方法,以避开浏览器的同源策略。

springboot 实现 cors

需要创建两个springboot 项目,一个为 provider提供服务的项目,一个为consumer消费服务的项目。

先看没有 cors 的情况

无 cors 情况

提供服务(provider)

1、创建提供服务的项目,添加依赖(provider)

因为需要模拟网页,所以需要 web 依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2、配置端口

server.port=8080

3、提供接口

@RestController
public class HelloController {
    @GetMapping("/h")
    public String hello(){
        return "hello cros";
    }
    @PutMapping ("/h1")
    public String he(){
        return "hello put cros";
    }
}

消费服务(consumer)

1、添加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2、配置端口

server.port=8081

3、页面准备

在resources/static下创建 index.html 文件,用于发送简单的 ajax 请求

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<input type="button" onclick="getData()" value="get"><br>
<input type="button" onclick="putData()" value="put"><br>
<script>
    function getData() {
        $.get("http://localhost:8080/h",function (msg){
            alert(msg);
        })
    }
    function putData() {
        $.ajax({
            url:"http://localhost:8080/h1",
            type:"put",
            success:function (msg) {
                alert(msg);
            }
        })
    }
</script>
</body>
</html>

启动两个项目,通过消费服务的页面定义的按钮,点击后会发现浏览器控制台输出如下:

可以看出由于同源策略的限制,请求无法获取资源。

而当使用了 cors 可以在前端代码不做任何修改下,实现跨越。

有 cors 情况

只需在 服务提供者(provider)中进行配置即可

方式一:@CrossOrigin()

在提供的接口中添加 @CrossOrigin() 注解,该注解添加类或方法上都可。

@RestController
@CrossOrigin(value = "http://localhost:8081",maxAge = 8000)
public class HelloController {
    @GetMapping("/h")
    public String hello(){
        return "hello cros";
    }
    @PutMapping ("/h1")
    public String he(){
        return "hello put cros";
    }
}

通过注解的 value 属性,来设置请求的地址。maxAge:设置相应时间

重启项目,再次访问就正常访问了。

上述实现缺点就是,需要手动添加该组注解,如果多个类,多个方法,也得手动添加多个该注解

方式二:WebMvcConfigurer 全局配置

在 springboot 中通过全局配置来进行配置 cors。

全局配置需要在 springmvc 的配置类中重写 addCorsMappings方法即可

@Configuration
public class MyWebMvcConfiguar implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//允许哪些接口
                .allowedMethods("*")
                .allowedOrigins("http://localhost:8081");
    }
}

/** :表示该应用的所有方法都会处理跨域请求,

allowedMethods:表示允许通过的请求方法

allowedOrigins:表示允许请求的地址

这样配置后就不必在每个类或方法上添单独配置跨域了。

方式三:CorsFilter

通过域过滤器,来进行跨域配置

@Configuration
public class MyWebMvcConfiguar implements WebMvcConfigurer {
    @Bean
    CorsFilter corsFilter(){
        //获取UrlBasedCorsConfigurationSource
        //其使用URL路径模式为请求选择CorsConfiguration。模式匹配可以通过PathMatcher或预先解析的PathPatterns来完成
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //获取CorsConfiguration对象
        CorsConfiguration cfg = new CorsConfiguration();
        //设置cors
        cfg.addAllowedMethod("*");
        cfg.addAllowedOrigin("http://localhost:8081");
        //将设置cors 注册到CorsConfiguration中
        source.registerCorsConfiguration("/**", cfg);//pattern:配置哪些接口可以请求,config:跨域配置
        return new CorsFilter(source);
    }
}

cors存在的问题

虽然解决跨域请求问题使用户体验提高了,但是也有潜在的威胁,常见的是 CSRF,跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

例如:假如一家银行用以运行转账操作的URL地址如下:http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName

那么,一个恶意攻击者可以在另一个网站上放置如下代码:

如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。

这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险

所以,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,

预先请求会首先发送一个 options 探测请求,和浏览器进行协调请求,默认下跨域请求是不需凭证的,但可通过服务端配置要求客户端提供凭证,这样可以防止攻击。

或者添加校验token也可避免

posted on 2023-06-16 11:30  xashould  阅读(364)  评论(0编辑  收藏  举报