在安全圈子里,素有“白帽”、“黑帽”一说。
黑帽子是指那些造成破坏的黑客,而白帽子则是研究安全,但不造成破坏的黑客。 白帽子
均以建设更安全的互联网为己任。
不想拿到“root”的黑客,不是好黑客。漏洞利用代码能够帮助黑客们达成这一目标。黑
客们使用的漏洞利用代码,被称为“exploit”。在黑客的世界里,有的黑客,精通计算机技术,
能自己挖掘漏洞,并编写 exploit;而有的黑客,则只对攻击本身感兴趣,对计算机原理和各种
编程技术的了解比较粗浅,因此只懂得编译别人的代码,自己并没有动手能力,这种黑客被称
为“Script Kids”,即“脚本小子”。在现实世界里,真正造成破坏的,往往并非那些挖掘并研
究漏洞的“黑客”们,而是这些脚本小子。而在今天已经形成产业的计算机犯罪、网络犯罪中,
造成主要破坏的,也是这些“脚本小子”。
崇尚分享、自由、免费的互联网精神,并热衷于分享自己的最新研究成果。-->黑客精神
浏览器攻击(分支之一):
黑客构造一个恶意网页,诱使用户使用浏览器访问该网页,利用浏览器中存在的某些漏洞,比如一个缓冲区溢出漏洞,执行 shellcode,通常是下载一个木马并在用户机器里执行。
SQL注入的出现是Web安全史上的一个里程碑。
XSS(跨站脚本攻击)的出现则是 Web 安全史上的另一个里程碑。
白帽子一般为企业或安全公司服务,工作的出发点
就是要解决所有的安全问题,因此所看所想必然要求更加的全面、宏观;黑帽子的主要目的是要入侵系统,找到对他们有价值的数据,因此黑帽子只需要以点突破,找到对他们最有用的一
点,以此渗透,因此思考问题的出发点必然是有选择性的、微观的。
WEB安全:
通过一个安全检查(过滤、净化)的过程,可以梳理未知的人或物,使其变得可信任。被划分出来的具有不同信任级别的区域,我们称为信任域,划分两个不同信任域之间的边界,我们称为信任边界。
数据从高等级的信任域流向低等级的信任域,是不需要经过安全检查的;数据从低等级的信任域流向高等级的信任域,则需要经过信任边界的安全检查。
例子:
我们在机场通过安检后,想要从候机厅出来,是不需要做检查的;但是想要再回到候机厅,则需要再做一次安全检查,就是这个道理。
安全问题的本质是信任的问题。
例子:
假设我们有份很重要的文件要好好保管起来,能想到的一个方案是把文件“锁”
到抽屉里。这里就包含了几个基本的假设,首先,制作这把锁的工匠是可以信任的,他没有私自藏一把钥匙;其次,制作抽屉的工匠没有私自给抽屉装一个后门;最后,钥匙还必须要保管在一个不会出问题的地方,或者交给值得信任的人保管。
安全三要素(CIA):
1.机密性要求保护数据内容不能泄露,加密是实现机密性要求的常见手段。
2.完整性则要求保护数据内容是完整、没有被篡改的。常见的保证一致性的技术手段是数字签名。
3.可用性要求保护资源是“随需而得”。
例子:
假设一个停车场里有 100 个车位,在正常情况下,可以停 100 辆车。但是在某一天,有个坏人搬了 100 块大石头,把每个车位都占用了,停车场无法再提供正常服务。在安全领域中这种攻击叫做拒绝服务攻击,简称 DoS(Denial of Service)。拒绝服务攻击破坏的是安全的可用性。
安全评估过程分为:
资产等级划分、威胁分析、风险分析、确认解决方案。
互联网安全的核心问题,是数据安全的问题。
对互联网公司拥有的资产进行等级划分,
就是对数据做等级划分。
了解公司最重要的资产是什么,他们最看重的数据是什么。
接下来就是要划分信任域和信任边界了。
从网络逻辑上来划分。
例子:
比如最重要的数据放在数据库里,那么把数据库的服务器圈起来;Web 应用可以从数据库中读/写数据,并对外提供服务,那再把 Web 服务器圈起来;最外面是不可信任的 Internet。
信任域划好之后,我们如何才能确定危险来自哪里呢?
在安全领域里,我们把可能造成危
害的来源称为威胁(Threat),而把可能会出现的损失称为风险(Risk)。
威胁建模:
在进行威胁分析时,要尽可能地不遗漏威胁,头脑风暴的过程可以确定攻击面(Attack
Surface)。
风险分析:
风险由以下因素组成:
Risk = Probability * Damage Potential
设计安全方案:
一个优秀的安全方案应该具备以下特点:
m 能够有效解决问题;
m 用户体验好;
m 高性能;
m 低耦合;
m 易于扩展与升级。
1.Secure By Default 原则:
也可以归纳为白名单、黑名单的思想。
例子A:
比如,在制定防火墙的网络访问控制策略时,如果网站只提供 Web 服务,那么正确的做法
是只允许网站服务器的 80 和 443 端口对外提供服务,屏蔽除此之外的其他端口。这是一种“白
名单”的做法;如果使用“黑名单”,则可能会出现问题。假设黑名单的策略是:不允许 SSH
端口对 Internet 开放,那么就要审计 SSH 的默认端口:22 端口是否开放了 Internet。但在实际
工作过程中,经常会发现有的工程师为了偷懒或图方便,私自改变了 SSH 的监听端口,比如
把 SSH 的端口从 22 改到了 2222,从而绕过了安全策略。
例子B:
又比如,在网站的生产环境服务器上,应该限制随意安装软件,而需要制定统一的软件版
本规范。这个规范的制定,也可以选择白名单的思想来实现。按照白名单的思想,应该根据业
务需求,列出一个允许使用的软件以及软件版本的清单,在此清单外的软件则禁止使用。如果
允许工程师在服务器上随意安装软件的话,则可能会因为安全部门不知道、不熟悉这些软件而
导致一些漏洞,从而扩大攻击面。
在 Web 安全中,对白名单思想的运用也比比皆是。
例子:
比如应用处理用户提交的富文本时,考
虑到 XSS 的问题,需要做安全检查。常见的 XSS Filter 一般是先对用户输入的 html 原文作
HTML Parse,解析成标签对象后,再针对标签匹配 XSS 的规则。这个规则列表就是一个黑白
名单。如果选择黑名单的思想,则这套规则里可能是禁用诸如<script>、<iframe>等标签。但是
黑名单可能会有遗漏,比如未来浏览器如果支持新的 HTML 标签,那么此标签可能就不在黑
名单之中了。如果选择白名单的思想,就能避免这种问题——在规则中,只允许用户输入诸如
<a>、<img>等需要用到的标签。
然而,并不是用了白名单就一定安全了。
选择白名单的思想,基于白名单来设计安全方案,其实就是信任白名单是好的,是安全的。但是一旦这个信任基础不存在了,那么安全就荡然无存。
在 Flash 跨域访问请求里,是通过检查目标资源服务器端的 crossdomain.xml 文件来验证是
否允许客户端的 Flash 跨域发起请求的,它使用的是白名单的思想。
比如下面这个策略文件:
指定了只允许特定域的 Flash 对本域发起请求。可是如果这个信任列表中的域名变得不可
信了,那么问题就会随之而来。比如:
通配符“*”,代表来自任意域的 Flash 都能访问本域的数据,因此就造成了安全隐患。所
以在选择使用白名单时,需要注意避免出现类似通配符“*”的问题。
Secure By Default 的另一层含义就是“最小权限原则”。
要求系统只授予主体必要的权限,而不要过度授权,这样能有效地减
少系统、网络、应用、数据库出错的机会。
比如在 Linux 系统中,一种良好的操作习惯是使用普通账户登录,在执行需要 root 权限的
操作时,再通过 sudo 命令完成。这样能最大化地降低一些误操作导致的风险。
在使用最小权限原则时,需要认真梳理业务所需要的权限,在很多时候,开发者并不会意
识到业务授予用户的权限过高。在通过访谈了解业务时,可以多设置一些反问句,比如:您确
定您的程序一定需要访问 Internet 吗?通过此类问题,来确定业务所需的最小权限。
2.纵深防御原则:
首先,要在各个不同层面、不同方面实施安全方案,避免出现疏
漏,不同安全方案之间需要相互配合,构成一个整体;其次,要在正确的地方做正确的事情,
即:在解决根本问题的地方实施针对性的安全方案。
例子:
某矿泉水品牌曾经在广告中展示了一滴水的生产过程:经过十多层的安全过滤,去除有害物质,
最终得到一滴饮用水。这种多层过滤的体系,就是一种纵深防御,是有立体层次感的安全方案。
在常见的入侵案例中,大多数是利用 Web 应用的漏洞,攻击者先获得一个低权限的 webshell,
然后通过低权限的 webshell 上传更多的文件,并尝试执行更高权限的系统命令,尝试在服务器上
提升权限为 root;接下来攻击者再进一步尝试渗透内网,比如数据库服务器所在的网段。
在这类入侵案例中,如果在攻击过程中的任何一个环节设置有效的防御措施,都有可能导
致入侵过程功亏一篑。
就入侵的防御来说,我们需要考虑的可能有 Web 应用
安全、OS 系统安全、数据库安全、网络环境安全等。在这些不同层面设计的安全方案,将共
同组成整个防御体系,这也就是纵深防御的思想(第一层含义)。
在 XSS 防御技术的发展过程中,曾经出现过几种不同的解决思路,直到最近几年 XSS 的
防御思路才逐渐成熟和统一。
在一开始的方案中,主要是过滤一些特殊字符,比如:
<<笑傲江湖>> 会变成 笑傲江湖
尖括号被过滤掉了。
但是这种粗暴的做法常常会改变用户原本想表达的意思,比如:
1<2 可能会变成 1 2
造成这种“乌龙”的结果就是因为没有“在正确的地方做正确的事情”。
对于 XSS 防御,
对系统取得的用户输入进行过滤其实是不太合适的,因为 XSS 真正产生危害的场景是在用户
的浏览器上,或者说服务器端输出的 HTML 页面,被注入了恶意代码。只有在拼装 HTML 时
输出,系统才能获得 HTML 上下文的语义,才能判断出是否存在误杀等情况。(第二层含义)
3.数据与代码分离原则:
广泛适用于各种由于“注入”而引发安全问题的场景。
例子A:
实际上,缓冲区溢出,也可以认为是程序违背了这一原则的后果——程序在栈或者堆中,
将用户数据当做代码执行,混淆了代码与数据的边界,从而导致安全问题的发生。
例子B:
4.不可预测性原则:
前面介绍的几条原则:Secure By Default,是时刻要牢记的总则;纵深防御,是要更全面、
更正确地看待问题;数据与代码分离,是从漏洞成因上看问题;接下来要讲的“ 不可预测性”
原则,则是从克服攻击方法的角度看问题。
微软使用的 ASLR 技术,在较新版本的 Linux 内核中也支持。在 ASLR 的控制下,一个程
序每次启动时,其进程的栈基址都不相同,具有一定的随机性,对于攻击者来说,这就是“不
可预测性”。
不可预测性(Unpredictable),能有效地对抗基于篡改、伪造的攻击。
例子:
不可预测性原则,可以巧妙地用在一些敏感数据上。比如在 CSRF 的防御技术中,通常会
使用一个 token 来进行有效防御。这个 token 能成功防御 CSRF,就是因为攻击者在实施 CSRF
攻击的过程中,是无法提前预知这个 token 值的,因此要求 token 足够复杂时,不能被攻击者
猜测到。
点击劫持(ClickJacking):
点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的 iframe,覆盖在一
个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的 iframe
页面。通过调整 iframe 页面的位置,可以诱使用户恰好点击在 iframe 页面的一些功能性按钮上。
例子:
有个test.html页面
Flash点击劫持:
攻击者通过 Flash 构造出了点击劫持,
在完成一系列复杂的动作(每次点击后,按钮的位置都会发生变化)后,最终控制了用户电脑的摄像头。
图片覆盖攻击:
例子:
由于<img>标签在很多系统中是对用户开放的,因此在现实中有非常多的站点存在被 XSIO
攻击的可能。在防御 XSIO 时,需要检查用户提交的 HTML 代码中,<img>标签的 style 属性是
否可能导致浮出。
拖拽劫持与数据窃取:
目前很多浏览器都开始支持 Drag & Drop 的 API。对于用户来说,拖拽使他们的操作更加
简单。浏览器中的拖拽对象可以是一个链接,也可以是一段文字,还可以从一个窗口拖拽到另
外一个窗口,因此拖拽是不受同源策略限制的。
“拖拽劫持”的思路是诱使用户从隐藏的不可见 iframe 中“拖拽”出攻击者希望得到的数
据,然后放到攻击者能控制的另外一个页面中,从而窃取数据。
例子:
ClickJacking 3.0:触屏劫持
一次触屏操作,可能会对应以下几个事件:
touchstart,手指触摸屏幕时发生;
touchend,手指离开屏幕时发生;
touchmove,手指滑动时发生;
touchcancel,系统可取消 touch 事件。
左边的图片,最上方显示了浏览器地址栏,同时攻击者在页面中画出了一个假的地址栏;
中间的图片,真实的浏览器地址栏已经自动隐藏了,此时页面中只剩下假的地址栏;
右边的图片,是浏览器地址栏被正常隐藏的情况。
这种针对视觉效果的攻击可以被利用进行钓鱼和欺诈。
防御 ClickJacking:
针对传统的 ClickJacking,一般是通过禁止跨域的 iframe 来防范。
因为 frame busting 存在被绕过的可能,所以我们需要寻找其他更好的解决方案。一个比较
好的方案是使用一个 HTTP 头——X-Frame-Options。
在支持X-Frame-Options的浏览器上
MVC 框架安全:
SQL注入是Model 层需要解决的问题。
模板引擎与 XSS 防御:
XSS 攻击是在用户的浏览器上执行的,
其形成过程则是在服务器端页面渲染时,注入了恶意的 HTML 代码导致的。从 MVC 架构来说,
是发生在 View 层,因此使用“输出编码”的防御方法更加合理,这意味着需要针对不同上下
文的 XSS 攻击场景,使用不同的编码方式。
Web 框架与 CSRF 防御:
在 Web
框架中可以使用 security token 解决 CSRF 攻击的问题。
CSRF 攻击的目标,一般都会产生“写数据”操作的 URL,比如“增”、“删”、“改”;而
“读数据”操作并不是 CSRF 攻击的目标,因为在 CSRF 的攻击过程中攻击者无法获取到服务
器端返回的数据,攻击者只是借用户之手触发服务器动作,所以读数据对于 CSRF 来说并无直
接的意义(但是如果同时存在 XSS 漏洞或者其他的跨域漏洞,则可能会引起别的问题,在这
里,仅仅就 CSRF 对抗本身进行讨论)。
因此,在 Web 应用开发中,有必要对“读操作”和“写操作”予以区分,比如要求所有的
“写操作”都使用 HTTP POST。
在 Ajax 请求中,一般是插入一个包含了 token 的 HTTP 头,使用 HTTP 头是为了防止 token
泄密,因为一般的 javascript 无法获取到 HTTP 头的信息,但是在存在一些跨域漏洞时可能会
出现例外。
HTTP Headers 管理:
对于框架来说,管理好跳转目的地址是很有必要的。一般来说,可以在两个地方做
这件事情:
(1)如果 Web 框架提供统一的跳转函数,则可以在跳转函数内部实现一个白名单,指定跳
转地址只能在白名单中;
(2)另一种解决方式是控制 HTTP 的 Location 字段,限制 Location 的值只能是哪些地址,
也能起到同样的效果,其本质还是白名单。
有很多与安全相关的 Headers,也可以统一在 Web 框架中配置。比如用来对抗 ClickJacking
的 X-Frame-Options,需要在页面的 HTTP Response 中添加:
X-Frame-Options: SAMEORIGIN
数据持久层与 SQL 注入:
使用 ORM(Object/Relation Mapping)框架对 SQL 注入是有积极意义的。我们知道对抗
SQL 注入的最佳方式就是使用“预编译绑定变量”。