如何理解web安全——同源策略

如何理解web安全——同源策略什么是同源策略 nbsp nbsp 浏览器同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行狡猾 nbsp nbsp nbsp 同源策略是浏览器的一个安全功能 不同源的客户端脚本在没有明确授权的情况下 不能读写对方资源 只有同一个源的脚本赋予 dom 读写 cookie session ajax 等操作的权限 url 由协议 域名 端口和路径组成 如果两个 url 的协议 域名和端口相同 则这两个 url 是同源的 限制来源不用源的

什么是同源策略?

    浏览器同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行狡猾。

    同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。只有同一个源的脚本赋予dom、读写cookie、session、ajax等操作的权限。url由协议、域名、端口和路径组成、如果两个url的协议、域名和端口相同,则这两个url是同源的。限制来源不用源的“document”,对当前的“document”读取或设置某些属性。在不受同源策略限制,带有“src”属性的标签加载是,实际上是由游览器发起一次GET请求,不同于XMLHTTPRequest,它们通过src属性加载的资源。但游览器限制了JavaScript的权限,使其不能读,写其中返回的内容。

以http://abc.com/为例

url  是否跨域  原因
http://abc.com/other  否  协议、端口、主机相同
https://abc.com  是  不同的协议(https)
http://abc.com:81  是  端口不用(81)
http://news.abc.com/  是  不同的主机(news)
http://www.abc.com/  是  域名不用,顶级域名与www子域名不是一个概念
postMessage(HTML5)

语法

otherWindow.postMessage(message, targetOrigin, [transfer]); // otherWindow 发送窗口,比如iframe的contentWindow // message 发送信息 // targetOrigin 定哪些窗口能接收到消息事件 "*" 表示无限制 // transfer [可选] 是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

