第三方组件安全剖析

Apache Struts2再曝高危漏洞

前段时间,Apache Struts2又接连曝出了两个高危远程代码执行(Remoce Code Execution,下文简称RCE)漏洞(CVE-2017-5638)。为什么要说“又”呢?那是因为这早就不是Apache Struts2第一次曝出这类漏洞了。

你应该还有印象,早几年前Apache Struts2披露了一系列RCE漏洞,而且他们家在披露RCE漏洞的同时还附带了证明漏洞存在的POC(Proof Of Concept)脚本。在那次事件中,由于POC包含的信息量太大,其本意可能是想方便开发者了解更多漏洞细节,但未曾想却为黑客攻击提供了重要线索,不得不让人觉得是“神助攻”。再加上,这种做法几乎就没给使用Struts2的开发团队留出进行修复的时间,以至于在短时间里,国内外众多使用Struts2的网站,包括一些知名网站均遭到黑客攻击,大量网站纷纷表示躺枪。

前端JS框架、库的安全性同样令人担忧

如果说现如今Struts2在新开发的应用中的使用量小到几乎可以忽略不计,它的安全漏洞所带来的影响有限,那么当下火爆的各种前端JavaScript开发框架、库当中也存在安全漏洞这一事实却让情况变得不容乐观。

早在2014年,当时的一份调查研究发现,在Alexa排名前10万的网站中,有60%的网站使用了至少含有一个已知安全漏洞的JavaScript库。时间来到2017年,美国波斯顿Northeastern University做了一次跟进调查,发现Alexa排名前13万的网站中,有37%的网站使用了至少含有一个已知安全漏洞的JavaScript库。

挑战

使用含有已知安全漏洞的第三方组件的现象为何会如此普遍呢?原因是多方面的,比如,在采用第三方组件的时候没有对其进行安全检查,或者最初该组件并没有安全漏洞,只是随着时间推移,一段时间后被发现存在安全问题并披露了出来等等。要想扭转这一局面,开发团队却也面临着不小的挑战。

挑战一:第三方组件及其版本号众多,需要快速确认哪些存在已知安全漏洞,是否受到漏洞披露的影响

无论是服务器端应用还是运行在浏览器里的前端应用,使用几十个第三方组件、库是稀疏平常的事情,更何况这还只是直接依赖的第三方组件,要是算上间接依赖(即第三方组件所依赖的第三方组件,以此类推)的话,组成一个应用的第三方组件数量将会相当可观。

在知道应用所使用的所有第三方组件之后,还需要知道各个组件的精确版本号,然后才能将组件、版本号在已知漏洞数据库里进行匹配查询,得出最后的结果。

让问题变得更加棘手的是,一个企业里往往有不止一个应用系统,而每个系统都需要定期或者不定期的做这样的排查,所需要的工作量有多么巨大可想而知。

挑战二:和时间赛跑,需要在第一时间内得到通知,以最短时间完成修复和测试,并发布到生产环境

应用在还未发布时如果遇到这类问题,开发团队有充足的时间来做出应对,但对于已经处于运营中的应用而言,时间就是生命线,这是一场和黑客争分夺秒的战争,如果不能赶在黑客进行攻击前完成修复、发布等一系列任务,那就只能祝你好运了。

挑战三:对企业持续交付能力是个考验

在第三方组件的提供商披露安全漏洞的同时,还会给出修复建议,而通常的情况是,开发团队只需要将受到影响的第三方组件升级到新版本即可。看上去这似乎一点不难,但却细思极恐。

第一,版本升级可能会带来兼容性问题,导致应用无法正常启动、使用等。解决兼容性问题就可能得花去不少时间。

第二,迈过了兼容性这一关,开发团队还得对应用进行回归测试,以确保版本升级没有破坏原有的业务功能。那么问题来了,你的团队需要花多少时间进行这一测试呢?几分钟?几小时?还是几天甚至几周?

第三,开发团队排除重重困难,避开了兼容性问题,完成了回归测试,终于走到了发布修复这一步。此时,你的团队是否能对应用进行蓝绿部署、滚动发布以保证生产环境业务不会因为部署而中断?

解决之道

创建和维护第三方组件信息库

开发团队可以将应用中所使用到的所有第三方组件,包括那些间接依赖的第三方组件,及其版本号集中收集起来,形成一个组件信息库。于是,每当有第三方组件安全漏洞信息披露出来的时候,开发团队都可以立即做出判断,了解自己的应用是否受此次漏洞披露的影响。

定期匹配排查

除了在得到第三方组件安全漏洞的信息披露通知后进行识别判断,开发团队还非常有必要主动的对所用到的组件进行定期安全检查。因为在上一步中已经识别出了所有的第三方组件及其版本号,开发团队接下来需要做的,是将这些信息在已知安全漏洞数据库(例如National Vulnerability Database)中进行匹配。

自动化

刚才已经提到,识别第三方组件及其版本号,并且还要对其进行细致的匹配排查,工作量是非常巨大的,如果没有自动化的帮助,仅仅依靠人工的话,几乎是不可能完成的任务。

