草庐IT

Spirit带你了解如何安全引入第三方资源

CodeSpirit 2023-03-28 原文

Spirit带你了解如何安全的引入第三方资源

本文介绍一下如何安全的引入第三方资源

同源策略(SOP)

首先我们来了解一下什么是同源策略,下面的是wiki百科的定义

✨同源策略是指Web浏览器中,允许某个网页脚本访问另一个网页的数据,但前提是这两个网页必须有相同的协议号(protocol),主机号(host name)端口号(port),一旦两个网站满足上述条件,这两个网站被认定为具有相同来源.

而同源策略主要表现在三个方面 DOM,Web数据和网络

  1. DOM:限制了来自不同源的JavaScript脚本对当前的DOM对象读和写的操作
  2. Web数据: 限制了不同源的站点读取当前站点的Cookie,indexDB,LocalStorage等数据
  3. 网络:限制了通过XMLHttpRequest等方式将站点的数据发送给不同源的站点

但是如果都按同源策略来的话,便利性其实是大打折扣的,所以为了便利,Web让出了一些安全性,推出了一系列举措,使得我们的网站能够引入第三方资源为用户提供更加丰富的功能

措施

跨域资源共享 - 维基百科(CORS)

我们先看下wiki百科的定义,方便理解

  • 跨域资源共享:用于让网页的受限资源能够被其他域名的页面访问的一种机制.
    • 通过该机制,页面能够自由地使用不同源(英语:cross-origin)的图片、样式、脚本、iframes以及视频。一些跨域的请求(特别是Ajax)常常会被同源策略(英语:Same-origin policy)所禁止的。
    • 跨源资源共享定义了一种方式,为的是浏览器和服务器之间能互相确认是否足够安全以至于能使用跨源请求(英语:cross-origin requests)。比起纯粹的同源请求,这将更为自由和功能性的(functionality),但比纯粹的跨源请求更为安全。
    • 跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略

通过wiki百科的定义,我们可以得到以下的3点

  1. 页面可以通过该机制,自由的嵌入不同源的图片,样式没脚本,iframes和videos
  2. 可以绕过同源策略,发送跨域请求
  3. 我们可以这么理解,同源策略相当于是把所有第三方的源列上黑名单,而CORS则是把第三方的源选择性的列成白名单,仿佛那些在白名单上的源和自己的源是在一起的

白名单通过服务器的指令传递给客户端,该指令在HTTP响应头中传递给客户端,它包含两个重要的headers

  1. Access-control-allow-origin:用于定义允许哪些源可以访问受限的资源的
  2. Access-control-allow-credentials:确定是否允许使用cookies验证请求

?大家可能注意到了,CORS提供的白名单实际上是为该域提供内容的源所维护的,并不是客户端所提供的.并不能由客户端自己决定,接下来所介绍的CSP则很好的解决了这个问题

内容安全策略(CSP)

老规矩,我们先看下wiki百科的定义

  • 内容安全策略英语:Content Security Policy,简称CSP)是一种计算机安全标准,旨在防御跨站脚本、点击劫持等代码注入攻击,阻止恶意内容在受信网页环境中执行。

  • 我们可以知道,CSP主要是为了抵御攻击手段所发明出来的

  • 但wiki百科对于这一块定义非常的少,接下来介绍的是从MDN上所看到的东西

CSP的主要作用

  1. 减少和报告XSS攻击
  2. CSP可以指定有效域,即客户端浏览器这边认可的可执行的脚本来源

使用CSP

通过Content-Security-Policy设定策略,以下是MDN中介绍的常见的安全策略方案实例

  1. 网站管理者想要所有内容均来自站点的同一个源(不包括其子域名)

    Content-Security-Policy: default-src 'self'
    
  2. 一个网站管理者允许内容来自信任的域名及其子域名 (域名不必须与CSP设置所在的域名相同)

    Content-Security-Policy: default-src 'self' *.trusted.com
    
  3. 一个网站管理者允许网页应用的用户在他们自己的内容中包含来自任何源的图片, 但是限制音频或视频需从信任的资源提供者(获得),所有脚本必须从特定主机服务器获取可信的代码.

    Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
    

    在这里,各种内容默认仅允许从文档所在的源获取, 但存在如下例外:

    • 图片可以从任何地方加载(注意 "*" 通配符)。
    • 多媒体文件仅允许从 media1.com 和 media2.com 加载(不允许从这些站点的子域名)。
    • 可运行脚本仅允许来自于userscripts.example.com。
  4. 一个线上银行网站的管理者想要确保网站的所有内容都要通过SSL方式获取,以避免攻击者窃听用户发出的请求。

    Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
    
  5. 一个在线邮箱的管理者想要允许在邮件里包含HTML,同样图片允许从任何地方加载,但不允许JavaScript或者其他潜在的危险内容(从任意位置加载)。

    Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
    

    注意这个示例并未指定script-src (en-US)。在此CSP示例中,站点通过 default-src 指令的对其进行配置,这也同样意味着脚本文件仅允许从原始服务器获取。


?从上述五个常见例子可以看到,通过自己指定策略,客户端可以自己管理可以从哪加载外部源,相比之前更加安全了,等同于可以自己设置防火墙,抵御外部的恶意攻击,同时也解决了跨域资源共享只能由服务器端来决定白名单的问题,Web的灵活性大大提高了

子资源完整性Subresource Integrity(SRI)

先来看看mdn的定义吧

子资源完整性(SRI)是允许浏览器检查其获得的资源是否被篡改的一项安全特性.它是通过验证获取文件的哈希值是否和你提供的哈希值一样来判断资源是否被篡改

我来给大家讲下SRI的应用场景

我们使用cdn分发脚本和样式表等文件时,并不是完全安全的,如果攻击者获得对CDN的控制权,则可以将任意恶意内容注入到CDN的文件上,因此有可能潜在的攻击所有从该CDN上获取文件的站点.而SRI可以极大限度的来降低这种损害
注意:SRI并不能规避所有的风险.第三方库经常会自己请求额外的信息,有可能会携带用户的账号密码等关键信息.这些经常需要JS功能的支持,比如一个地图库会需要取<svg>数据来渲染,但是包含点击事件.通过点击事件就有可能对你的网站造成损害的

使用方法

  • 使用base64编码过后的文件哈希值写入你所引用的<script><link>标签的integrity就可以启用子资源完整性功能
  • 更为详细的用法 请大家到MDN上浏览,本文不做过多介绍

浏览器处理SRI

  1. 当浏览器在<script>或者<link>标签中遇到 integrity 属性之后,会在执行脚本或者应用样式表之前对比所加载文件的哈希值和期望的哈希值。
  2. 当脚本或者样式表的哈希值和期望的不一致时,浏览器必须拒绝执行脚本或者应用样式脚本,并且返回一个网络

引入第三方资源小结

从上面的讲述,我们可以看到为了引入第三方资源,其实是做了很多努力的

我们在此也可以总结出一些内容

  • 同源策略相当于密不透风的防火墙,任何第三方资源都进不来
  • 跨域资源共享(CORS)和内容安全策略相当于是白名单,告诉同源策略,我们是安全的,让它放行他们进去
  • 子资源完整性(SRI)则是镇守防火墙内的一个尖兵,启动它的时候,能检查出这些第三方资源是否是伪装的恶意进攻
  • 他们相互结合,能极大限度的保护我们的网站不受侵害,同时还能很好的为用户提供更加丰富的功能

有关Spirit带你了解如何安全引入第三方资源的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

随机推荐