浏览器跨域问题

一、什么是跨域

  首先当我们遇到一个问题,应该尽量去了解问题的成因,不要只是为了解决问题而解决问题。

1.背景

  跨域问题的背景是浏览器成为互联网访问最大入口,浏览器安全越来越重要,由此抛出了一个实际场景:
  浏览器同时打开了多个网站,比如是a.com和b.com。a.com中加载了a.js文件,如果网站间的资源互通,那b.com也会获取到a.js,相当于a.js可以获取b.com的网站数据,也可以进行数据篡改。如果a.js被不法分子利用,是不是很可怕?

2.跨域定义

  跨域其实就是浏览器的一种隔离策略。
  浏览器提出“Origin”(源)概念,来自不同Origin的对象不能相互干扰,浏览器的同源策略,限制了来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。有点像局部变量和全局变量,网站都规规矩矩用自己的“变量”,没有权利获取其他网站的“变量”。
  注意:浏览器对 <link> <script> <img> <frame>这样获取资源的标签没有跨域限制。

3.跨域触发规则

  所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

地址是否同源原因
http://a.com/dir1/a.html
http://a.com/dir2/b.html
https://a.com/dir1/a.html协议不一样(http和https)
http://a.com:81/dir1/a.html端口不一样
http://b.com/dir1/a.html域名不一样

  跨域一般是在浏览器控制台输出:
在这里插入图片描述

4.为什么跨域问题出现频繁

  浏览器同源策略是1995 年由 Netscape 公司提出,之后被其他浏览器厂商采纳。同源策略最开始只是为了保证网站用户的信息安全,防止网站数据被恶意篡改,但随着Web发展,前后端逐渐分离,前端资源和后端资源开始解耦、独立部署,所以跨域问题就需要解决。
  一般如果前后端打包部署在同一个服务器,浏览器用同一个源请求前端和后端,就不存在跨域;但前后端部署在同一个服务器,部署的端口不一致,也会发生跨域。

5.为什么其他客户端没有跨域这个说法

  首先浏览器作为一种客户端,可能会同时访问多个网站,这些网站“良莠不齐”,你不能保证所有的网站都没有漏洞,不能保证所有网站开发者都是规规矩矩。传统客户端访问都是C/S模式,每个项目有自己独立的客户端,自己的前端访问自己的后端,所以安全性较高。

6.为什么服务器之间没有跨域

  首先服务器和服务器之间访问就不像浏览器访问服务器这么频繁,且服务器不会像浏览器这样会存储很多用户的访问凭证(比如Cookie之类),别人家的服务器怎么调用也不告诉你,你就没那么容易获取信息。

二、怎么解决跨域

  实例:浏览器正常通过服务器A加载了A.html,但是A.html需要加载服务器B中的某些文件,此时会出现跨域。

1.礼貌型解决

在这里插入图片描述
  这时候浏览器首先非常礼貌的问服务器B,我能不能访问你的文件呢?如果服务器B说可以,那么浏览器就可以获得文件。
  获取文件的过程分成两次请求:
  ①预检请求:
  浏览器首先发起OPTIONS请求(预检请求),此时如果访问目标不同意跨域访问,则会报错403(资源不可用):
在这里插入图片描述
  如果允许访问则返回200:
在这里插入图片描述
  ②并且会发起真正的资源请求,并且预检请求和实际请求的响应头都有Access-Control-Allow-Origin。
在这里插入图片描述
解决方案:
  核心思想,在请求的响应头中添加Access-Control-Allow-Origin、Access-Control-Allow-Headers。
  比如以SpringBoot为例,可以注入一个响应头的Component

@Component
class CorsFilter implements Filter {
    //Cross-origin resource sharing
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest reqs = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin",reqs.getHeader("Origin"));
        //response.setHeader("Access-Control-Allow-Origin","*");
        //response.setHeader("Access-Control-Allow-Credentials", "true");
        //response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT, OPTIONS");
        //response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept ,X-Custom-Header, Authorization");
        chain.doFilter(req, res);
    }
    @Override
    public void init(FilterConfig filterConfig) {}
    @Override
    public void destroy() {}
}
2.甩锅型解决

  既然浏览器不让直接访问,那就让服务器A去访问服务器B,反正服务器之间也没有跨域问题,这就是通过代理去解决跨域。
在这里插入图片描述

解决方案:
  通过代理去解决跨域的具体实现有很多个,比如最常见的nginx解决跨域,vue可以配置代理解决跨域。我们以nginx举例
  我们在nginx的server块中配置如下内容:

    server {
        listen       80;
        server_name  localhost;

		location /api {
			proxy_pass http://localhost:8082;
		}
		
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

  我们通过http://localhost/进入html;
  访问接口时直接访问http://localhost/api/xxx,这样浏览器就认为你们是同源的,也就没有跨域问题了。

3.钻空子型解决

  讲同源问题的时候,浏览器对 <link> <script> <img> <frame>这样获取资源的标签没有跨域限制。所以第三种跨域解决方式就是通过这样的标签去获取数据,这种方式就是jsonp方式,目前这种解决跨域的方式用的并不多了。
  注意,这些请求资源的标签本质上都是Get请求,因此只能解决Get请求跨域。
  比如我们在Body里插入这个标签

		<script src="http://localhost:8082/cors"></script> 
		<script>
			function cors(data) {
				console.log(data);
			}
		</script>

  然后在后端写这样一个接口

    @GetMapping("/cors")
    public String corsTest(){
        return "cors('hello world');";
    }

  这时候页面加载时就会触发这个接口,在控制台打印出hello world。
  文章部分摘自——吴翰清《白帽子讲Web安全》

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dantesding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值