幸运的是,目前已经有不少工具能帮我们完成这一工作,例如两次入选ThoughtWorks技术雷达的OWASP Dependency Check,它能自动完成第三方组件识别、漏洞数据库维护,以及漏洞匹配、生成检查报告等一些列活动。除了支持Java和.Net应用外,还支持Ruby、NodeJS以及Python应用,以及部分C/C++应用。

同类型的工具还有支持.NET的OWASP SafeNuGet,专门针对Node应用的Node Security Project等等。对于其他语言,也有各自对应的自动化检查工具,在此就不一一列举了。

贯穿整个生命周期

在应用开发过程中,第三方组件可能会不断的被加入到项目里,或者移除出去,其版本也可能会随着时间的推移而不断更改。在这个过程中,组件的的每一次变化都可能会带来新的安全隐患。

开发团队可以利用上一步提到的自动化检查工具,并将其和CI服务器集成起来,可以很容易做到在每次代码提交的时候进行一次安全检查,从而达到持续监控组件安全性的目标。

总结

应用往往使用了大量第三方组件,它们可能含有安全漏洞,给应用的整体安全性埋下隐患。开发团队和黑客一直都在进行时间竞赛,其必须要在第一时间内得到安全漏洞的披露通知,赶在黑客发动攻击之前,完成漏洞修复工作。

好在开发团队可以利用各种自动化工具,快速且全面的发现那些有问题的第三方组件,通过运行回归测试以确保原有业务行为的正确性,并且结合持续交付的能力,在不影响生产环境业务持续运行的情况下,将代码改动发布到生成环境,及时避免第三方组件安全漏洞给应用带来安全风险。


更多精彩洞见,请关注微信公众号:思特沃克

Share

8大前端安全问题(下)

《8大前端安全问题(上)》这篇文章里我们谈到了什么是前端安全问题,并且介绍了其中的4大典型安全问题,本篇文章将介绍剩下的4大前端安全问题,它们分别是:

  • 防火防盗防猪队友:不安全的第三方依赖包
  • 用了HTTPS也可能掉坑里
  • 本地存储数据泄露
  • 缺乏静态资源完整性校验

防火防盗防猪队友:不安全的第三方依赖包

现如今进行应用开发,就好比站在巨人的肩膀上写代码。据统计,一个应用有将近80%的代码其实是来自于第三方组件、依赖的类库等,而应用自身的代码其实只占了20%左右。无论是后端服务器应用还是前端应用开发,绝大多数时候我们都是在借助开发框架和各种类库进行快速开发。

这样做的好处显而易见,但是与此同时安全风险也在不断累积——应用使用了如此多的第三方代码,不论应用自己的代码的安全性有多高,一旦这些来自第三方的代码有安全漏洞,那么对应用整体的安全性依然会造成严峻的挑战。

