跨域详解(含解决方案)

 

 

一、介绍

1、什么是跨域?构成跨域的条件是什么?

当一个请求url的协议域名端口三者之间任意一个与当前页面url不同即为跨域。

 

当前页面url被请求页面url是否跨域 原因
http://www.test.com/http://www.test.com/index.html否 同源(协议、域名、端口号相同)
http://www.test.com/https://www.test.com/index.html跨域 协议不同(http/https)
http://www.test.com/http://www.baidu.com/跨域 主域名不同(test/baidu)
http://www.test.com/http://blog.test.com/跨域 子域名不同(www/blog)
http://www.test.com:8080/http://www.test.com:7001/跨域 端口号不同(8080/7001)

那为什么跨域就不能访问呢?这是因为浏览器的同源策略。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,简单来说就是一种安全机制,它规定了只有同源下才能进行访问。

而所谓同源(即指在同一个域)就是两个页面具有相同的协议,主机、端口号。在非同源情况下的请求会受到以下限制:

【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

【2】无法接触非同源网页的 DOM

【3】无法向非同源地址发送 AJAX 请求

但是有三个标签是允许跨域加载资源:

【1】<img/>

【2】<link/>

【3】<script/>

但我们首先要明确以下几点:

  1. 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境

  2. 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

 

2、没有同源策略的危险场景

举两个例子

1、没有同源策略限制的接口请求

有一个小小的东西叫cookie大家应该知道,一般用来处理登录等场景,目的是让服务端知道谁发出的这次请求。如果你请求了接口进行登录,服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,服务端就能知道这个用户已经登录过了。知道这个之后,我们来看场景: ​ 1.你准备去清空你的购物车,于是打开了买买买网站www.maimaimai.com,然后登录成功,一看,购物车东西这么少,不行,还得买多点。 ​ 2.你在看有什么东西买的过程中,你的好基友发给你一个链接www.nidongde.com,一脸坏笑地跟你说:“你懂的”,你毫不犹豫打开了。 ​ 3.你饶有兴致地浏览着www.nidongde.com,谁知这个网站暗地里做了些不可描述的事情!由于没有同源策略的限制,它向www.maimaimai.com发起了请求!聪明的你一定想到上面的话“服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中”,这样一来,这个不法网站就相当于登录了你的账号,可以为所欲为了!如果这不是一个买买买账号,而是你的银行账号,那……。这就是传说中的CSRF攻击。但及时有同源策略的保护,cookie是明文的可以通过XSS攻击并可以轻松获得你的cookie。其实没有刺不穿的盾,只是攻击的成本和攻击成功后获得的利益成不成正比。攻击者就不会想着攻击了。可以攻击,但没必要。

2、没有同源策略限制的Dom查询

1.有一天你刚睡醒,收到一封邮件,说是你的银行账号有风险,赶紧点进www.yinghang.com改密码。你吓尿了,赶紧点进去,还是熟悉的银行登录界面,你果断输入你的账号密码,登录进去看看钱有没有少了。 ​ 2.睡眼朦胧的你没看清楚,平时访问的银行网站是www.yinhang.com,而现在访问的是www.yinghang.com,这个钓鱼网站直接引用了www.yinhang.com的页面,而你没有任何察觉的输入了你的银行密码。。。。。

总结

 

由此我们知道,同源策略确实能规避一些危险,不是说有了同源策略就安全,只是说同源策略是一种浏览器最基本的安全机制,毕竟能提高一点攻击的成本。

参考网站:https://segmentfault.com/a/1190000015597029?utm_source=tag-newest#articleHeader6

 

二、解决方案

 

核心逻辑在于:给响应头设置Access-Control-Allow-xxxxx字段,表示服务端支持某些域名可以访问。如:

            httpResponse.setHeader("Access-Control-Allow-Headers","准许的请求头字段);
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Origin", '访问的ip');
            httpResponse.setHeader("Access-Control-Allow-Methods", '准许的请求方式');
            httpResponse.setHeader("Access-Control-Max-Age", "验证的时间");

 

 

1、基于Spring4.2以上的解决方案

参考网站:https://segmentfault.com/a/1190000018554528?utm_source=tag-newest

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
            }
        };
    }
​

 

2、filter解决方案

 

yml配置

​
#cors 防跨域攻击
cors:
  #允许跨域域名
  corsAllowedOrigins: http://127.0.0.1:9090,http://localhost:9090
  #允许跨域方法
  corsAllowedMethod: OPTIONS,GET,POST,DELETE,PUT
​
​

 

 

java代码

package guhong.core.api.filter;
​
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
​
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * @author : 李双凯
 * @date : 2019-11-20 22:32
 **/
​
@Component
@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
​
    @Value("${cors.corsAllowedOrigins}")
    private String[] corsAllowedOrigins;
​
    @Value("${cors.corsAllowedMethod}")
    private String corsAllowedMethod;
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        if (httpRequest.getRequestURL().toString().matches(".+.ico$")) {
            chain.doFilter(request, response);
        } else {
            String origin = httpRequest.getHeader("origin");
            boolean isValid = false;
            if (null != corsAllowedOrigins) {
                for (String corsAllowedOrigin : corsAllowedOrigins) {
                    if (StrUtil.isNotBlank(corsAllowedOrigin) && corsAllowedOrigin.equals(origin)) {
                        // 如果当前域名准许跨域访问,则为true,将其添加到Access-Control-Allow-Origin中去
                        isValid = true;
                        break;
                    }
                }
            }
            HttpServletResponse httpResponse = (HttpServletResponse)response;
            httpResponse.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, token");
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Origin", isValid ? origin : null);
            httpResponse.setHeader("Access-Control-Allow-Methods", corsAllowedMethod);
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            chain.doFilter(request, httpResponse);
        }
​
    }
}
​

 

 

三、相关知识

1、CSRF攻击

简单来说,就是通过获取你未登出的网站的cookie、认证,从而以你的身份操作你的信息。

浅谈CSRF攻击

2、XSS攻击

简单来说,就是在表单提交的时,输入的数据变成了JavaScript,而这些嵌入的JavaScript代码将会被执行,从而获取你的信息。

Web安全测试之XSS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值