再也不学AJAX了!(三)跨域获取资源 ① - 同源策略
我们之前提到过,AJAX技术使开发者能够专注于互联网中数据的传输,而不再拘泥于数据传输的载体。通过AJAX技术,我们获取数据的方式变得更加灵活,可控和优雅。
但是AJAX技术并不是一把万能钥匙,互联网中的数据隐私和数据安全(例如你的银行账号和密码)也非常重要,为了保护某些用户数据的隐私与安全,浏览器使用“同源策略”限制了AJAX技术获取数据的范围和能力。但在一些合理的场景中,我们又不得不想办法绕过同源策略,实现跨域请求资源。因此“跨域技术”一直成为开发者们经久不衰的讨论话题。
在“跨域获取资源”这一主题中,我们将围绕“同源策略”和“跨域”两大主题展开,不但讲述它们是什么,更说明了为什么要这么做。相信你在读完该主题下的两篇文章后,一定会对这两大主题有一个清晰,系统的认识。
需要提前声明的是,本主题下的文章并不会像众多相同主题的文章一样罗列出所有的跨域技术,而只会捡最主流的四种进行讲解。因为我并不打算写“教你如何跨域”这样类型的文章。
让我们开始吧。
同源策略
整个互联网世界的数据要么存储在服务端(即服务器,如数据库,硬盘等)中,要么存储在客户端(即浏览器,如cookie,LocalStorage,sessionStorage)中。互联网数据的传输实际上就是客户端与服务端之间的交互。
而所谓的数据隐私与安全保护,说白了就是数据拥有者对数据索取者发出警告:“不是你的你别动”。
搞清了这个原则,我们就很容易明白,如果你在客户端,并且想要获取服务端数据,你首先需要通过服务器端的验证,证明你有权限获取数据(例如“登录”),而如果你在服务端,想要获取客户端的某些数据,你同样需要客户端通过某些方式验证你有资格获取相应的数据资源。
那么上面提到的“某些方式”是什么呢?其中最重要的就是我们今天的主题之一 -- 浏览器的“同源策略”。
浏览器的“同源策略”
浏览器所遵守的“同源策略”是指:限制不同源之间执行特定操作。这涉及到两个问题:什么是“源”?,以及“特定操作”是指什么?
让我们停下来解释一下这个概念:
- 一个源由协议,域名和端口三部分组成,这三者任一一个不同都会被浏览器识别为不同的源;
- 上文所提到的特定操作是指:
- 读取 Cookie,LocalStorage 和 IndexDB;
- 获取 DOM 元素;
- 发送 AJAX 请求;
在搞清了同源策略的概念之后,让我们看看浏览器是出于怎样的考虑,一直坚守着同源策略:
为什么要有“源”的概念?
因为不同的源,大多数情况下就意味着它们在互联网中归属于不同的站点(或是被用作不同的用途)。也就是说它们是不同的项目,有不同的文件根目录,那么它们的数据也不应该共享也就理所应当了,否则数据的隐私和安全也无从谈起。不过请注意,我上面所说的话是基于“不同源就彼此不相干”的假设,这其实存在一些问题,我们之后会提到。
为什么不能执行“特定操作”?
这个需要我们假设,如果我们想做一些“坏事”,并且浏览器允许我们执行这些“特定操作”,我们作为“坏人”能做什么:
首先,由于很多网站使用浏览器存储用户的用户名和密码,那么我们便可以在A域中(我们在服务器上托管的网站)读取任意来访用户的所有Cookie信息(没有同源策略的保护,该用户所有网站的Cookie记录都是透明的),我们就可以利用这些Cookie信息伪装成来访用户做任何事,而在现实世界,出于同源政策的保护,我们只能访问用户该域下的Cookie信息,也就是说,我们只能访问我们自己设置的Cookie信息。
其次,如果我们能够获取不同域下的DOM元素,我们就可以通过<iframe>标签在我们的A域网站上引入B域网站,然后诱使用户在B域网站操作,由于我们能够跨域获取DOM元素,因此我们可以操作B域网站的DOM结构,用户输入的一切信息,以及用户操作的DOM元素就都在我们的掌控之中了。这正是同源策略想要规避的安全隐患。
最后,为什么要禁止不同源的站点发送AJAX请求呢?这个说起来有些复杂,我们首先要对Cookie的运作原理有一个大致的了解:
当我们设置Cookie时,除了存放键值对形式的数据信息外,浏览器还会为Cookie的一些属性填充默认值(我们也可以手动修改这些属性的值)。在这些属性中,我们需要关注domain和path两个属性,它们一个代表域名,一个代表路径,两者加起来构成了一个确定这条Cookie何时被调用和访问的URL。与此同时,浏览器自己维护的Cookie文件中也会添加这一条新创建的Cookie数据。
当我们在浏览器中发送HTTP请求时,浏览器首先会检查请求地址并在自己所维护的Cookie文件中寻找匹配的Cookie信息,将其添加到请求头中的Cookie属性内,然后向服务器发送请求。请注意,这个自动添加相应Cookie信息的过程是浏览器自己偷偷帮我们做到的,也就是说,我们自己无法控制这个过程。
下面重点来了,当我们的HTTP请求到达服务器时,服务器返回的响应中,响应头会原封不动的返回我们发送给他的Cookie信息。嗅到危险的味道了吗?我们虽然不能在发送请求前获得Cookie信息,但是在发送请求后,我们还是能够获得用户的Cookie!
让我再进一步解释一下这和AJAX有什么关系,假设我们在自己的服务器上托管了站点A,并在其中隐藏了一段脚本,每个登录站点A的人都会自动发送AJAX请求至站点B(提示:站点B是一个银行),那么在没有浏览器同源策略的情况下,如果站点A中的访问者恰好有Cookie中保留站点B信息的用户,通过AJAX请求返回的响应头,我们一样可以拿到这位用户的站点B Cookie,从而伪装成用户在站点B登录,做一些违法乱纪的事情(CSRF攻击即是利用了这个原理,只不过出于同源策略限制,并不能通过发起AJAX的方式)。
虽然有些费劲,但是现在你应该明白为什么同源策略要阻止跨域发送AJAX了吧?(我终于将这个概念说清楚了,真是费了不少力气
再也不学AJAX了!(三)跨域获取资源 ① - 同源策略的更多相关文章
- 再也不学AJAX了!(三)跨域获取资源 ③ - WebSocket & postMessage
让我们先简单回顾一下之前谈到的内容,AJAX是一种无页面刷新的获取服务器资源的混合技术.而基于浏览器的"同源策略",不同"域"之间不可以发送AJAX请求.但是在 ...
- 再也不学AJAX了!(三)跨域获取资源 ② - JSONP & CORS
浏览器的"同源策略"固然保障了互联网世界的数据隐私与数据安全,但是如果当我们需要使用AJAX跨域请求资源时,"同源策略"又会成为开发者的阻碍.在本文中,我们会简 ...
- django中的缓存 跨域问题(同源策略)
django缓存机制 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作 ...
- Jsonp的js实现,跨域请求,同源策略机制
Jsonp的js实现,跨域请求,同源策略机制1.跨域请求:请求URL的协议,域名,端口三者之间任意一个与当前页面地址不同即为跨域 存在跨域的情况: 网络协议不同,端口不通,域名不同,子域名不同,域名和 ...
- [ 转 ]jquery的ajax和getJson跨域获取json数据
目前浏览器端跨域访问常用的两种方法有两种: 1.通过jQuery的ajax进行跨域,这其实是采用的jsonp的方式来实现的. jsonp是英文json with padding的缩写.它允许在服务器端 ...
- jquery的ajax和getJson跨域获取json数据
目前浏览器端跨域访问常用的两种方法有两种: 1.通过jQuery的ajax进行跨域,这其实是采用的jsonp的方式来实现的. jsonp是英文json with padding的缩写.它允许在服务器端 ...
- 使用JSONP,jQuery的ajax跨域获取json数据
网上找了很多资料,写的不错,推荐下: 1.深入浅出JSONP--解决ajax跨域问题 (http://www.cnblogs.com/chopper/archive/2012/03/24/240394 ...
- 再也不学AJAX了!(一)AJAX概述
"再也不学AJAX了"是一个与AJAX主题相关的文章系列,包含以下三个部分的内容: AJAX概述:主要回答"AJAX是什么"这个问题: 使用AJAX:介绍如何通 ...
- jsonp跨域获取数据实现百度搜索
本菜鸡最近在写某个页面请求数据时,报了如下的错误. Failed to load https://...:No 'Access-Control-Allow-Origin' header is pres ...
随机推荐
- js 正则 exec() 和 match() 数据抽取
js 的正则表达式平常用的不多,但以前抽取数据的时候用到过,主要是有这样的需求: var text='<td class="data">2014-4-4</td& ...
- maven发布项目的snapshot到nexus
1.配置发布地址信息 <repositories> <repository> <id>nexus</id> <name>Local Repo ...
- Python--进阶处理2
# ===================第二章:字符串和文本====================== # -----------------使用多个界定符分割字符串--------------- ...
- mysql json
SELECT name, profile->"$.twitter" AS `twitter` FROM `user` WHERE profile->"$.tw ...
- Flask使用日志记录到文件示例
https://www.polarxiong.com/archives/Flask%E4%BD%BF%E7%94%A8%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95%E5%8 ...
- 剑指Offer——求1+2+3+...+n
题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 分析: 递归实现. 代码: class So ...
- 如何使文本溢出边界不换行强制在一行内显示?#test{width:150px;white-space:nowrap;}
#test{width:150px;white-space:nowrap;}
- git学习------>如何修改git已提交的记录中的Author和Email?
一.背景 最近搭建好GitLab后,准备陆陆续续的将之前在SVN仓库中保存的代码迁移到GitLab上,昨天顺利将三个Android组件的代码迁移到GitLab后,其他同事发现迁移是成功了,但是pull ...
- Linux下多线程的重要知识点
线程属性: typedef struct { int detachstate; 线程的分离状态 int ...
- SpringBoot-URL路由:@Controller和@RequestMapping
SpringBoot定义URL处理方法:@Controller和@RequestMapping @Controller标注的类表示的是一个处理HTTP请求的控制器(即MVC中的C),该类中所有被@Re ...