(图片来自:http://t.cn/RlAQsZ0

举个例子,jQuery就存在多个已知安全漏洞,例如jQuery issue 2432,使得应用存在被XSS攻击的可能。而Node.js也有一些已知的安全漏洞,比如CVE-2017-11499,可能导致前端应用受到DoS攻击。另外,对于前端应用而言,除使用到的前端开发框架之外,通常还会依赖不少Node组件包,它们可能也有安全漏洞。

手动检查这些第三方代码有没有安全问题是个苦差事,主要是因为应用依赖的这些组件数量众多,手工检查太耗时,好在有自动化的工具可以使用,比如NSP(Node Security Platform),Snyk等等。

用了HTTPS也可能掉坑里

为了保护信息在传输过程中不被泄露,保证传输安全,使用TLS或者通俗的讲,使用HTTPS已经是当今的标准配置了。然而事情并没有这么简单,即使是服务器端开启了HTTPS,也还是存在安全隐患,黑客可以利用SSL Stripping这种攻击手段,强制让HTTPS降级回HTTP,从而继续进行中间人攻击。

问题的本质在于浏览器发出去第一次请求就被攻击者拦截了下来并做了修改,根本不给浏览器和服务器进行HTTPS通信的机会。大致过程如下,用户在浏览器里输入URL的时候往往不是从https://开始的,而是直接从域名开始输入,随后浏览器向服务器发起HTTP通信,然而由于攻击者的存在,它把服务器端返回的跳转到HTTPS页面的响应拦截了,并且代替客户端和服务器端进行后续的通信。由于这一切都是暗中进行的,所以使用前端应用的用户对此毫无察觉。

解决这个安全问题的办法是使用HSTS(HTTP Strict Transport Security),它通过下面这个HTTP Header以及一个预加载的清单,来告知浏览器在和网站进行通信的时候强制性的使用HTTPS,而不是通过明文的HTTP进行通信:

Strict-Transport-Security: max-age=<seconds>; includeSubDomains; preload

这里的“强制性”表现为浏览器无论在何种情况下都直接向服务器端发起HTTPS请求,而不再像以往那样从HTTP跳转到HTTPS。另外,当遇到证书或者链接不安全的时候,则首先警告用户,并且不再让用户选择是否继续进行不安全的通信。

(图片来自:http://t.cn/Rfj3Tku

本地存储数据泄露

以前,对于一个Web应用而言,在前端通过Cookie存储少量用户信息就足够支撑应用的正常运行了。然而随着前后端分离,尤其是后端服务无状态化架构风格的兴起,伴随着SPA应用的大量出现,存储在前端也就是用户浏览器中的数据量也在逐渐增多。

前端应用是完全暴露在用户以及攻击者面前的,在前端存储任何敏感、机密的数据,都会面临泄露的风险,就算是在前端通过JS脚本对数据进行加密基本也无济于事。

举个例子来说明,假设你的前端应用想要支持离线模式,使得用户在离线情况下依然可以使用你的应用,这就意味着你需要在本地存储用户相关的一些数据,比如说电子邮箱地址、手机号、家庭住址等PII(Personal Identifiable Information)信息,或许还有历史账单、消费记录等数据。

尽管有浏览器的同源策略限制,但是如果前端应用有XSS漏洞,那么本地存储的所有数据就都可能被攻击者的JS脚本读取到。如果用户在公用电脑上使用了这个前端应用,那么当用户离开后,这些数据是否也被彻底清除了呢?前端对数据加密后再存储看上去是个防御办法,但其实仅仅提高了一点攻击门槛而已,因为加密所用到的密钥同样存储在前端,有耐心的攻击者依然可以攻破加密这道关卡。

所以,在前端存储敏感、机密信息始终都是一件危险的事情,推荐的做法是尽可能不在前端存这些数据。

缺乏静态资源完整性校验

出于性能考虑,前端应用通常会把一些静态资源存放到CDN(Content Delivery Networks)上面,例如Javascript脚本和Stylesheet文件。这么做可以显著提高前端应用的访问速度,但与此同时却也隐含了一个新的安全风险。

如果攻击者劫持了CDN,或者对CDN中的资源进行了污染,那么我们的前端应用拿到的就是有问题的JS脚本或者Stylesheet文件,使得攻击者可以肆意篡改我们的前端页面,对用户实施攻击。这种攻击方式造成的效果和XSS跨站脚本攻击有些相似,不过不同点在于攻击者是从CDN开始实施的攻击,而传统的XSS攻击则是从有用户输入的地方开始下手的。

防御这种攻击的办法是使用浏览器提供的SRI(Subresource Integrity)功能。顾名思义,这里的Subresource指的就是HTML页面中通过<script><link>元素所指定的资源文件。

每个资源文件都可以有一个SRI值,就像下面这样。它由两部分组成,减号(-)左侧是生成SRI值用到的哈希算法名,右侧是经过Base64编码后的该资源文件的Hash值。

<script src=“https://example.js” integrity=“sha384-eivAQsRgJIi2KsTdSnfoEGIRTo25NCAqjNJNZalV63WKX3Y51adIzLT4So1pk5tX”></script>

浏览器在处理这个script元素的时候,就会检查对应的JS脚本文件的完整性,看其是否和script元素中integrity属性指定的SRI值一致,如果不匹配,浏览器则会中止对这个JS脚本的处理。

小结

在上一篇和本篇文章中,我们为大家介绍了在开发前端应用的时候容易遇到的8大安全问题,它们是:

  • 老生常谈的XSS
  • 警惕iframe带来的风险
  • 别被点击劫持了
  • 错误的内容推断
  • 防火防盗防猪队友:不安全的第三方依赖包
  • 用了HTTPS也可能掉坑里
  • 本地存储数据泄露
  • 缺乏静态资源完整性校验

我们希望能通过对这些问题的介绍,引起前端开发小伙伴的注意,尽可能提前绕过这些安全问题的坑。


更多精彩洞见,请关注微信公众号:思特沃克

Share

8大前端安全问题(上)

当我们说“前端安全问题”的时候,我们在说什么

“安全”是个很大的话题,各种安全问题的类型也是种类繁多。如果我们把安全问题按照所发生的区域来进行分类的话,那么所有发生在后端服务器、应用、服务当中的安全问题就是“后端安全问题”,所有发生在浏览器、单页面应用、Web页面当中的安全问题则算是“前端安全问题”。比如说,SQL注入漏洞发生在后端应用中,是后端安全问题,跨站脚本攻击(XSS)则是前端安全问题,因为它发生在用户的浏览器里。

除了从安全问题发生的区域来分类之外,也可以从另一个维度来判断:针对某个安全问题,团队中的哪个角色最适合来修复它?是后端开发还是前端开发?

总的来说,当我们下面在谈论“前端安全问题”的时候,我们说的是发生在浏览器、前端应用当中,或者通常由前端开发工程师来对其进行修复的安全问题。

8大前端安全问题

按照上面的分类办法,我们总结出了8大典型的前端安全问题,它们分别是:

  • 老生常谈的XSS
  • 警惕iframe带来的风险
  • 别被点击劫持了
  • 错误的内容推断
  • 防火防盗防猪队友:不安全的第三方依赖包
  • 用了HTTPS也可能掉坑里
  • 本地存储数据泄露
  • 缺失静态资源完整性校验

由于篇幅所限,本篇文章先给各位介绍前4个前端安全问题。

老生常谈的XSS

XSS是跨站脚本攻击(Cross-Site Scripting)的简称,它是个老油条了,在OWASP Web Application Top 10排行榜中长期霸榜,从未掉出过前三名。XSS这类安全问题发生的本质原因在于,浏览器错误的将攻击者提供的用户输入数据当做JavaScript脚本给执行了。

XSS有几种不同的分类办法,例如按照恶意输入的脚本是否在应用中存储,XSS被划分为“存储型XSS”和“反射型XSS”,如果按照是否和服务器有交互,又可以划分为“Server Side XSS”和“DOM based XSS”。

无论怎么分类,XSS漏洞始终是威胁用户的一个安全隐患。攻击者可以利用XSS漏洞来窃取包括用户身份信息在内的各种敏感信息、修改Web页面以欺骗用户,甚至控制受害者浏览器,或者和其他漏洞结合起来形成蠕虫攻击,等等。总之,关于XSS漏洞的利用,只有想不到没有做不到。

如何防御

防御XSS最佳的做法就是对数据进行严格的输出编码,使得攻击者提供的数据不再被浏览器认为是脚本而被误执行。例如<script>在进行HTML编码后变成了&lt;script&gt;,而这段数据就会被浏览器认为只是一段普通的字符串,而不会被当做脚本执行了。

编码也不是件容易的事情,需要根据输出数据所在的上下文来进行相应的编码。例如刚才的例子,由于数据将被放置于HTML元素中,因此进行的是HTML编码,而如果数据将被放置于URL中,则需要进行URL编码,将其变为%3Cscript%3E。此外,还有JavaScript编码、CSS编码、HTML属性编码、JSON编码等等。好在现如今的前端开发框架基本上都默认提供了前端输出编码,这大大减轻了前端开发小伙伴们的工作负担。

其他的防御措施,例如设置CSP HTTP Header、输入验证、开启浏览器XSS防御等等都是可选项,原因在于这些措施都存在被绕过的可能,并不能完全保证能防御XSS攻击。不过它们和输出编码却可以共同协作实施纵深防御策略。

你可以查阅OWASP XSS Prevention Cheat Sheet_Prevention_Cheat_Sheet),里面有关于XSS及其防御措施的详细说明。

警惕iframe带来的风险

有些时候我们的前端页面需要用到第三方提供的页面组件,通常会以iframe的方式引入。典型的例子是使用iframe在页面上添加第三方提供的广告、天气预报、社交分享插件等等。

iframe在给我们的页面带来更多丰富的内容和能力的同时,也带来了不少的安全隐患。因为iframe中的内容是由第三方来提供的,默认情况下他们不受我们的控制,他们可以在iframe中运行JavaScirpt脚本、Flash插件、弹出对话框等等,这可能会破坏前端用户体验。

如果说iframe只是有可能会给用户体验带来影响,看似风险不大,那么如果iframe中的域名因为过期而被恶意攻击者抢注,或者第三方被黑客攻破,iframe中的内容被替换掉了,从而利用用户浏览器中的安全漏洞下载安装木马、恶意勒索软件等等,这问题可就大了。

如何防御

还好在HTML5中,iframe有了一个叫做sandbox的安全属性,通过它可以对iframe的行为进行各种限制,充分实现“最小权限“原则。使用sandbox的最简单的方式就是只在iframe元素中添加上这个关键词就好,就像下面这样:

<iframe sandbox src="..."> ... </iframe>

sandbox还忠实的实现了“Secure By Default”原则,也就是说,如果你只是添加上这个属性而保持属性值为空,那么浏览器将会对iframe实施史上最严厉的调控限制,基本上来讲就是除了允许显示静态资源以外,其他什么都做不了。比如不准提交表单、不准弹窗、不准执行脚本等等,连Origin都会被强制重新分配一个唯一的值,换句话讲就是iframe中的页面访问它自己的服务器都会被算作跨域请求。

另外,sandbox也提供了丰富的配置参数,我们可以进行较为细粒度的控制。一些典型的参数如下:

  • allow-forms:允许iframe中提交form表单
  • allow-popups:允许iframe中弹出新的窗口或者标签页(例如,window.open(),showModalDialog(),target=”_blank”等等)
  • allow-scripts:允许iframe中执行JavaScript
  • allow-same-origin:允许iframe中的网页开启同源策略

更多详细的资料,可以参考iframe中关于sandbox的介绍

别被点击劫持了

有个词叫做防不胜防,我们在通过iframe使用别人提供的内容时,我们自己的页面也可能正在被不法分子放到他们精心构造的iframe或者frame当中,进行点击劫持攻击。

这是一种欺骗性比较强,同时也需要用户高度参与才能完成的一种攻击。通常的攻击步骤是这样的:

  1. 攻击者精心构造一个诱导用户点击的内容,比如Web页面小游戏
  2. 将我们的页面放入到iframe当中
  3. 利用z-index等CSS样式将这个iframe叠加到小游戏的垂直方向的正上方
  4. 把iframe设置为100%透明度
  5. 受害者访问到这个页面后,肉眼看到的是一个小游戏,如果受到诱导进行了点击的话,实际上点击到的却是iframe中的我们的页面

点击劫持的危害在于,攻击利用了受害者的用户身份,在其不知情的情况下进行一些操作。如果只是迫使用户关注某个微博账号的话,看上去仿佛还可以承受,但是如果是删除某个重要文件记录,或者窃取敏感信息,那么造成的危害可就难以承受了。

如何防御

有多种防御措施都可以防止页面遭到点击劫持攻击,例如Frame Breaking方案。一个推荐的防御方案是,使用X-Frame-Options:DENY这个HTTP Header来明确的告知浏览器,不要把当前HTTP响应中的内容在HTML Frame中显示出来。

关于点击劫持更多的细节,可以查阅OWASP Clickjacking Defense Cheat Sheet

错误的内容推断

想象这样一个攻击场景:某网站允许用户在评论里上传图片,攻击者在上传图片的时候,看似提交的是个图片文件,实则是个含有JavaScript的脚本文件。该文件逃过了文件类型校验(这涉及到了恶意文件上传这个常见安全问题,但是由于和前端相关度不高因此暂不详细介绍),在服务器里存储了下来。接下来,受害者在访问这段评论的时候,浏览器会去请求这个伪装成图片的JavaScript脚本,而此时如果浏览器错误的推断了这个响应的内容类型(MIME types),那么就会把这个图片文件当做JavaScript脚本执行,于是攻击也就成功了。

问题的关键就在于,后端服务器在返回的响应中设置的Content-Type Header仅仅只是给浏览器提供当前响应内容类型的建议,而浏览器有可能会自作主张的根据响应中的实际内容去推断内容的类型。

在上面的例子中,后端通过Content-Type Header建议浏览器按照图片来渲染这次的HTTP响应,但是浏览器发现响应中其实是JavaScript,于是就擅自做主把这段响应当做JS脚本来解释执行,安全问题也就产生了。

如何防御

浏览器根据响应内容来推断其类型,本来这是个很“智能”的功能,是浏览器强大的容错能力的体现,但是却会带来安全风险。要避免出现这样的安全问题,办法就是通过设置X-Content-Type-Options这个HTTP Header明确禁止浏览器去推断响应类型。

同样是上面的攻击场景,后端服务器返回的Content-Type建议浏览器按照图片进行内容渲染,浏览器发现有X-Content-Type-OptionsHTTP Header的存在,并且其参数值是nosniff,因此不会再去推断内容类型,而是强制按照图片进行渲染,那么因为实际上这是一段JS脚本而非真实的图片,因此这段脚本就会被浏览器当作是一个已经损坏或者格式不正确的图片来处理,而不是当作JS脚本来处理,从而最终防止了安全问题的发生。

更多关于X-Content-Type-Options的细节请参考这里

小结

本文对前端安全问题进行了一次梳理,介绍了其中4个典型的前端安全问题,包括它们发生的原因以及防御办法。在下篇文章中,我们将介绍其他的几个前端安全问题,敬请期待。


更多精彩洞见,请关注微信公众号:ThoughtWorks商业洞见

Share

Build Security In PII

引子

很多年前,我沉迷在一款名叫《魔兽世界》的游戏中,不幸的是,我使用了Yahoo的邮箱来注册游戏账号。大约在2013年的某天,因为密码错误,我发现自己已无法登陆,同时,注册游戏账户的邮箱也被人修改了密码。不出所料,经过繁琐的手续找回密码后,发现自己已损失惨重,这直接导致我放弃了这款游戏。

不久就看到“Yahoo丢失了大量账户(一说500万账户被泄露,另一说则高达10亿)”的新闻,对于Yahoo来说,这只是业务江河日下的开始。不幸的是,在我们的生活中,只有危机发生后我们才开始重视,进行补救、修复、挽回、公关等工作,在安全领域预防危机是非常难的,而且也是经常被忽略的。我们常常会被一个简单的逻辑思路所误导:我们的系统看起来没有任何问题,为什么我需要安全保护呢?

作为一个用户,我们每天都在承受隐私被泄露的痛苦:

  • 你的手机是否天天收到垃圾短信?是否被猎头各种骚扰?
  • 你的QQ 、微信是否被广告、微商、奇怪的好友申请围绕?
  • 在使用一个邮件去注册各种服务,该邮箱总会被垃圾广告填满?
  • 只要联系过一次租房中介,每天都会被各种中介的电话亲切的问候?
  • 在某搜索引擎上搜索了贷款,第二天被各种贷款、保险电话骚扰?

诚然,也许对于用户来说,保护自己的隐私或者尽早的适应隐私泄露的生活才是最重要的,但是矛盾之处在于,现代社会是建立在合作分工基础上的,你必须提供自己的身份信息来获取服务。对于服务的提供者(企业),保护个人隐私数据已经是一个社会责任,这会影响到用户的信任、企业的声望,特别是对于金融、审计、房产、航空、医疗等行业。

图 1 – 我们可以为可能到来的无隐私时代做点什么?

PII是什么?

PII是Personal Identifiable Information的全称,也被称为SPI(Sensitive Personal Information),从这个名字中我们可以读出三个关键点:

  • 敏感的
  • 标识的
  • 个人相关

总结就是,PII可以用来识别出个体的信息。直接的PII信息有全名、地址、邮件地址、身份证、信用卡、电话号码等等,也有些信息是潜在的PII信息,比如经过简单的组合就可以识别出个体的信息,全名、省份、街道、年龄、性格、种族等。有这样一个著名的例子:1990年,87%的美国人可以被性别、邮政编码,以及出生年月所识别出。

在一个房地产应用中,使用服务的人分为两类:中介和客户,大量的用户都有强烈的买房欲望,用户群集中、多样性不高,如果泄露了这些优质用户的联系方式,有竞争关系的中介就会获得一个优质用户的联系列表,并且很可能直接骚扰用户,显而易见的后果是评价降低、带来公关危机、罚款以及用户流失。特别是在北美、欧洲、澳洲等发达地区,健全的法规对企业的约束与惩罚是非常严厉的,罚款往往是一个天文数字。

图2 – email_address 永远是存在最广泛的PII信息,可以思考一下,我们是否可以不需要该字段就完成我们的业务呢?

危害

最近出现的一个新闻就是美国选举人信息泄露问题,由于数据库的错误配置,大约有2亿选民身份被泄露,大约有1.8T的数据量,泄露的身份占美国人口63%。泄露的数据包括姓名、出生日期、住址、电话号码以及选民注册细节信息,很难计算这样的数据泄露所造成的危害,但对于Deep Root Analytics这样的大数据分析的公司,声望的损失无法估量。

所以,当PII泄露后,最大的危害是大量的经济损失,包含有政府管理部门的罚款(往往伴随着法律问题)、对于用户的补偿、以及清理breach的各种成本。公关部门将会彻夜忙碌,开发部门天天加班,而管理人员则需要更新管理规范等,损失所产生的骨牌效应是无法预计的。2011年SONY PSN账户泄露造成了1.71亿美元的损失,SONY为每个用户的数据丢失付出了1.67$的代价。

在Ponemon Institute与IBM的报告《2017 Cost of Data Breach Study》中,每条丢失或被盗的记录的平均成本是$141。而且该报告中并不包括知识产权、商业秘密等高价值信息资产泄露的损失。数据永远是无价的。

即使像ThoughtWorks这样一个提供软件服务的公司,我们也需要为客户应用的安全提供更好的保护,并且如果暴露出隐私问题,很可能会带来法律责任。回到选举人泄露问题,这也说明了很多非专业的客户(政府、银行、保险、医疗等)并没有能力保护好自己的数据,对于一个专业的提供软件服务的公司,我们更需要替客户考虑周到,并且规避风险。

图 3 – 一旦使用用户的信用卡数据, PCI标准便是一条红线,不能让信用卡在你的服务中裸奔

Build Security In PII

我们在和一家审计行业的领先企业的长期合作中培养出了更高的隐私保护意识,资深的业务人员与安全技术人员会不断的分享关于隐私保护的知识,正如同其他的安全措施一样,所有的风险、漏洞都是存在在细节中的,只有意识上重视才能在工作中避免出现问题。

当意识一旦建立完毕后,开发人员、项目管理者等角色会主动引入PII信息保护到具体的业务设计、架构设计等,我们的工程师会主动确认、问询、double check PII。

对于一家审计行业的巨头,保护客户的隐私并且遵守法律的规定是极为重要的,他们也非常乐意与我们在合作中将隐私保护做到最好。同时,也很赞赏我们为隐私保护所作出的努力。我们要在和客户的长期合作中建立出对于PII的重视,在策略、法律、长期合作的基础上做到合理的保护PII。在顶层角度,我们输出两点:

建立意识:

保护PII是一个需要长期建立的意识,特别是对一些长期发展的项目中,需要每一位参与项目的人都要清楚的了解到PII是什么、为什么要保护它,要提高它的重要性,这个意识不应该随着人员流动而变的淡薄。目前在一个房地产信息项目中,如果需要新启动小项目,对项目中PII数据的识别、分析、提出保留策略等都会由组员所提出,并且提醒。在开发、测试等等环节中,参与的人员都需要按照之前讨论的策略对PII进行检查等。这些行为都是自发的,是由重视的意识所驱动的。

解决方案:

我所收集到的解决方案基本涵盖了PII数据的生命周期,有些解决方案关注于顶层策略,在战略层级制定PII的保护策略,有些则是需要开发新的系统、功能来维护数据安全,还有些是清理已有系统中的风险。同样,例如数据库加密,入侵检测等等这些基础设施上的保护功能也是可以帮助我们保护PII的。总体来说,在合适的层级、场景我们都需要有类似的解决方案。也可以把自己作为入侵者,来思考如何保护系统中PII的数据。

图4 – BSI 所提出的方法论

制定 Policy

一般来说,整体考虑PII的问题需要从制定顶层policy做起,首先必须明确一点:企业的雇员必须通过PII数据完成工作,如果雇员不需要用该数据进行工作的话,那么他就不应该接触到PII,进一步讲,就是不需要感知到PII的存在。销售人员需要给不同的客户发送促销通知,那么他就必须要知道用户的邮件地址。所以,将PII数据彻底的清除掉是不现实的。

在2017年6月1日施行的《中华人民共和国网络安全法》中,安全法规定了账号实名的法规,所以很多应用都需要更新以适应。不同的国家和地区对于个人隐私信息都是有明确法律法规的,所以也是必须要考虑的。

制定数据传输的规则和政策也是必要的,特别是在很多应用需要依赖于外部服务的情况下,我们需要考虑哪些数据是可以传输给外部服务的。很多应用都使用了log center来收集应用的日志,往往这些log center是三方所提供的服务,工程师们希望有详细的日志来帮助分析问题,所以很有可能将用户名、密码、邮箱地址等PII信息上传上去。这些PII数据就处于不可控的状态,提高了泄露风险。

我们也需要考虑数据聚合、备份等情况。某公司每天都会backup自己的数据库,但是所dump出的数据库备份,并没有做好权限保护,这也会造成泄露PII的风险(MySQL dump造成了大量的数据泄露,我们往往重视数据库的保护却忽略了备份);Dropbox曾经犯过一个错误,由于错误的保存了用户数据的聚合(一个xlsx表格),某员工的账号被入侵,造成了6800万个账号信息泄露。特别是在扁平化的组织中,员工的账号都有很大的权限,这也为身份安全提出了新的挑战,当然这些挑战在安全领域都有很好的解决方案,很多安全领域的solution都可以帮助我们降低PII泄露的风险,即使该solution不是针对PII的。

一旦我们保留PII信息的策略发生变更,我们需要更新User Agreement以通知用户,简单的来说,如果用户不同意我们的策略,我们就不能提供服务。现代应用往往都有很多客户端,怎样将User Agreement推送给用户,并且保证用户阅读并同意是一个关键点。可以参考的是iOS更新,每次更新都会加入User Agreement的改动,并且只有将滚动条移动到最后才能进行升级操作。User Agreement不仅仅是对用户的声明,也可以保护企业规避部分法律风险。

总体来说,制定PII保护的Policy需要有四个步骤:

  1. Find:找到系统中持有的PII数据,以及需要解除或者使用PII数据的角色。
  2. Arrange:分析并整理数据,哪些是必要的,哪些是不必要的,哪些的权限需要更新,而哪些存放在三方服务中等等。
  3. Create:根据整理到的数据建立policy,包含有action。例如:我们不希望在日志中保留用户的信息,应该修改日志记录的内容,同时处理掉已有的数据中的 PII。
  4. Educate:将制定的policy通知给相关的人员,确保所有人都清楚我们的策略。

考虑PII数据的生命周期

之前我们是通过组织结构来规划我们的PII保护策略的,也可以使用另一种角度去达到目的,就是紧跟PII数据的生命周期。我们可以将数据生命周期表示为:存储、处理、传输,PII数据永远都是在这三个状态中进行转换,于是我们提出以下五个步骤来处理PII:

  1. 考虑哪些数据是必要的,收集并持有必要的数据
  2. 根据我们的隐私策略,如何持有、处理这些PII数据(例如加密、权限设置、敏感字符替换等等)
  3. 根据新的风险调整策略,并且演进业务逻辑
  4. 合理的规划保护PII数据的每一个步骤(细化)
  5. 销毁不必要的数据,包括 backup,log甚至audit report

例如我们在开发一个提醒用户房产项目更新的服务时,在项目启动阶段,我们就会考虑到该系统会使用到哪些PII的数据,由于我们要给用户发送邮件和推送,用户的邮件地址与设备id就是PII,而信息中往往也含有用户的全名,我们必须要使用这些数据。所以问题就变成了我们如何持有、消费、销毁这些数据。

最少一个追踪邮件是否送达的数据表中,只需要知道邮件的标记就足够了。对于BA想看到的审计数据,也需要经过处理,例如展示收到邮件最多的地址时,我们可以使用wildcard来替换掉邮件地址中的部分字符。在开发过程中,需要注意的是不要在日志、监控这样的地方泄露PII,部署中也得考虑数据库加密、线上环境的权限配置等等工作。总而言之,在这个服务中,系统是需要知道邮件的目的地址的,而雇员、工程师、其他人则是不需要的,所以PII应该设计为对这些人不可见。

图 5 – dump file永远都是十分危险的,无数数据都是通过mysql dump泄露的

总结

PII数据保护是一个范围很大、优先级很高的事情,最重要的意识是根据大量的教育、分享、实践所build出来的。同时,PII也是信息安全的重要组成部分,我们希望不论是在交付还是在咨询项目中,我们能够考虑到了PII信息,也给出了较好的解决方案,则会提高我们的声望。而PII泄露的事故正如很多信息安全故事一样,如果不出事故则不会被重视,但是一旦出现事故,结果往往则是无法挽回的。保护PII,不仅是保护客户的利益,也是保护我们自己。


更多精彩洞见,请关注微信公众号:思特沃克

Share

在医疗健康领域引入软件开发安全实践

BSI简介

“Build Security in DNA”简称BSI,是在开发过程中内置安全的软件开发实践。 顾名思义,BSI是要将各种安全措施从早期就纳入到软件开发生命周期的每个阶段; 因此,安全是内建的,而不是事后补齐的。通过早期引入这些实践并在整个开发生命周期中进行审查,团队会更早地考虑到安全性的问题并尽早收到反馈。这让团队获得了更多的时间和选项来响应和预防安全问题。

下图描绘了BSI的实现。 我们将安全性作为敏捷开发过程的一部分,在每次迭代中逐步建立和完善我们的安全措施。

通过在软件开发生命周期中添加各种安全措施,安全风险的反馈渠道增加了,安全问题反馈周期缩短了,因此安全问题可以立即得到反馈且进入持续改进的闭环。 通过在业务分析过程中引入威胁建模,可以在某些潜在的安全问题出现之前就主动将其避免掉,从而做到防范于未然。

项目背景

与Clinton Health Access Initiatives(CHAI)合作,我们开发了Electronic Stock Management System(ESMS),这是一个安卓平板APP,其后端对接开源医疗物流平台OpenLMIS,致力于为莫桑比克的患者提供更好的医疗服务。 ESMS有两个主要目标:首先是通过提供用户友好的数字解决方案和自动计算表单来减少医疗工作者的工作量;二是及时、准确的收集药品库存信息,并生成报告,以协助卫生部门来规划、分配、运送药物给卫生站。

如果系统存在安全问题就可能影响到医疗机构运送药物的及时性,进而延缓病人的治疗; 所以确保系统安全是项目团队最重要的工作之一。

引入BSI实践

BSI可以从早期就开始提高软件的安全性,并确保安全问题能得到正确的处理。来看看我们在莫桑比克使用OpenLMIS为CHAI所做的项目的一些例子。该项目在BSI引入时已经处于第二阶段了,其大多数功能已经开发完成。基于这种情况,我们把BSI中的活动重新按优先级排了序,首要做了以下工作。

安全培训工作坊

BSI的主要思想之一是,安全性不仅仅是外部信息安全团队或安全顾问的责任,而是交付团队中的每个人都应该了解的事情。 我们针对Open Web Application Security Project (OWASP)的十大安全问题举办了为期一天的工作坊。ThoughtWorks的安全顾问为项目中的各种角色:开发人员,质量分析师和业务分析师都提供了培训内容。以下是我们向与会者介绍的问题。

在工作坊期间,安全顾问为每个问题解释了定义、概念、理论、行为和预防性解决方案,然后通过实例说明了这些内容,以便与会者理解这些问题产生的后果。工作坊的内容还包括与会者现场上手实操OWASP ZAP和Burp Suite等工具,以此来体验如何排查安全问题。 这次工作坊为开发阶段引入BSI实践打下了良好的基础。

安全性功能测试

安全性功能测试应该内建在质量保证流程中。安全性功能测试涉及身份验证和授权(登录/退出、忘记密码、用户管理等)。根据工作坊介绍、讨论的概念和工具,团队成员和安全顾问一起进行了安全功能测试,涵盖用户访问控制,会话到期等方面。这些测试是手动进行的,并添加了针对这些场景的自动化测试,以确保未来的改动不会再次引入这些问题。

我们发现在一些最常用的功能中存在安全问题,例如在用户注销后会话没有关闭,或非管理员用户能够查看管理员的内容等。

根据优先级排名中的位置,团队成员修复了这些安全问题,完成了一个问题检测和消除的闭环。

渗透测试

渗透测试用于分析系统以识别弱点、技术缺陷或漏洞。从攻击者的角度检查系统,了解什么可能危及系统的安全性。安全顾问与质量分析师合作分析了所有的用例,发现了更多的问题。 例如,登录功能可能会受到暴力攻击,或者可能会通过提交大量数据来攻击,导致拒绝服务。与安全功能测试活动类似,团队修复了这些发现的问题。

代码安全审查

基于安全顾问引入的安全编程原则和指导,团队进行了安全代码审查。 重点放在以下几个模块上:认证/授权,日志记录,密码保护。发现的所有问题都记录在了Mingle的技术卡或缺陷卡里。然后,团队给这些卡排列了优先级,并采取适当的措施来消除或减轻了问题;例如,如果我们发现密码是使用哈希算法存储但没有加盐(salt),那么团队会建一张技术卡,并给予其高优先级,以便在下一次迭代中首要修复该问题。

结论

每一个软件项目都应该从一开始就考虑安全性问题。现在大多数企业级软件都连接到了互联网上,安全性就尤为重要。联网应用的增多是一种趋势,这就增多了可被攻击的潜在目标,安全风险也会随之而来。在开发阶段没有足够的安全保护措施将对项目的长期运行产生负面影响。

反馈周期过长

一般来说,安全问题是在渗透测试阶段显露出来的,有时甚至是应用程序上线后才发现。这样问题的发现、报告和解决要花费很多的时间。

修复成本高

如果是在软件项目的晚期阶段才发现安全问题,软件体系结构已经定型并实现了,这时修复问题就变得额外困难。

BSI可以在开发阶段提高软件的安全性。BSI的目标是在软件发布前,通过业务与技术的手段来确保安全性。

没有绝对的安全,BSI并不能保证系统是完全安全的。然而,对于会向着更大更复杂方向演进的软件系统而言,BSI的安全软件开发过程肯定可以从源头控制安全风险,大大降低黑客攻击的可能性,并显著降低软件投产后安全问题所造成的损失。

作者:刘庆华、崔鹏飞


更多精彩洞见,请关注微信公众号:思特沃克

Share