跨源网络访问

    同源策略控制了不用源之间的交互、交互通常分为三类


  • 允许进行跨域写操作(cross-origin writes)。例如链接(links)、重定向以及表单提交
  • 允许跨域资源嵌入(cross-origin embedding)
  • 不允许跨域读操作(cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问

可能的跨域资源嵌入实例

  •   <script src=””></script>标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
  • <link rel=”stylesheet” href=””/>标签嵌入css。由于css的松散的语法规则,css的跨域需要一个正确的content-type消息头。不用的浏览器有不同的限制。
  • <img>嵌入图片
  • <video>和<audio>嵌入多媒体资源
  • <object>,<embed>和<applet>的插件
  • @font-face引入的字体。一些浏览器允许跨域字体(cross-origin fonts),一些需要同源字体
  • <frame>和<iframe>载入的任何资源。站点可以使用x-Frame-Options消息头来阻止这种形式的跨域交互

同源策略的限制

  • Cookie、LocalStorage和IndexDB无法读取
  • DOM无法获得
  • AJAX请求不能发送 

如何突破同源策略

   受同源策略的限制,只有同源网站的 Cookie才能共享。

   1.cookie

    cookie只有同源的网站才能获取,但是如果两个网页的一级域名相同,只有二级域名不同,可以设置相同的document.domain,两个网页就可以共享cookie了

    域名的等级划分:

  1. 顶级域名:.com
  2. 一级域名:baidu.com
  3. 二级域名:tieba.baidu.com

  例如,a网页是http://abc.com/a.html,b网页是http://abc.com/b.html,我们可以设置document,.domain = ‘abc.com’,a与b可以共享cookie

   2.iframe

    如果两个网页不用源,就无法拿到对方的DOM。典型的例子是iframe窗口和用window.open方法打开的窗口,它们与父窗口无法通信。所以对于完全不同源的网站,目前可以使用以下几种方法突破同源问题:

  1. 片段标识符(fragement identifier)
  2. window.name
  3. 跨文档通信API(window.postMessage)
  • 片段标识符

      片段标识符指的是URL中#后面的内容,比如http://ab.com/search.html#search中的#search,如果只是改变片段标识符,页面不会重新刷新。

      父窗口可以把信息写入子窗口的片段标识符:

var src=originURL + '# '+data document.getElementById('myIframe').src = src

     子窗口通过监听hashchange时间得到通知:

window.onhashchange = function(){ console.log(window.location.hash) }
  • window.name

     浏览器窗口有window.name属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。

  • window.postMessage

     HTML5为了解决跨窗口通讯问题引入了一个新的API:跨文档通信API。window.postMessage方法允许跨窗口通讯,不论这两个窗口是否同源。

    例子:父窗口为http://a.com,子窗口为http://b.com

//父窗口向子窗口发送消息 var popup = window.open('http://b.com','title'); popup.postMessage('hello world','http:/b.com')

    postMessage()方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即“协议+域名+端口”。也可以设为*,表示不限制域名,向所有的窗口发送

    同样,子窗口向父窗口发送消息可以这样写:

window.opener.postMessage('hi,this is a.com','http://a.com')

    父窗口和子窗口都可以通过message事件,监听对方的消息

window.addEventListener('message', function(e) { console.log(e.data) },false)

    message事件和event对象有以下三个属性:

  1. event.source发送消息的窗口
  2. event.origin消息发送的网址
  3. event.data消息内容

例子,子窗口通过event.source属性引用父窗口,然后发送消息。

window.addEventListener('message',receiveMessage); function receiveMessage(event){ event.source.postMessage('nice to see you!','*') }

如何我们将发送的消息改为localStorage,则可以互相读取localStorage.

3.AJAX

同样ajax请求也会受到同源策略的影响,除了使用代理服务器外,还有一个方法可以实现跨域;

  • jsonp
  • WebSocket
  • CORS

1.jsonp

    jsonp由两部分组成,回调函数和数据。其基本思路是:动态插入script标签,向服务器请求json数据,返回的数据将在回调函数中获取。

function addScript(src){ var script = document.createElement('script'); script.setAttribute('type','text/javascript'); script.src = src; document.body.appendChild(script); } //回调函数 function foo(data){ console.log('You public IP address is:'+data.ip) }; window.onload = function(){ addScript('http://example.com/ip?callback=foo') }

   上面的代码通过动态添加script元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字。

2.WebSocket

    WebSocket不用于http,它提供一种双向通讯的功能,即客户端可以向服务器请求数据,同时服务器也可以向客户端发送数据。而http只能是单向的。

    同事WebSocket使用ws:\//(非加密)和wss:\//(加密)作为协议前缀,该协议不实行同源策略,只要服务器支持,就可以通过它进行跨域通信。

   要创建WebSocket,先实例化一个WebSocket对象并传入要连接的URL:

var socket = new WebSocket('ws://www.example.com/server.php')

    实例化WebSocket对象之后,浏览器会马上尝试建立连接。与XHR类似,WebSocket也有一系列表示当前状态的readyState属性,如下:

  1. WebSocket.OPENING:正在建立连接
  2. WebSocket.OPEN:已经建立连接
  3. WebSocket.CLOSEING:正在关闭连接
  4. WebSocket.CLOSE:已经关闭连接

    WebSocke没有readyStatechange事件:不过它有其他的事件,下面会介绍。

要关闭WebSocket连接,可以调用close()方法:

scoket.close()

    WebSocket连接之后,就可以发送和接收数据,要发送数据可以调用send()方法,并传入字符串,例如:

var socket = new WebSocket('ws://www.example.com/server.php') socket.send('hello world')

    因为WebSocket只能发送纯文本数据,所以对于复杂的数据类型我们应先将其序列化转化json字符串

var message = { name:'sillywa' } socket.send(JSON.stringify(message))

    同样服务器必须先解析再读取数据。

    当服务器向客户端发来消息时,WebSocket对象就会触发message事件。这个message事件与其它传递消息的协议类似,也就是把返回的数据保存在event.data的属性中。

socket.message = function(event){ console.log(message) }

    与通过send()发送到服务器的数据一样,event.data中返回的数据也是字符串。

    WebSocket对象还有其它三个事件,在连接生命周期的不同阶段触发。

  • open:在成功建立连接时触发
  • error:在发生错误时触发,连接不能持续
  • close:在连接关闭时触发

    WebSocket对象不支持DOM2级事件侦听器,因此必须使用DOM0级语法分别定义每个事件处理程序。

var socket = new WebSocket('ws://www.example.com/server.php') socket.onopen = function(){ console.log('connection start') } socket.onerror = function(){ console.log('connection error') } socket.onclose = function(event){ console.log(event) }

   这三个事件中只有close的event对象有额外的信息。这个事件的对象有三个额外的属性:wasClean、code、reason.其中wasClean是一个布尔值,表示连接是否已经明确地关闭,close是服务器返回的数据状态码:reason是一个字符串,包含服务器发回的消息。

3.CORS

   CORS是一个W3C标准,全程是”跨域资源共享”(Cross-origin resource sharing)

   它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

   相比于jsonp只能发送get请求,CORS允许发送任何类型的请求。但CORS要求浏览器和服务器同时支持。目前所有浏览器都支持,IE需要IE10以上。

    整个CORS通讯过程中都是浏览器自动完成,不需要用户的参与。CORS通讯和同源的AJAX请求没有区别。浏览器一旦发现AJAX请求跨域,就会自动添加一些头部信息,有时候还会多出一次附加请求。

浏览器将CORS请求分为两类:简单请求和非简单请求:

只要同时满足一下两个条件就是简单请求,否则就是非简单请求:

(1)请求方法是下列方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP头信息不超出一下几个字段:

  • Accept
  • Aceept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded/multipart/form-data/text/plain

    对于简单请求,浏览器会自动在头部信息里增加一个Origin字段,用来表示请求来于哪个源,服务器根据这个值决定是否同意此次请求。如果origin不在请求范围内,服务器返回一个正常的http回应。这个回应的头信息中没有Access-Control-Allow-Origin字段,浏览器发现没有这个字段之后就会抛出一个错误。如果origin在请求范围内,服务器返回的响应会多出几个头信息字段,其中一个是Access-Control-Allow-Origin,它的值要么是origin的值,要么是*,表示允许任何域名的请求。

    对于非简单请求,它会在正式通信之前,增加一次http查询请求,成为“预检”请求(preflight)。通常是一个OPION请求。这个请求先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪http动词和头信息字段。只有得到肯定答案,浏览器才会发出正常的XMLHTTPRequest请求,否则报错。

如果大家想要更详细的了解CORS,可以参考以下文章。

参考文章:

阮一峰《浏览器同源政策及其规避方法》

阮一峰《跨域资源共享 CORS 详解》

参考书籍:

《javascript高级程序设计》




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/230512.html原文链接:https://javaforall.net

(0)
上一篇 2026年2月18日 下午4:01
下一篇 2026年2月18日 下午4:22


相关推荐

  • ABP源码分析十四:Entity的设计

    ABP源码分析十四:Entity的设计

    2021年9月13日
    44
  • ajax菜鸟教程html,菜鸟教程–AJAX[通俗易懂]

    一.简介1.AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。2.AJAX=异步JavaScript和XML。3.通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。二.原理:1.创建XMLHttpRequest对象(1).XMLHttpRequest对象:所有现代浏览器均支…

    2022年4月8日
    85
  • ContentPlaceHolder必须放在具有 runat=server 的窗体标记内

    ContentPlaceHolder必须放在具有 runat=server 的窗体标记内类型 GridView 的控件 ctl00 contentBody gridView4Exp 必须放在具有 runat server 的窗体标记内 nbsp 页面是从母版页继承的 而 gridview 所在的 ContentPlace 确定是放在 form 中的 以前只有控件未放在 form 中才会抛出同类异常 nbsp 1 nbsp protected nbsp void nbsp btExport Click obje

    2025年10月10日
    5
  • Codeblocks中文字体反转[通俗易懂]

    Codeblocks中文字体反转[通俗易懂]codeblocks输入中文字体,出现这样的情况:属于字体的设置问题,将字体栏中的@符号去掉即可。

    2022年7月14日
    22
  • Camstar开发思考:如何在C代码中控制事务

    Camstar开发思考:如何在C代码中控制事务目录开发现状开发问题解决方案 1 自定义 UserFunction 预调用服务预调用服务方案设计与实现代码设计实现结果开发现状 Camstar 开发过程中 业务代码通常写在以下位置 1 Web 服务端 C 代码 基于 NET 的 B S 框架 代码运行环境是 IIS 因为直接使用 VisualStudio 即可编程 并且方便和 UI 做代码交互 因此很多业务代码都在此处编

    2026年3月18日
    1
  • python调用c++动态库_python登陆mt4

    python调用c++动态库_python登陆mt4广告关闭腾讯云11.11云上盛惠,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!运行平台:windowspython版本:python3.6ide:sublimetext其他工具:chrome浏览器0、写在前面的话本文是基于基础版上做的修改,如果没有阅读基础版,请移步python爬虫抓取智联招聘(基础版)在基础版中,构造url时使用了urllib…

    2022年8月15日
    11

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号