白帽子讲Web安全
2023-04-22 11:32:42 1 举报
AI智能生成
白帽子讲Web安全 思维导读 读书笔记
作者其他创作
大纲/内容
第三篇 服务器端应用安全
第7章 注入攻击
安全设计原则——“数据与代码分离”原则,它可以说是专门为了解决注入攻击而生的。
注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据。
7.1 SQL注入
在SQL注入的过程中,如果网站的Web服务器开启了错误回显,则会为攻击者提供极大的便利,比如攻击者在参数中输入一个单引号“'”,引起执行查询语句的语法错误,服务器直接返回了错误信息:
从错误信息中可以知道,服务器用的是Access作为数据库,查询语句的伪代码极有可能是:
错误回显披露了敏感信息,对于攻击者来说,构造SQL注入的语句就可以更加得心应手了。
7.1.1 盲注(BIind Injection)
所谓“盲注”,就是在服务器没有错误回显时完成的注入攻击。服务器没有错误回显,对于攻击者来说缺少了非常重要的“调试信息”,所以攻击者必须找到一个方法来验证注入的SQL语句是否得到执行。
最常见的盲注验证方法是,构造简单的条件语句,根据返回页面是否发生变化,来判断SQL语句是否得到执行。
7.1.2 Timing Attack
利用BENCHMARK()函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长;通过时间长短的变化,可以判断出注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack。
Timing Attack是盲注的一种高级技巧。在不同的数据库中,都有着类似于BENCHMARK()的函数,可以被Timing Attack所利用。
7.2 数据库攻击技巧
7.2.1 常见的攻击技巧
这个过程非常的烦琐,所以非常有必要使用一个自动化工具来帮助完成整个过程。sqlmap.py就是一个非常好的自动化注入工具。
7.2.2 命令执行
在MySQL中,除了可以通过导出webshell间接地执行命令外,还可以利用“用户自定义函数”的技巧,即UDF(User-Defined Functions)来执行命令。
UDF不仅仅是MySQL的特性,其他数据库也有着类似的功能。利用UDF的功能实施攻击的技巧也大同小异,查阅数据库的相关文档将会有所帮助。
在建立数据库账户时应该遵循“最小权限原则”,尽量避免给Web应用使用数据库的管理员权限。
7.2.3 攻击存储过程
存储过程为数据库提供了强大的功能,它与UDF很像,但存储过程必须使用CALL或者EXECUTE来执行。
7.2.4 编码问题
在有些时候,不同的字符编码也可能会导致一些安全问题。在注入的历史上,曾经出现过“基于字符集”的注入攻击技巧。
要解决这种问题,需要统一数据库、操作系统、Web应用所使用的字符集,以避免各层对字符的理解存在差异。统一设置为UTF-8是一个很好的方法。
7.2.5 SQL CoIumn Truncation
当MySQL的sql-mode设置为default时,即没有开启STRICT_ALL_TABLES选项时,MySQL对于用户插入的超长值只会提示warning,而不是error(如果是error则插入不成功),这可能会导致发生一些“截断”问题。
7.3 正确地防御SQL注入
从防御的角度来看,要做的事情有两件:
找到所有的SQL注入漏洞;
修补这些漏洞。
解决好这两个问题,就能有效地防御SQL注入攻击。
7.3.1 使用预编译语句
防御SQL注入的最佳方式,就是使用预编译语句,绑定变量。
在不同的语言中,都有着使用预编译语句的方法。
7.3.2 使用存储过程
我们还可以使用安全的存储过程对抗SQL注入。使用存储过程的效果和使用预编语句译类似,其区别就是存储过程需要先将SQL语句定义在数据库中。但需要注意的是,存储过程中也可能会存在注入问题,因此应该尽量避免在存储过程内使用动态的SQL语句。
7.3.3 检查数据类型
检查输入数据的数据类型,在很大程度上可以对抗SQL注入。
7.3.4 使用安全函数
各种Web语言都实现了一些编码函数,可以帮助对抗SQL注入。
7.4 其他注入攻击
7.4.1 XML注入
XML是一种常用的标记语言,通过标签对数据进行结构化表示。XML与HTML都是SGML(Standard Generalized Markup Language,标准通用标记语言)。
7.4.2 代码注入
代码注入比较特别一点。代码注入与命令注入往往都是由一些不安全的函数或者方法引起的,其中的典型代表就是eval()。
7.4.3 CRLF注入
CRLF实际上是两个字符:CR是Carriage Return (ASCII 13, \r), LF是Line Feed (ASCII 10,\n)。\r\n这两个字符是用于表示换行的,其十六进制编码分别为0x0d、0x0a。
7.5 小结
注入攻击是应用违背了“数据与代码分离原则”导致的结果。它有两个条件:一是用户能够控制数据的输入;二是代码拼凑了用户输入的数据,把数据当做代码执行了。
在对抗注入攻击时,只需要牢记“数据与代码分离原则”,在“拼凑”发生的地方进行安全检查,就能避免此类问题。
第8章 文件上传漏洞
8.1 文件上传漏洞概述
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。
8.1.1 从FCKEditor文件上传漏洞谈起
FCKEditor是一款非常流行的富文本编辑器,为了方便用户,它带有一个上传文件功能,但是这个功能却出过许多次漏洞。
黑名单是一种非常不好的设计思想。
8.1.2 绕过文件上传检查功能
针对上传文件的检查中,很多应用都是通过判断文件名后缀的方法来验证文件的安全性的。
JPG文件的文件头
在正常情况下,通过判断前10个字节,基本上就能判断出一个文件的真实类型。
隐藏在JPG文件中的PHP代码
8.2 功能还是漏洞
8.2.1 Apache文件解析问题
Apache对于文件名的解析是从后往前解析的,直到遇见一个Apache认识的文件类型为止。
rar是一个合法的上传需求,在应用里只判断文件的后缀是否是.rar,最终用户上传的是phpshell.php.rar.rar.rar,从而导致脚本被执行。
8.2.2 IIS文件解析问题
IIS 6在处理文件解析时,也出过一些漏洞。前面提到的0x00字符截断文件名,在IIS和Windows环境下曾经出过非常类似的漏洞,不过截断字符变成了分号“; ”。
8.2.3 PHP CGI路径解析问题
如果在任何配置为fastcgi的PHP应用里上传一张图片(可能是头像,也可能是论坛里上传的图片等),其图片内容是PHP文件,则将导致代码执行。
PHP官方给出的建议是将cgi.fix_pathinfo设置为0,但可以预见的是,官方的消极态度在未来仍然会使得许许多多的“不知情者”遭受损失。
8.2.4 利用上传文件钓鱼
在正常情况下,浏览器是不会将jpg文件当做HTML执行的,但是在低版本的IE中,比如IE 6和IE 7,包括IE 8的兼容模式,浏览器都会“自作聪明”地将此文件当做HTML执行。
8.3 设计安全的文件上传功能
根据攻击的原理,笔者结合实际经验总结了以下几点。
文件上传的目录设置为不可执行
只要Web容器无法解析该目录下的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响,因此此点至关重要。
判断文件类型
在文件类型检查中,强烈推荐白名单的方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。
使用随机数改写文件名和文件路径
像shell.php.rar.rar这种文件,或者是crossdomain.xml这种文件,都将因为文件名被改写而无法成功实施攻击。
单独设置文件服务器的域名
由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含JavaScript的XSS利用等问题将得到解决。
文件上传问题,看似简单,但要实现一个安全的上传功能,殊为不易。如果还要考虑到病毒、木马、色情图片与视频、反动政治文件等与具体业务结合更紧密的问题,则需要做的工作就更多了。不断地发现问题,结合业务需求,才能设计出最合理、最安全的上传功能。
8.4 小结
文件上传往往与代码执行联系在一起,因此对于所有业务中要用到的上传功能,都应该由安全工程师进行严格的检查。
第9章 认证与会话管理
9.1 Who am I?
实际上“认证”和“授权”是两件事情,认证的英文是Authentication,授权则是Authorization。分清楚这两个概念其实很简单,只需要记住下面这个事实:
认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么。
钥匙在认证过程中,被称为“凭证”(Credential),开门的过程,在互联网里对应的是登录(Login)。
可是开门之后,什么事情能做,什么事情不能做,就是“授权”的管辖范围了。
可以看到,“能否进入卧室”这个权限被授予的前提,是需要识别出来者到底是主人还是客人,所以如何授权是取决于认证的。
认证实际上就是一个验证凭证的过程。
如果只有一个凭证被用于认证,则称为“单因素认证”;如果有两个或多个凭证被用于认证,则称为“双因素(Two Factors)认证”或“多因素认证”。一般来说,多因素认证的强度要高于单因素认证,但是在用户体验上,多因素认证或多或少都会带来一些不方便的地方。
9.2 密码的那些事儿
根据OWASP推荐的一些最佳实践,我们可以对密码策略稍作总结。
密码长度方面:
普通应用要求长度为6位以上;
重要应用要求长度为8位以上,并考虑双因素认证。
密码复杂度方面:
密码区分大小写字母;
密码为大写字母、小写字母、数字、特殊符号中两种以上的组合;
不要有连续性的字符,比如1234abcd,这种字符顺着人的思路,所以很容易猜解;
尽量避免出现重复的字符,比如1111。
不要使用用户的公开数据,或者是与个人隐私相关的数据作为密码。比如不要使用QQ号、身份证号码、昵称、电话号码(含手机号码)、生日、英文名、公司名等作为密码,这些资料往往可以从互联网上获得,并不是那么保密。
微博网站Twitter在用户注册的过程中,列出了一份长达300个单词的弱密码列表,如果用户使用的密码被包含在这个列表中,则会提示用户此密码不安全。
密码必须以不可逆的加密算法,或者是单向散列函数算法,加密后存储在数据库中。
国内最大的开发者社区CSDN的数据库被黑客公布在网上。令人震惊的是,CSDN将用户的密码明文保存在数据库中,致使600万用户的密码被泄露。明文保存密码的后果很严重,黑客们曾经利用这些用户名与密码,尝试登录了包括QQ、人人网、新浪微博、支付宝等在内的很多大型网站,致使数以万计的用户处于风险中。
将明文密码经过哈希后(比如MD5或者SHA-1)再保存到数据库中,是目前业界比较普遍的做法——在用户注册时就已将密码哈希后保存在数据库中,登录时验证密码的过程仅仅是验证用户提交的“密码”哈希值,与保存在数据库中的“密码”哈希值是否一致。
目前黑客们广泛使用的一种破解MD5后密码的方法是“彩虹表(Rainbow Table)”。
彩虹表的思路是收集尽可能多的密码明文和明文对应的MD5值。这样只需要查询MD5值,就能找到该MD5值对应的明文。一个好的彩虹表,可能会非常庞大,但这种方法确实有效。彩虹表的建立,还可以周期性地计算一些数据的MD5值,以扩充彩虹表的内容。
一个提供彩虹表查询的MD5破解网站
为了避免密码哈希值泄露后,黑客能够直接通过彩虹表查询出密码明文,在计算密码明文的哈希值时,增加一个“Salt”。“Salt”是一个字符串,它的作用是为了增加明文的复杂度,并能使得彩虹表一类的攻击失效。
Salt应该保存在服务器端的配置文件中,并妥善保管。
9.3 多因素认证
支付宝提供的多种认证方式
9.4 Session与认证
密码与证书等认证手段,一般仅仅用于登录(Login)的过程。当登录完成后,用户访问网站的页面,不可能每次浏览器请求页面时都再使用密码认证一次。因此,当认证成功后,就需要替换一个对用户透明的凭证。这个凭证,就是SessionID。
SessionID除了可以保存在Cookie中外,还可以保存在URL中,作为请求的一个参数。但是这种方式的安全性难以经受考验。
在手机操作系统中,由于很多手机浏览器暂不支持Cookie,所以只能将SessionID作为URL的一个参数用于认证。
9.5 Session Fixation攻击
这个没有换“锁”而导致的安全问题,就是Session Fixation问题。
解决Session Fixation的正确做法是,在登录完成后,重写SessionID。
9.6 Session保持攻击
一般的应用都会给session设置一个失效时间,当到达失效时间后,Session将被销毁。但有一些系统,出于用户体验的考虑,只要这个用户还“活着”,就不会让这个用户的Session失效。从而攻击者可以通过不停地发起访问请求,让Session一直“活”下去。
Cookie的Expire时间是完全可以由客户端控制的。篡改这个时间,并使之永久有效,就有可能获得一个永久有效的Session,而服务器端是完全无法察觉的。
强制销毁Session可能会影响到一些正常的用户,还可以选择的方法是当用户客户端发生变化时,要求用户重新登录。比如用户的IP、UserAgent等信息发生了变化,就可以强制销毁当前的Session,并要求用户重新登录。
需要考虑的是同一用户可以同时拥有几个有效Session。若每个用户只允许拥有一个Session,则攻击者想要一直保持一个Session也是不太可能的。当用户再次登录时,攻击者所保持的Session将被“踢出”。
9.7 单点登录(SSO)
单点登录的英文全称是Single Sign On,简称SSO。它希望用户只需要登录一次,就可以访问所有的系统。
OpenID是一个开放的单点登录框架,它希望使用URI作为用户在互联网上的身份标识,每个用户(End User)将拥有一个唯一的URI。在用户登录网站(Relying Party)时,用户只需要提交他的OpenID(就是用户唯一的URI)以及OpenID的提供者(OpenID Provider),网站就会将用户重定向到OpenID的提供者进行认证,认证完成后再重定向回网站。
OpenID的认证流程可以用下图描述。
9.8 小结
认证解决的是“Who Am I? ”的问题,它就像一个房间的大门一样,是非常关键的一个环节。
双因素认证或多因素认证的方式,提高系统的安全强度。
在Web应用中,用户登录之后,服务器端通常会建立一个新的Session以跟踪用户的状态。每个Session对应一个标识符SessionID, SessionID用来标识用户身份,一般是加密保存在Cookie中。有的网站也会将Session保存在Cookie中,以减轻服务器端维护Session的压力。围绕着Session可能会产生很多安全问题,这些问题都是在设计安全方案时需要考虑到的。
第10章 访问控制
10.1 What Can I Do?
权限控制,或者说访问控制,广泛应用于各个系统中。抽象地说,都是某个主体(subject)对某个客体(object)需要实施某种操作(operation),而系统对这种操作的限制就是权限控制。
防火墙的ACL策略面板
在操作系统中,对文件的访问也有访问控制。此时“主体”是系统的用户,“客体”是被访问的文件,能否访问成功,将由操作系统给文件设置的ACL(访问控制列表)决定。
比如在Linux系统中,一个文件可以执行的操作分为“读”、“写”、“执行”三种,分别由r、w、x表示。这三种操作同时对应着三种主体:文件拥有者、文件拥有者所在的用户组、其他用户。主体、客体、操作这三者之间的对应关系,构成了访问控制列表。
在一个安全系统中,确定主体的身份是“认证”解决的问题;而客体是一种资源,是主体发起的请求的对象。在主体对客体进行操作的过程中,系统控制主体不能“无限制”地对客体进行操作,这个过程就是“访问控制”。
主体“能够做什么”,就是权限。权限可以细分成不同的能力(capability)。在Linux的文件系统中,将权限分成了“读”、“写”、“执行”三种能力。用户可能对某个文件拥有“读”的权限,但却没有“写”的权限。
10.2 垂直权限管理
访问控制实际上是建立用户与权限之间的对应关系,现在应用广泛的一种方法,就是“基于角色的访问控制(Role-Based Access Control)”,简称RBAC。
这种基于角色的权限管理(RBAC模型),我们可以称之为“垂直权限管理”。
在配置权限时,应当使用“最小权限原则”,并使用“默认拒绝”的策略,只对有需要的主体单独配置“允许”的策略。这在很多时候能够避免发生“越权访问”。
10.3 水平权限管理
URL经过rewrite后将参数映射成URL路径,但这并不妨碍通过修改用户id来实现攻击。在这里,id代表资源的唯一编号,因此通过篡改id,就能改变要访问的资源。
水平权限管理问题示意图
由于水平权限管理是系统缺乏一个数据级的访问控制所造成的,因此水平权限管理又可以称之为“基于数据的访问控制”。
对于数据的访问控制,与业务结合得十分紧密。有的业务有数据级访问控制的需求,有的业务则没有。
一个简单的数据级访问控制,可以考虑使用“用户组(Group)”的概念。比如一个用户组的数据只属于该组内的成员,只有同一用户组的成员才能实现对这些数据的操作。
水平权限管理问题,至今仍然是一个难题——它难以发现,难以在统一框架下解决,在未来也许会有新的技术用以解决此类问题。
10.4 OAuth简介
OAuth是一个在不提供用户名和密码的情况下,授权第三方应用访问Web资源的安全协议。
OAuth委员会实际上是从OpenID委员会中分离出来的(2006年12月), OAuth的设计原本想弥补OpenID中的一些缺陷或者说不够方便的地方,但后来发现需要设计一个全新的协议。
OAuth产生的背景
Request Token只能用于获取用户的授权,Access Token才能用于访问用户的资源。
新浪微博的OAuth使用过程
OAuth标准中的安全建议
常见的需要用到OAuth的地方有桌面应用、手机设备、Web应用,但OAuth 1.0只提供了统一的接口。这个接口对于Web应用来说尚可使用,但手机设备和桌面应用用起来则会有些别扭。同时OAuth 1.0的应用架构在扩展性方面也存在一些问题,当用户请求数庞大时,可能会遇到一些性能瓶颈。为了改变这些问题,OAuth 2.0应运而生。
10.5 小结
访问控制解决了“What Can I Do? ”的问题。
还分别介绍了“垂直权限管理”,它是一种“基于角色的访问控制”;以及“水平权限管理”,它是一种“基于数据的访问控制”。这两种访问控制方式,在进行安全设计时会经常用到。
访问控制与业务需求息息相关,并非一个单纯的安全问题。因此在解决此类问题或者设计权限控制方案时,要重视业务的意见。
无论选择哪种访问控制方式,在设计方案时都应该满足“最小权限原则”,这是权限管理的黄金法则。
第11章 加密算法与随机数
11.1 概述
达芬奇密码筒
常见的加密算法通常分为分组加密算法与流密码加密算法两种,两者的实现原理不同。
分组加密算法基于“分组”(block)进行操作,根据算法的不同,每个分组的长度可能不同。分组加密算法的代表有DES、3-DES、Blowfish、IDEA、AES等。
流密码加密算法,则每次只处理一个字节,密钥独立于消息之外,两者通过异或实现加密与解密。流密码加密算法的代表有RC4、ORYX、SEAL等。
11.2 Stream Cipher Attack
流密码是常用的一种加密算法,与分组加密算法不同,流密码的加密是基于异或(XOR)操作进行的,每次都只操作一个字节。但流密码加密算法的性能非常好,因此也是非常受开发者欢迎的一种加密算法。
11.2.1 Reused Key Attack
在流密码的使用中,最常见的错误便是使用同一个密钥进行多次加/解密。这将使得破解流密码变得非常简单。这种攻击被称为“Reused Key Attack”,在这种攻击下,攻击者不需要知道密钥,即可还原出明文。
11.2.2 Bit-fIipping Attack
解决Bit-flipping攻击的方法是验证密文的完整性,最常见的方法是增加带有KEY的MAC(消息验证码,Message Authentication Code),通过MAC验证密文是否被篡改。
通过哈希算法来实现的MAC,称为HMAC。HMAC由于其性能较好,而被广泛使用。如下图所示为HMAC的一种实现。
11.2.3 弱随机IV问题
4字节的IV是很脆弱的,它不够随机,我们完全可以通过“暴力破解”的方式找到重复的IV。
11.3 WEP破解
IV一旦开始重复,就会使得“Reused Key Attack”成为可能。同时通过收集大量的数据包,找到相同的IV,构造出相同的CRC-32校验值,也可以成功实施“Bit-flipping Attack”。
11.4 ECB模式的缺陷
ECB模式(电码簿模式)是最简单的一种加密模式,它的每个分组之间相对独立,其加密过程如下:
但ECB模式最大的问题也是出在这种分组的独立性上:攻击者只需要对调任意分组的密文,在经过解密后,所得明文的顺序也是经过对调的。
ECB模式可以交换密文或明文的顺序
ECB模式与CBC模式的对比效果
当需要加密的明文多于一个分组的长度时,应该避免使用ECB模式,而使用其他更加安全的加密模式。
11.5 Padding Oracle Attack
分组加密算法在实现加/解密时,需要把消息进行分组(block), block的大小常见的有64bit、128bit、256bit等。
在这个过程中,如果最后一个分组的消息长度没有达到block的大小,则需要填充一些字节,被称为padding。
PKCS#5填充效果示意图
Padding Oracle实际上是一种边信道攻击,攻击者只需要知道密文的解密结果是否正确即可,而这往往有许多途径。
比如在Web应用中,如果是padding不正确,则应用程序很可能会返回500的错误;如果padding正确,但解密出来的内容不正确,则可能会返回200的自定义错误。
如何通过Padding Oracle使得密文能够解密为任意明文呢?实际上通过前面的解密过程可以看出,通过改变IV,可以控制整个解密过程。因此在已经获得了Intermediary Value的情况下,很快就可以通过XOR运算得到可以生成任意明文的IV。
而对于多个分组的密文来说,从最后一组密文开始往前推。以两个分组为例,第二个分组使用的IV是第一个分组的密文(cipher text),因此当推导出第二个分组使用的IV时,将此IV值当做第一个分组的密文,再次进行推导。
11.6 密钥管理
在密码学里有个基本的原则:密码系统的安全性应该依赖于密钥的复杂性,而不应该依赖于算法的保密性。
在安全领域里,选择一个足够安全的加密算法不是困难的事情,难的是密钥管理。在一些实际的攻击案例中,直接攻击加密算法本身的案例很少,而因为密钥没有妥善管理导致的安全事件却很多。对于攻击者来说,他们不需要正面破解加密算法,如果能够通过一些方法获得密钥,则是件事半功倍的事情。
密钥管理中最常见的错误,就是将密钥硬编码在代码里。
硬编码的密钥,在以下几种情况下可能被泄露。
一是代码被广泛传播。这种泄露途径常见于一些开源软件;有的商业软件并不开源,但编译后的二进制文件被用户下载,也可能被逆向工程反编译后,泄露硬编码的密钥。
二是软件开发团队的成员都能查看代码,从而获知硬编码的密钥。开发团队的成员如果流动性较大,则可能会由此泄露代码。
对于第一种情况,如果一定要将密钥硬编码在代码中,我们尚可通过Diffie-Hellman交换密钥体系,生成公私钥来完成密钥的分发;而对于第二种情况,则只能通过改善密钥管理来保护密钥。
常见的做法是将密钥(包括密码)保存在配置文件或者数据库中,在使用时由程序读出密钥并加载进内存。密钥所在的配置文件或数据库需要严格的控制访问权限,同时也要确保运维或DBA中具有访问权限的人越少越好。
在应用发布到生产环境时,需要重新生成新的密钥或密码,以免与测试环境中使用的密钥相同。
密钥管理的主要目的,还是为了防止密钥从非正常的渠道泄露。定期更换密钥也是一种有效的做法。一个比较安全的密钥管理系统,可以将所有的密钥(包括一些敏感配置文件)都集中保存在一个服务器(集群)上,并通过Web Service的方式提供获取密钥的API。每个Web应用在需要使用密钥时,通过带认证信息的API请求密钥管理系统,动态获取密钥。Web应用不能把密钥写入本地文件中,只加载到内存,这样动态获取密钥最大程度地保护了密钥的私密性。密钥集中管理,降低了系统对于密钥的耦合性,也有利于定期更换密钥。
11.7 伪随机数问题
伪随机数(pseudo random number)问题——伪随机数不够随机,是程序开发中会出现的一个问题。
伪随机数,是通过一些数学算法生成的随机数,并非真正的随机数。密码学上的安全伪随机数应该是不可压缩的。对应的“真随机数”,则是通过一些物理系统生成的随机数,比如电压的波动、硬盘磁头读/写时的寻道时间、空中电磁波的噪声等。
11.7.1 弱伪随机数的麻烦
Sun Java 6 Update 11之前的createTempFile()中存在一个随机数可预测的问题,在短时间内生成的随机数实际上是顺序增长的。
这个函数经常被用于生成临时文件。如果临时文件可以被预测,那么根据业务逻辑的不同,将导致各种不可预估的结果,严重的将导致系统被破坏,或者为攻击者打开大门。
在官方解决方案中,一方面增大了随机数的空间,另一方面修补了顺序增长的问题。
在Web应用中,使用伪随机数的地方非常广泛。密码、key、SessionID、token等许多非常关键的“secret”往往都是通过伪随机数算法生成的。如果使用了弱伪随机数算法,则可能会导致非常严重的安全问题。
11.7.2 时间真的随机吗
在开发程序时,要切记:不要把时间函数当成随机数使用。
11.7.3 破解伪随机数算法的种子
伪随机数是由数学算法实现的,它真正随机的地方在于“种子(seed)”。种子一旦确定后,再通过同一伪随机数算法计算出来的随机数,其值是固定的,多次计算所得值的顺序也是固定的。
11.7.4 使用安全的随机数
在重要或敏感的系统中,一定要使用足够强壮的随机数生成算法。在Java中,可以使用java.security.SecureRandom
而在Linux中,可以使用/dev/random或者 /dev/urandom来生成随机数
从算法上还可以通过多个随机数的组合,以增加随机数的复杂性。比如通过给随机数使用MD5算法后,再连接一个随机字符,然后再使用MD5算法一次。
11.8 小结
在加密算法的选择和使用上,有以下最佳实践:
不要使用ECB模式;
不要使用流密码(比如RC4);
使用HMAC-SHA1代替MD5(甚至是代替SHA1);
不要使用相同的key做不同的事情;
salts与IV需要随机产生;
不要自己实现加密算法,尽量使用安全专家已经实现好的库;
不要依赖系统的保密性。
当你不知道该如何选择时,有以下建议:
使用CBC模式的AES256用于加密;
使用HMAC-SHA512用于完整性检查;
使用带salt的SHA-256或SHA-512用于Hashing。
以MD5为例,首先算法将消息以512bit(就是64字节)的长度分组。最后一组必然不足512bit,这时算法就会自动往最后一组中填充字节,这个过程被称为padding。
当知道MD5(secret) 时,在不知道secret的情况下,可以很轻易地推算出MD5(secret||padding||m')。
所以要实施Length Extension Attack,就需要找到MD5(secret)最后压缩的值,并算出其padding,然后加入到下一轮的MD5压缩算法中,算出最终我们需要的值。
MD5算法会对消息进行分组,每组64个字节,不足64个字节的部分用padding补齐。padding的规则是,在最末一个字节之后补充0x80,其余的部分填充为0x00, padding最后的8个字节用来表示需要哈希的消息长度。
对消息进行分组以及padding后,MD5算法开始依次对每组消息进行压缩,经过64轮数学变换。在这个过程中,一开始会有定义好的初始化向量,为4个中间值,初始化向量不是随机生成的,是标准里定义死的——是的,你没看错,这是“硬编码”!
How to Fix?
MD5、SHA-1之类的使用Merkle-Damgård hash construction的算法是没希望了。
使用HMAC-SHA1之类的HMAC算法吧,目前HMAC还没有发现过安全漏洞。
另外,针对Flickr API等将参数签名的应用来说,secret放置在参数末尾也能防止这种攻击。
比如MD5(m+secret),希望推导出MD5(m+secret||padding||m'),结果由于自动附加secret在末尾的关系,会变成MD5(m||padding||m'||secret),从而导致Length Extension run不起来。
第12章 Web框架安全
12.1 MVC框架安全
MVC是Model-View-Controller的缩写,它将Web应用分为三层,View层负责用户视图、页面展示等工作;Controller负责应用的逻辑实现,接收View层传入的用户请求,并转发给对应的Model做处理;Model层则负责实现模型,完成数据的处理。
在MVC框架中,通过切片、过滤器等方式,往往能对数据进行全局处理,这为设计安全方案提供了极大的便利。
一个优秀的安全方案,应该是:在正确的地方,做正确的事情。
对应到MVC架构里,它是在View层做这件事情的,而SQL注入是Model层需要解决的问题,Model层的事情搞到View层去解决,效果只会适得其反。
在框架中实施安全方案,比由程序员在业务中修复一个个具体的bug,有着更多的优势。
12.2 模板引擎与XSS防御
在View层,可以解决XSS问题。在本书的“跨站脚本攻击”一章中,阐述了“输入检查”与“输出编码”这两种方法在XSS防御效果上的差异。XSS攻击是在用户的浏览器上执行的,其形成过程则是在服务器端页面渲染时,注入了恶意的HTML代码导致的。从MVC架构来说,是发生在View层,因此使用“输出编码”的防御方法更加合理,这意味着需要针对不同上下文的XSS攻击场景,使用不同的编码方式。
在“跨站脚本攻击”一章中,我们将“输出编码”的防御方法总结为以下几种:
在HTML标签中输出变量;
在HTML属性中输出变量;
在script标签中输出变量;
在事件中输出变量;
在CSS中输出变量;
在URL中输出变量。
在很多Web框架官方文档中推荐的用法,就是存在缺陷的。Web框架的开发者在设计安全方案时,有时会缺乏来自安全专家的建议。所以开发者在使用框架时,应该慎重对待安全问题,不可盲从官方指导文档。
12.3 Web框架与CSRF防御
CSRF攻击的目标,一般都会产生“写数据”操作的URL,比如“增”、“删”、“改”;而“读数据”操作并不是CSRF攻击的目标,因为在CSRF的攻击过程中攻击者无法获取到服务器端返回的数据,攻击者只是借用户之手触发服务器动作,所以读数据对于CSRF来说并无直接的意义(但是如果同时存在XSS漏洞或者其他的跨域漏洞,则可能会引起别的问题,在这里,仅仅就CSRF对抗本身进行讨论)。
在Web应用开发中,有必要对“读操作”和“写操作”予以区分,比如要求所有的“写操作”都使用HTTP POST。
12.4 HTTP Headers管理
Cookie的HttpOnly Flag,它能告诉浏览器不要让JavaScript访问该Cookie,在Session劫持等问题上有着积极的意义,而且成本非常小。
一般来说,框架会提供一个统一的设置Cookie函数,HttpOnly的功能可以在此函数中实现;如果没有这样的函数,则需要统一在HTTP返回头中配置实现。
12.5 数据持久层与SQL注入
使用ORM(Object/Relation Mapping)框架对SQL注入是有积极意义的。我们知道对抗SQL注入的最佳方式就是使用“预编译绑定变量”。在实际解决SQL注入时,还有一个难点就是应用复杂后,代码数量庞大,难以把可能存在SQL注入的地方不遗漏地找出来,而ORM框架为我们发现问题提供了一个便捷的途径。
12.6 还能想到什么
凡是在Web框架中可能实现的安全方案,只要对性能没有太大的损耗,都应该考虑实施。
在设计安全逻辑时也需要考虑到日志的记录,比如发生XSS攻击时,可以记录下攻击者的IP、时间、UserAgent、目标URL、用户名等信息。这些日志,对于后期建立攻击事件分析、入侵分析都是有积极意义的。当然,开启日志也会造成一定的性能损失,因此在设计时,需要考虑日志记录行为的频繁程度,并尽可能避免误报。
12.7 Web框架自身安全
12.7.1 Struts 2命令执行漏洞
XWork通过getters/setters方法从HTTP的参数中获取对应action的名称,这个过程是基于OGNL(Object Graph Navigation Language)的。
12.7.2 Struts 2的问题补丁
关于如何正确地防御XSS漏洞,请参考本书的“跨站脚本攻击”一章。
12.7.3 Spring MVC命令执行漏洞
由于Spring框架允许使用客户端所提供的数据来更新对象属性,而这一机制允许攻击者修改class.classloader加载对象的类加载器的属性,这可能导致执行任意命令。例如,攻击者可以将类加载器所使用的URL修改到受控的位置。
12.7.4 Django命令执行漏洞
Django在处理消息文件时存在问题,远程攻击者构建恶意.po文件,诱使用户访问处理,可导致以应用程序进程权限执行任意命令。
12.8 小结
Web框架为安全方案的设计提供了很多便利,好好利用它的强大功能,能够设计出非常优美的安全方案。
第13章 应用层拒绝服务攻击
在互联网中一谈起DDOS攻击,人们往往谈虎色变。DDOS攻击被认为是安全领域中最难解决的问题之一,迄今为止也没有一个完美的解决方案。
13.1 DDOS简介
DDOS又称为分布式拒绝服务,全称是Distributed Denial of Service。DDOS本是利用合理的请求造成资源过载,导致服务不可用。
常见的DDOS攻击有SYN flood、UDP flood、ICMP flood等。
其中SYN flood是一种最为经典的DDOS攻击,其发现于1996年,但至今仍然保持着非常强大的生命力。SYN flood如此猖獗是因为它利用了TCP协议设计中的缺陷,而TCP/IP协议是整个互联网的基础,牵一发而动全身,如今想要修复这样的缺陷几乎成为不可能的事情。
在正常情况下,TCP三次握手过程如下:
客户端向服务器端发送一个SYN包,包含客户端使用的端口号和初始序列号x;
服务器端收到客户端发送来的SYN包后,向客户端发送一个SYN和ACK都置位的TCP报文,包含确认号x+1和服务器端的初始序列号y;
客户端收到服务器端返回的SYN+ACK报文后,向服务器端返回一个确认号为y+1、序号为x+1的ACK报文,一个标准的TCP连接完成。
对抗SYN flood的主要措施有SYN Cookie/SYN Proxy、safereset等算法。SYN Cookie的主要思想是为每一个IP地址分配一个“Cookie”,并统计每个IP地址的访问频率。如果在短时间内收到大量的来自同一个IP地址的数据包,则认为受到攻击,之后来自这个IP地址的包将被丢弃。
在实际的攻击中,DDOS的流量甚至可以达到数G到几十G,遇到这种情况,只能与网络运营商合作,共同完成DDOS攻击的响应。
13.2 应用层DDOS
13.2.1 CC攻击
“CC攻击”的前身是一个叫fatboy的攻击程序,当时黑客为了挑战绿盟的一款反DDOS设备开发了它。绿盟是中国著名的安全公司之一,它有一款叫“黑洞(Collapasar)”的反DDOS设备,能够有效地清洗SYN Flood等有害流量。而黑客则挑衅式地将fatboy所实现的攻击方式命名为:Challenge Collapasar(简称CC),意指在黑洞的防御下,仍然能有效完成拒绝服务攻击。
CC攻击的原理非常简单,就是对一些消耗资源较大的应用页面不断发起正常的请求,以达到消耗服务端资源的目的。
在互联网中充斥着各种搜索引擎、信息收集等系统的爬虫(spider),爬虫把小网站直接爬死的情况时有发生,这与应用层DDOS攻击的结果很像。由此看来,应用层DDOS攻击与正常业务的界线比较模糊。
应用层DDOS攻击是针对服务器性能的一种攻击,那么许多优化服务器性能的方法,都或多或少地能缓解此种攻击。比如将使用频率高的数据放在memcache中,相对于查询数据库所消耗的资源来说,查询memcache所消耗的资源可以忽略不计。但很多性能优化的方案并非是为了对抗应用层DDOS攻击而设计的,因此攻击者想要找到一个资源消耗大的页面并不困难。比如当memcache查询没有命中时,服务器必然会查询数据库,从而增大服务器资源的消耗,攻击者只需要找到这样的页面即可。同时攻击者除了触发“读”数据操作外,还可以触发“写”数据操作,“写”数据的行为一般都会导致服务器操作数据库。
13.2.2 限制请求频率
最常见的针对应用层DDOS攻击的防御措施,是在应用中针对每个“客户端”做一个请求频率的限制。
13.2.3 道高一尺,魔高一丈
然而这种防御方法并不完美,因为它在客户端的判断依据上并不是永远可靠的。这个方案中有两个因素用以定位一个客户端:一个是IP地址,另一个是Cookie。但用户的IP地址可能会发生改变,而Cookie又可能会被清空,如果IP地址和Cookie同时都发生了变化,那么就无法再定位到同一个客户端了。
应用代码要做好性能优化。合理地使用memcache就是一个很好的优化方案,将数据库的压力尽可能转移到内存中。此外还需要及时地释放资源,比如及时关闭数据库连接,减少空连接等消耗。
其次,在网络架构上做好优化。善于利用负载均衡分流,避免用户流量集中在单台服务器上。同时可以充分利用好CDN和镜像站点的分流作用,缓解主站的压力。
实现一些对抗手段,比如限制每个IP地址的请求频率。
13.3 验证码的那些事儿
验证码是互联网中常用的技术之一,它的英文简称是CAPTCHA(Completely Automated Public Turing Test to Tell Computers and Humans Apart,全自动区分计算机和人类的图灵测试)。
在很多时候,如果可以忽略对用户体验的影响,那么引入验证码这一手段能够有效地阻止自动化的重放行为。
还有的验证码实现方式,是提前将所有的验证码图片生成好,以哈希过的字符串作为验证码图片的文件名。在使用验证码时,则直接从图片服务器返回已经生成好的验证码,这种设计原本的想法是为了提高性能。
但这种一一对应的验证码文件名会存在一个缺陷:攻击者可以事先采用枚举的方式,遍历所有的验证码图片,并建立验证码到明文之间的一一对应关系,从而形成一张“彩虹表”,这也会导致验证码形同虚设。修补的方式是验证码的文件名需要随机化,满足“不可预测性”原则。
随着技术的发展,直接通过算法破解验证码的方法也变得越来越成熟。通过一些图像处理技术,可以将验证码逐步变化成可识别的图片。
13.4 防御应用层DDOS
在Apache的配置文件中,有一些参数可以缓解DDOS攻击。比如调小Timeout、KeepAliveTimeout值,增加MaxClients值。
Yahoo为我们提供了一个解决思路。因为发起应用层DDOS攻击的IP地址都是真实的,所以在实际情况中,攻击者的IP地址其实也不可能无限制增长。假设攻击者有1000个IP地址发起攻击,如果请求了10000次,则平均每个IP地址请求同一页面达到10次,攻击如果持续下去,单个IP地址的请求也将变多,但无论如何变,都是在这1000个IP地址的范围内做轮询。
为此Yahoo实现了一套算法,根据IP地址和Cookie等信息,可以计算客户端的请求频率并进行拦截。Yahoo设计的这套系统也是为Web Server开发的一个模块,但在整体架构上会有一台master服务器集中计算所有IP地址的请求频率,并同步策略到每台WebServer上。
Yahoo为此申请了一个专利(Detecting system abuse),因此我们可以查阅此专利的公开信息,以了解更多的详细信息。
13.5 资源耗尽攻击
13.5.1 SIowIoris攻击
Slowloris是在2009年由著名的Web安全专家RSnake提出的一种攻击方法,其原理是以极低的速度往服务器发送HTTP请求。由于Web Server对于并发的连接数都有一定的上限,因此若是恶意地占用住这些连接不释放,那么Web Server的所有连接都将被恶意连接占用,从而无法接受新的请求,导致拒绝服务。
此类拒绝服务攻击的本质,实际上是对有限资源的无限制滥用。
13.5.2 HTTP POST DOS
原理是在发送HTTP POST包时,指定一个非常大的Content-Length值,然后以很低的速度发包,比如10~100s发一个字节,保持住这个连接不断开。这样当客户端连接数多了以后,占用住了Web Server的所有可用连接,从而导致DOS。
凡是资源有“限制”的地方,都可能发生资源滥用,从而导致拒绝服务,也就是一种“资源耗尽攻击”。
13.5.3 Server Limit DOS
Web Server对HTTP包头都有长度限制,以Apache举例,默认是8192字节。也就是说,Apache所能接受的最大HTTP包头大小为8192字节(这里指的是Request Header,如果是Request Body,则默认的大小限制是2GB)。
攻击者通过XSS攻击,恶意地往客户端写入了一个超长的Cookie,则该客户端在清空Cookie之前,将无法再访问该Cookie所在域的任何页面。这是因为Cookie也是放在HTTP包头里发送的,而Web Server默认会认为这是一个超长的非正常请求,从而导致“客户端”的拒绝服务。
要解决此问题,需要调整Apache配置参数LimitRequestFieldSize,这个参数设置为0时,对HTTP包头的大小没有限制。
13.6 一个正则引发的血案:ReDOS
ReDOS是一种代码实现上的缺陷。我们知道正则表达式是基于NFA(Nondeterministic Finite Automaton)的,它是一个状态机,每个状态和输入符号都可能有许多不同的下一个状态。正则解析引擎将遍历所有可能的路径直到最后。由于每个状态都有若干个“下一个状态”,因此决策算法将逐个尝试每个“下一个状态”,直到找到一个匹配的。
当用户恶意构造输入时,这些有缺陷的正则表达式就会消耗大量的系统资源(比如CPU和内存),从而导致整台服务器的性能下降,表现的结果是系统速度很慢,有的进程或服务失去响应,与拒绝服务的后果是一样的。
在今天的互联网中,正则表达式可能存在于任何地方,但只要任何一个环节存在有缺陷的正则表达式,就都有可能导致一次ReDOS。
13.7 小结
应用层拒绝服务攻击是传统的网络拒绝服务攻击的一种延伸,其本质也是对有限资源的无限制滥用所造成的。所以,解决这个问题的核心思路就是限制每个不可信任的资源使用者的配额。
第14章PHP安全
14.1 文件包含漏洞
当使用这4个函数包含一个新的文件时,该文件将作为PHP代码执行,PHP内核并不会在意该被包含的文件是什么类型。所以如果被包含的是txt文件、图片文件、远程URL,也都将作为PHP代码执行。这一特性,在实施攻击时将非常有用。
要想成功利用文件包含漏洞,需要满足下面两个条件:
include()等函数通过动态变量的方式引入需要包含的文件;
用户能够控制该动态变量。
14.1.1 本地文件包含
能够打开并包含本地文件的漏洞,被称为本地文件包含漏洞(Local File Inclusion,简称LFI)。
14.1.2 远程文件包含
如果PHP的配置选项allow_url_include为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞(Remote File Inclusion,简称RFI)。
14.1.3 本地文件包含的利用技巧
远程文件包含漏洞之所以能够执行命令,就是因为攻击者能够自定义被包含的文件内容。因此本地文件包含漏洞想要执行命令,也需要找到一个攻击者能够控制内容的本地文件。
PHP处理上传文件的过程是这样的:
14.2 变量覆盖漏洞
14.2.1 全局变量覆盖
变量如果未被初始化,且能被用户所控制,那么很可能会导致安全问题。
14.2.2 extract()变量覆盖
extract()函数能将变量从数组导入当前的符号表,当extract() 函数从用户可以控制的数组中导出变量时,可能发生变量覆盖。
14.2.3 遍历初始化变量
常见的一些以遍历的方式释放变量的代码,可能会导致变量覆盖。
14.2.4 import_request_variabIes变量覆盖
import_request_variables() 将GET、POST、Cookie中的变量导入到全局,使用这个函数只需要简单地指定类型即可。其中第二个参数是为导入的变量添加的前缀,如果没有指定,则将覆盖全局变量。
14.2.5 parse_str()变量覆盖
parse_str()函数往往被用于解析URL的query string,但是当参数值能被用户控制时,很可能导致变量覆盖。
14.3 代码执行漏洞
14.3.1 “危险函数”执行代码
14.3.1.1 phpMyAdmin 3.4.3.1远程代码执行漏洞
在phpMyAdmin版本3.3.10.2与3.4.3.1以下存在一个变量覆盖漏洞,漏洞编号为:CVE-2011-2505,漏洞代码存在于libraries/auth/swekey/swekey.auth.lib.php中。
14.3.1.2 MyBB 1.4远程代码执行漏洞
挖掘漏洞的过程,通常需要先找到危险函数,然后回溯函数的调用过程,最终看在整个调用的过程中用户是否有可能控制输入。
14.3.2 “文件写入”执行代码
如果文件操作的内容用户可以控制,则也极容易成为漏洞。
14.3.3 其他执行代码方式
直接执行代码的函数
文件包含
本地文件写入
preg_replace()代码执行
动态函数执行
Curly Syntax
回调函数执行代码
unserialize()导致代码执行
14.4 定制安全的PHP环境
推荐php.ini中一些安全相关参数的配置。
register_globals
open_basedir
allow_url_include
display_errors
log_errors
magic_quotes_gpc
cgi.fix_pathinfo
session.cookie_httponly
session.cookie_secure
safe_mode
safe_mode在当前的PHP版本中会影响以下函数。
safe_mode被绕过的情况,往往是因为加载了一些非官方的PHP扩展。扩展自带的函数可以绕过safe_mode,因此请谨慎加载非默认开启的PHP扩展,除非能确认它们是安全的。
disable_functions
disable_functions能够在PHP中禁用函数。这是把双刃剑,禁用函数可能会为开发带来不便,但禁用的函数太少又可能增加开发写出不安全代码的几率,同时为黑客获取webshell提供便利。
14.5 小结
PHP是一门被广泛使用的Web开发语言,它的语法和使用方式非常灵活,这也导致了PHP代码安全评估的难度相对较高。
第15章 Web Server配置安全
Web服务器是Web应用的载体,如果这个载体出现安全问题,那么运行在其中的Web应用程序的安全也无法得到保障。因此Web服务器的安全不容忽视。
15.1 Apache安全
Web Server的安全我们关注两点:一是Web Server本身是否安全;二是Web Server是否提供了可使用的安全功能。
检查Apache安全的第一件事情,就是检查Apache的Module安装情况,根据“最小权限原则”,应该尽可能地减少不必要的Module,对于要使用的Module,则检查其对应版本是否存在已知的安全漏洞。
Apache以root身份或者admin身份运行是一个非常糟糕的决定。这里的admin身份是指服务器管理员在管理机器时使用的身份。这个身份的权限也是比较高的,因为管理员有操作管理脚本、访问配置文件、读/写日志等需求。
使用高权限身份运行Apache的结果可能是灾难性的,它会带来两个可怕的后果:
当黑客入侵Web成功时,将直接获得一个高权限(比如root或admin)的shell;
应用程序本身将具备较高权限,当出现bug时,可能会带来较高风险,比如删除本地重要文件、杀死进程等不可预知的结果。
比较好的做法是使用专门的用户身份运行Apache,这个用户身份不应该具备shell,它唯一的作用就是用来运行Web应用。
单台机器的性能毕竟有限,所以对抗DDOS不可依赖于这些参数,但聊胜于无。
一般来说,攻击者入侵成功后,要做的第一件事情就是清除入侵痕迹,修改、删除日志文件,因此access log应当妥善保管,比如实时地发送到远程的syslog服务器上。
15.2 Nginx安全
近年来Nginx发展很快,它的高性能和高并发的处理能力使得用户在Web Server的选择上有了更多的空间。但从安全的角度来看,Nginx近年来出现的影响默认安装版本的高危漏洞却比Apache要多。
从历史的经验来看,如果一个软件出现的漏洞较多,那么说明代码维护者的安全意识与安全经验有所欠缺,同时由于破窗效应,这个软件未来往往会出现更多的漏洞。
Nginx与Apache最大的区别在于,检查Apache安全时更多的要关注Module的安全,而Nginx则需要注意软件本身的安全,及时升级软件版本。
Web Server对于DDOS攻击的防御作用是有限的。对于大规模的拒绝服务攻击,需要使用更加专业的保护方案。
15.3 jBoss远程命令执行
jBoss是J2EE环境中一个流行的Web容器,但是jBoss在默认安装时提供的一些功能却不太安全,如果配置不得当,则可能直接造成远程命令执行。
jBoss在默认安装时会有一个管理后台,叫做JMX-Console,它提供给管理员一些强大的功能,其中包括配置MBeans,这同样也会为黑客们打开方便之门。通过8080端口(默认安装时会监听8080端口)访问 /jmx-console能够进入到这个管理界面。默认安装时访问JMX-Console是没有任何认证的。
15.4 Tomcat远程命令执行
虽然Tomcat后台有密码认证,但笔者仍然强烈建议删除这一后台,因为攻击者可以通过暴力破解等方式获取后台的访问权限,从安全的角度看,这增加了系统的攻击面,得不偿失。
15.5 HTTP Parameter Pollution
在2009年的OWASP大会上,Luca、Carettoni等人演示了这种被称为HPP的攻击。简单来说,就是通过GET或POST向服务器发起请求时,提交两个相同的参数,那么服务器会如何选择呢?
这种HPP攻击,与Web服务器环境、服务器端使用的脚本语言有关。HPP本身可以看做服务器端软件的一种功能,参数选择的顺序是由服务器端软件所决定的。但是正如我们在本书中所举的很多例子一样,当程序员不熟悉软件的这种功能时,就有可能造成误用,或者程序逻辑涵盖范围不够全面,从而形成漏洞。
比如可以通过HPP混淆参数,从而绕过ModSecurity对于SQL注入的检测。
HPP这一问题再次提醒我们,设计安全方案必须要熟悉Web技术方方面面的细节,才不至于有所疏漏。从防范上来看,由于HPP是服务器软件的一种功能,所以只需在具体的环境中注意服务器环境的参数取值顺序即可。
15.6 小结
在搭建服务器端环境时,需要注意最小权限原则,应该以独立的低权限身份运行Web进程。同时Web Server的一些参数能够优化性能,有助于缓解DDOS攻击,在实际运用时可以酌情使用。
第四篇 互联网公司安全运营
第16章 互联网业务安全
16.1 产品需要什么样的安全
安全是产品的一个特性,如果我们的产品能够潜移默化地培养用户的安全习惯,将用户往更安全的行为上引导,那么这样的安全就是最理想的产品安全。
16.1.1 互联网产品对安全的需求
当一个产品其他方面都做得很好的时候,安全有可能会成为产品的一种核心竞争力,成为拉开产品与竞争对手之间差距的秘密武器。
只有安全也做得好的产品,才能成为真正的好产品。
Google与Stopbadware展开了合作,Stopbadware提供一份实时更新的恶意网站列表给Google,其中包括了挂马网站、钓鱼网站、欺诈网站等;而Google则根据这份名单对搜索引擎结果中的数据进行筛选,过滤掉不安全的结果。
钓鱼网站、欺诈网站通常使用一些搜索引擎优化(SEO)技术,来提高自身在搜索结果中的排名,一旦被搜索引擎收录,就可以更有效地传播,骗到更多的人。
挂马网站略有不同,挂马网站往往是黑客入侵了一个颇受欢迎的网站之后,篡改了网站的页面。黑客在网页中植入一段攻击代码,试图利用浏览器的漏洞攻击网站的用户。
目前搜索引擎的普遍做法是与专业的安全厂商进行合作,排查搜索结果中的恶意网址。
在电子邮箱领域,最重要的一项安全特性就是“反垃圾邮件”。
安全性做得好的产品,对于用户来说可能不会有什么特别的感觉,因为坏人、坏的信息已经被处理掉了;相反,如果产品安全没有做好,则用户一定会感受到:垃圾消息泛滥、骗子满地跑,这些业务安全的问题会带来糟糕的用户体验,有时候甚至会毁掉一个新兴的领域。
16.1.2 什么是好的安全方案
一个优秀的安全方案,除了可以有效地解决问题以外,至少还必须具备两个条件:
良好的用户体验;
优秀的性能。
双因素认证可能会降低用户体验,因为用户使用起来更加麻烦了。
手机短信有一个到达率的问题,有些国外的用户就接收不到手机短信;
“U盾”、“令牌”的制作成本比较高,不大面积推广的话是一笔不菲的花费;
客户端证书则需要解决不同浏览器、不同操作系统的兼容问题,以及证书的过期与更新也不是件容易的事情。
复杂密码安全吗?
设置复杂密码也是一种糟糕的体验。
所以“提高密码复杂度”这个安全需求,其本质其实可以分解为:
如何对抗暴力破解;
检查一个账户在一段时间内的登录失败次数,或者检测某一个IP地址在一段时间内的登录行为次数。这些行为都是比较明显的暴力破解特征。暴力破解往往还借助了脚本或者扫描器,那么在检测到此类行为后,向特定客户端返回一个验证码,也可以有效地缓解暴力破解攻击。
如何防止密码中包含个人信息。
如何防止密码中包含个人信息呢?在用户注册时,可以收集到用户填写的个人资料,如果发现用户使用了诸如:用户名、邮件地址、生日、电话号码之类的个人信息作为密码,则应当立即进行提示。
“威胁分析”是设计安全方案的基础。
16.2 业务逻辑安全
16.2.1 永远改不掉的密码
业务逻辑问题是一种设计缺陷,在产品开发过程中,可以考虑在产品设计和测试阶段解决。
16.2.2 谁是大赢家
当认定某一IP地址存在恶意行为后,对IP地址的历史记录追加处罚。这样就不会阻碍正常用户的访问,而仅仅把坏人关在门外。
16.2.3 瞒天过海
电视台的滚动信息被黑客篡改
16.2.4 关于密码取回流程
在进行敏感操作之前再次认证用户的身份。
16.3 账户是如何被盗的
16.3.1 账户被盗的途径
可以得出安全工作的优先级。从以上分析可以看出:
如果网站将用户的密码明文保存在数据库中,或者没有加Salt的哈希值,则黑客可以根据这些密码,再次尝试入侵同一用户的邮箱、IM等第三方网站账户。因为大部分用户都习惯于使用同一个密码登录不同的网站。
16.3.2 分析账户被盗的原因
首先,客服是最重要和直接的渠道。
其次,从日志中寻找证据。
最后,打入敌人内部,探听最新动态。
16.4 互联网的垃圾
16.4.1 垃圾的危害
在网站应用中,垃圾注册几乎成为一切业务安全问题的源头。
“目的不是网站所提供的服务”的注册账户,都属于垃圾账户。
淘宝网的商品评价中的垃圾信息
搜索到的自动注册机结果
16.4.2 垃圾处理
仔细分析垃圾行为特征,可以大致分成:内容的特征、行为的特征、客户端本身的特征。从这三个方面入手,可以得出不同类型的规则。
基于内容的规则:以自然语言分析、关键词匹配等为代表。
基于行为的规则:以业务逻辑规则为代表。
基于客户端识别的规则:以人机识别为代表,比如验证码,或者让客户端去解析JavaScript。
识别出非法用户和非法行为后,在“拦截”上也需要讲究策略和战术。因为很多时候,规则都是“见光死”,规则的保密性非常重要。如果使用规则和恶意用户做直接对抗,那么规则的内容很容易暴露,导致规则很快会被绕过。
如果不是特别紧急的业务,则可以打一个时间差。当使用规则识别出垃圾账户后,过一段时间再做处理,这样恶意用户就摸不准到底触犯了哪条规则。
同时还可以“打压”大部分账户,放过一小批账户。这样既控制住大部分的风险,又让风险不会随意转移,可以一直把可控的风险放在明处。
16.5 关于网络钓鱼
16.5.1 钓鱼网站简介
网络钓鱼大多集中在网络购物、网上银行等行业。
看出淘宝网的钓鱼网站是目前国内钓鱼网站的主流。
淘宝网上的购物有自己的IM——淘宝旺旺,在旺旺上传播的钓鱼网站一般是模仿淘宝网的钓鱼网站;而在QQ上,更多的是传播拍拍与财付通的钓鱼网站。
16.5.2 邮件钓鱼
基于IP的策略,一旦写死,维护起来也是一件非常痛苦的事情。这意味着发信方域的邮件服务器IP不能做较大的变化——一旦IP变化了,SPF策略却未及时更新,就可能会造成大面积误杀。SPF仍然成为对抗“邮件地址伪造”的一项主要技术,在没有更好的技术出现时,只能选择去推广SPF。
16.5.3 钓鱼网站的防控
16.5.3.1 控制钓鱼网站传播途径
控制钓鱼网站传播的途径,就能对钓鱼网站实施有效的打击。
Google公开了一个“Safe Browsing API”,公布了Google发现的这些恶意网址。通过“Safe Browsing API”,可以获取钓鱼网址、挂马网址、诈骗网址的黑名单。
16.5.3.2 直接打击钓鱼网站
目前中国法律方面对网络犯罪的相关条例尚不完善。以往的网络犯罪案件,仍然是使用传统法律条款进行解释。“盗窃罪”和“诈骗罪”是网络犯罪案件中被引用得最多的条款。
16.5.3.3 用户教育
用户教育永远是安全工作中必不可少的一环。网站需要告知用户什么是好的,什么是坏的。
16.5.3.4 自动化识别钓鱼网站
自动识别钓鱼网站是一项复杂的工作,不同的思路会有不同的结果。同时这项工作必然是在不断的对抗中成长,没有一成不变的规则和模型,也没有一成不变的钓鱼网站。
16.5.4 网购流程钓鱼
贯穿不同平台的唯一标识,是订单号。订单中只包含了商品信息,但缺少创建订单用户的相关信息。这是网上支付流程中存在的一个重大设计缺陷。
找到一个唯一的客户端信息,贯穿于整个网上支付流程的所有平台,保证订单是由订单创建者本人支付的。
根据用户的需求,可能还会产生“代付业务”,这时候还需要设计一个合法的代付流程。只有当所有平台都统一了订单拥有者的信息后,才能真正解决这个问题。目前看来,使用客户端IP地址作为这个信息,比较经济,易于推广。
16.6 用户隐私保护
16.6.1 互联网的用户隐私挑战
PCI认为现有的安全技术是复杂的,要想完美地保护好用户个人信息比较困难,最好的做法是限制数据的使用——“不存在的数据是最安全的”。
对隐私数据进行标准化的定义,也是一件很困难的事情——业务场景太复杂了。
16.6.2 如何保护用户隐私
曾经有人怀疑Google偷看用户的邮件内容,因为Gmail里的广告总是能够伴随着邮件的内容而精准投放。Gmail实际上是使用了算法实现这一切,但这给我们提了个醒:网站不应该有个人能够接触到用户的隐私数据。
16.6.3 Do-Not-Track
Do-Not-Track工作在浏览器上。该选项打开后,将在HTTP头中增加一个header,用以告诉网站用户不想被追踪。最初由美国政府权威机构联邦贸易委员会(Federal Trade Commission)发布,其灵感来自于阻止电话推销的“全美不接受电话推销名单”(do-not-call registry)。
16.7 小结
其实漏洞跟风险还有一定距离。漏洞首先要有人使用,然后才会成为风险。
还有就是刷等级,可能存在一些用户行为,可以把低等级会员刷成高等级会员。还有领红包,我们给团队一些推广费用,希望给用户回报,但是没有一个有效措施保障这些回报落到有效客户手里,大部分推广费用落到了垃圾注册的口袋,最终可能只有一个团伙在收钱。
我们有一套专门的解决方案,通过用户行为分析,判断到底是人还是机器,这套系统的准确率已经达到99.999%,在10万个分析里面有一个误报,这是我们目前的现状。
第17章 安全开发流程(SDL)
17.1 SDL简介
SDL的全称是Security Development Lifecycle,即:安全开发生命周期。
它是由微软最早提出的,在软件工程中实施,是帮助解决软件安全问题的办法。
SDL一直都是微软在全公司实施的强制性策略。SDL的大致步骤如下:
而美国国家标准与技术研究所(NIST)估计,如果是在项目发布后再执行漏洞修复计划,其修复成本相当于在设计阶段执行修复的30倍。
17.2 敏捷SDL
微软为敏捷开发专门设计了敏捷SDL。
17.3 SDL实战经验
准则一:与项目经理进行充分沟通,排出足够的时间。
一个项目的安全评估,在开发的不同环节有着不同的安全要求,而这些安全要求都需要占用开发团队的时间。因此在立项阶段与项目经理进行充分沟通是非常有必要的。
准则二:规范公司的立项流程,确保所有项目都能通知到安全团队,避免遗漏。
在公司规模较小时,员工沟通成本较低,很容易做到这件事情。但当公司大到一定的规模时,出现多个部门与多个项目组,沟通成本就大大增加。在这种情况下,从公司层面建立一个完善的“立项制度”,就变得非常有必要了。
SDL是依托于软件工程的,立项也属于软件工程的一部分。如果能集中管理立项过程,SDL就有可能在这一阶段覆盖到公司的所有项目。相对于测试阶段和发布阶段来说,在立项阶段就有安全团队介入,留给开发团队的反应时间也更加富足。
准则三:树立安全部门的权威,项目必须由安全部门审核完成后才能发布。
必须通过规范和制度,明确要求所有项目必须在安全审核完成后才能发布。如果没有这样的权威,对于项目组来说,安全就变成了一项可有可无的东西。而如果产品急着发布,很可能因此砍掉或者裁减部分安全需求,也可能延期修补漏洞,从而导致风险升高。
准则四:将技术方案写入开发、测试的工作手册中。
直接将安全技术方案写入开发者的代码规范中。比如规定好哪些函数是要求禁用的,只能使用哪些函数;或者封装好一些安全功能,在代码规范中注明在什么情况下使用什么样的安全API。
准则五:给工程师培训安全方案。
在微软的SDL框架中,第一项就是培训。培训的作用不可小视,它是技术方案与执行者之间的调和剂。
准则六:记录所有的安全bug,激励程序员编写安全的代码。
为了更好地推动项目组写出安全的代码,可以尝试给每个开发团队设立绩效。被发现漏洞最少的团队可以得到奖励,并将结果公布出来。如此,项目组之间将产生一些竞争的氛围,开发者们将更努力于遵守安全规范,写出安全的代码。此举还能帮助不断提高开发者的代码质量,形成良性循环。
17.4 需求分析与设计阶段
在需求阶段,安全工程师需要关心产品主要功能上的安全强度和安全体验是否足够,主要需要思考安全功能。
需要注意的是,在安全领域中,“安全功能”与“安全的功能”是两个不同的概念。“安全功能”是指产品本身提供给用户的安全功能,比如数字证书、密码取回问题等功能。
而“安全的功能”,则指在产品具体功能的实现上要做到安全,不要出现漏洞而被黑客利用。
在需求分析阶段,可以对项目经理、产品经理或架构师进行访谈,以了解产品背景和技术架构,并给出相应的建议。从以往的经验来看,一份checklist可以在一定程度上帮助到我们。
BUSINESS REQUIREMENTS
Business Model
What is the application's primary business purpose?
How will the application make money?
What are the planned business milestones for developing or improving the application?
How is the application marketed?
What key benefits does the application offer users?
What business continuity provisions have been defined for the application?
What geographic areas does the application service?
Data Essentials
What data does the application receive, produce, and process?
How can the data be classified into categories according to its sensitivity?
How might an attacker benefit from capturing or modifying the data?
What data backup and retention requirements have been defined for the application?
End-Users
Who are the application's end-users?
How do the end-users interact with the application?
What security expectations do the end-users have?
Partners
Which third-parties supply data to the application?
Which third-parties receive data from the applications?
Which third-parties process the application's data?
What mechanisms are used to share data with third-parties besides the application itself?
What security requirements do the partners impose?
Administrators
Who has administrative capabilities in the application?
What administrative capabilities does the application offer?
Regulations
In what industries does the application operate?
What security-related regulations apply?
What auditing and compliance regulations apply?
INRASTRUCTURE REQUIREMENTS
Network
What details regarding routing, switching, firewalling, and load-balancing have been defined?
What network design supports the application?
What core network devices support the application?
What network performance requirements exist?
What private and public network links support the application?
Systems
What operating systems support the application?
What hardware requirements have been defined?
What details regarding required OS components and lock-down needs have been defined?
Infrastructure Monitoring
What network and system performance monitoring requirements have been defined?
What mechanisms exist to detect malicious code or compromised application components?
What network and system security monitoring requirements have been defined?
Virtualization and Externalization
What aspects of the application lend themselves to virtualization?
What virtualization requirements have been defined for the application?
What aspects of the product may or may not be hosted via the cloud computing model?
APPLICATION REQUIREMENTS
Environment
What frameworks and programming languages have been used to create the application?
What process, code, or infrastructure dependencies have been defined for the application?
What databases and application servers support the application?
Data Processing
What data entry paths does the application support?
What data output paths does the application support?
How does data flow across the application's internal components?
What data input validation requirements have been defined?
What data does the application store and how?
What data is or may need to be encrypted and what key management requirements have been defined?
What capabilities exist to detect the leakage of sensitive data?
What encryption requirements have been defined for data in transit over WAN and LAN links?
Access
What user identification and authentication requirements have been defined?
What session management requirements have been defined?
What access requirements have been defined for URI and Service calls?
What user authorization requirements have been defined?
How are user identities maintained throughout transaction calls?
What user access restrictions have been defined?
What user privilege levels does the application support?
Application Monitoring
What application performance monitoring requirements have been defined?
What application security monitoring requirements have been defined?
What application error handling and logging requirements have been defined?
How are audit and debug logs accessed, stored, and secured?
What application auditing requirements have been defined?
Application Design
How many logical tiers group the application's components?
How is intermediate or in process data stored in the application components' memory and in cache?
What application design review practices have been defined and executed?
What staging, testing, and Quality Assurance requirements have been defined?
SECURITY PROGRAM REQUIREMENTS
Operations
What access to system and network administrators have to the application's sensitive data?
What security incident requirements have been defined?
What physical controls restrict access to the application's components and data?
What is the process for granting access to the environment hosting the application?
What is the process for identifying and addressing vulnerabilities in network and system components?
How do administrators access production infrastructure to manage it?
What is the process for identifying and addressing vulnerabilities in the application?
Change Management
What mechanisms exist to detect violations of change management practices?
How are changes to the infrastructure controlled?
How are changes to the code controlled?
How is code deployed to production?
Software Development
How do developers assist with troubleshooting and debugging the application?
What requirements have been defined for controlling access to the applications source code?
What data is available to developers for testing?
What secure coding processes have been established?
Corporate
Which personnel oversees security processes and requirements related to the application?
What employee initiation and termination procedures have been defined?
What controls exist to protect a compromised in the corporate environment from affecting production?
What security governance requirements have been defined?
What security training do developers and administrators undergo?
What application requirements impose the need to enforce the principle of separation of duties?
What corporate security program requirements have been defined?
很多时候,入侵是从第三方软件开始的。如果评估后发现第三方软件存在风险,则应该替换它,或者使用其他方式来规避这种风险。
一个最佳实践是给公司拥有的数据定级,对不同级别的数据定义不同的保护方式,将安全方案模块化。这样在review项目的需求和设计时,根据项目涉及的数据敏感程度,可以套用不同的等级化保护标准。
17.5 开发阶段
依据“安全是为业务服务”这一指导思想,在需求层面,安全改变业务的地方较少,因此应当力求代码实现上的安全,也就是做到“安全的功能”。
17.5.1 提供安全的函数
OWASP的开源项目OWASP ESAPI也为安全模块的实现提供了参考。如果开发者没有把握实现一个足够好的安全模块,则最好是参考OWASP ESAPI的实现方式。
微软在面对同样问题时,为开发者提供了安全函数库:
在代码审核阶段,可以通过白盒扫描的方式检查变量输出是否使用了安全的函数,没有使用安全函数的可以认为不符合安全规范。这个过程也可以由开发者自检。
将安全方案写入开发规范中,就真正地让安全方案落了地。这样不仅仅是为了方便开发者写出安全的代码,同时也为代码安全审计带来了方便。
17.5.2 代码安全审计工具
代码自动化审计工具的另外一种思路是,找到所有可能的用户输入入口,然后跟踪变量的传递情况,看变量最后是否会走到危险函数(如eval())。这种思路比回溯函数调用过程要容易实现,但仍然会存在较多的误报。
对于甲方公司来说,完全可以根据开发规范来定制代码审计工具。其核心思想是,并非直接检查代码是否安全,而是检查开发者是否遵守了开发规范。
这样就把复杂的“代码自动化审计”这一难题,转化为“代码是否符合开发规范”的问题。而开发规范在编写时就可以写成易于审计的一种规范。最终,如果开发规范中的安全方案没有问题的话,当开发者严格遵守开发规范时,产出的代码就应该是安全的。
这些经验对于以Web开发为主的互联网公司来说,具有高度的可操作性。
17.6 测试阶段
测试阶段是产品发布前的最后一个阶段,在此阶段需要对产品进行充分的安全测试,验证需求分析、设计阶段的安全功能是否符合预期目标,并验证在开发阶段发现的所有安全问题是否得到解决。
安全测试,一般分为自动化测试和手动测试两种方式。
自动化测试以覆盖性的测试为目的,可以通过“Web安全扫描器”对项目或产品进行漏洞扫描。
常见的Web安全扫描器效果对比
Google的skipfish扫描结果页面
安全测试完成以后,需要生成一份安全测试报告。这份报告并不是扫描器的扫描报告。扫描报告可能会存在误报与漏报,因此扫描报告需要经过安全工程师的最终确认。确认后的扫描报告,结合手动测试的结果,最终形成一份安全测试报告。
安全测试报告中提到的问题,需要交给开发工程师进行修复。漏洞修补完成后,再迭代进行安全测试,以验证漏洞的修补情况。由此可见,在项目初期与项目经理进行充分沟通,预留出代码审计、安全测试的时间,是一件很重要的事情。
17.7 小结
实施SDL(安全开发流程)。SDL是建立在公司软件工程基础之上的,公司的软件工程实施越规范,SDL就越容易实施,反之则难度越大。
互联网公司不同于传统软件公司,它更注重产品的快捷与时效性,因此在产品开发的路线上大多选择敏捷开发,这也给SDL的实施带来了一定的难度。
SDL需要从上往下推动,归根结底,它仍然是“人”的问题。实施SDL一定要得到公司技术负责人与产品负责人的全力支持,并通过完善软件发布流程、工程师的工作手册来达到目的。SDL实施的成功与否,与来自高级管理层的支持力度有很大关系。
第18章 安全运营
俗话说,安全是“三分技术,七分管理”。安全对于企业来说,结果才是最重要的。安全方案设计完成后,即使看起来再美好,也需要经受实践的检验。
在“我的安全世界观”一章中曾经提到,安全是一个持续的过程。而“安全运营”的目的,就是把这个“持续的过程”执行起来。健康的企业安全,需要依靠“安全运营”来保持新陈代谢,保持活力。
18.1 把安全运营起来
互联网公司如何规划自己的安全蓝图呢?从战略层面上来说,Aberdeen Group提到了三句话:Find and Fix, Defend and Defer, Secure at the Source。
一个安全评估的过程,就是一个“Find and Fix” 的过程。通过漏洞扫描、渗透测试、代码审计等方式,可以发现系统中已知的安全问题;然后再通过设计安全方案,实施安全方案,最终解决这些问题。
而像入侵检测系统、Web应用防火墙,反DDOS设备等则是一些防御性的工作,这也是保证安全必不可少的一个部分。它们能防范问题于未然,或者当安全事件发生后,快速地响应和处理问题。这些防御性的工作,是一个“Defend and Defer”的过程。
最后“Secure at the Source”指的则是“安全开发流程(SDL)”,它能从源头降低安全风险,提高产品的安全质量。
在安全运营的过程中,必然会与各种安全产品、安全工具打交道。有的安全产品是商业产品,有的则是开源工具,甚至安全团队还需要自主研发一些安全工具,这些安全产品都会产生大量的日志,这些日志对于安全运营来说是非常有价值的。通过事件之间的关联,可以全面地分析出企业的安全现状,并对未来的安全趋势做出一些预警,为决策提供参考意见。
将各种安全日志、安全事件关联起来的系统我们称之为SOC(Security Operation Center)。建立SOC可以算是安全运营的一个重要目标。
18.2 漏洞修补流程
建立漏洞修补流程,是在“Fix”阶段要做的第一件事情。当公司规模不大时,沟通成本较低,可以通过口口相传的方式快速解决问题;但当公司规模大了以后,沟通成本随之上升,相应的漏洞修补速度会降低,而只靠沟通还可能会出现一些错漏,所以建立一个“漏洞修补流程”以保证漏洞修补的进度和质量是非常有必要的。
目前许多大的开源项目也是如此处理安全漏洞的,在bug中会定义类型为security,同时还定义了bug的紧急程度。
对于“安全运营”的工作来说,建立漏洞修补流程,意味着需要完成这几件事情:
建立类似bugtracker的漏洞跟踪机制,并为漏洞的紧急程度选择优先级;
建立漏洞分析机制,并与程序员一起制定修补方案,同时review补丁的代码实现;
对曾经出现的漏洞进行归档,并定期统计漏洞修补情况。
18.3 安全监控
对于互联网公司来说,由于其业务的高度连续性,所以监控网络、系统、应用的健康程度是一件非常重要的事情。监控能使公司在发生任何异常时第一时间就做出反应。
安全监控就像是一双眼睛,能够时刻捕捉到发生的异常情况。
18.4 入侵检测
常见的安全监控产品有IDS(入侵检测系统)、IPS(入侵防御系统)、DDOS监控设备等。在IDS这个大家族中,Web应用防火墙(简称WAF)又是近年来兴起的一种产品。
ModSecurity是Apache的一个Module,它能获取到所有访问Apache Httpd Server的请求,并根据自己的规则对这些请求进行匹配,以检测哪些请求存在攻击行为。
ModSecurity的规则几乎囊括了所有的Web攻击行为,其核心规则由社区的安全专家维护。
但是在实际使用IDS产品时,需要根据具体情况调整规则,避免误报。规则的优化是一个相对较长的过程,需要经过实践的检验。因此IDS在很多时候仅仅是报警,而不会由程序直接处理报告的攻击。人工处理报警,会带来运营成本的提升。
除了部署入侵检测产品外,在应用中也可以实现代码级的安全监控功能。比如在实施CSRF方案时,采取的办法是对比用户提交表单中的token与当前用户Session中的token是否一致。当比对失败时,可以由应用记录下当前请求的IP地址、时间、URL、用户名等相关信息。这些安全日志汇总后,可以酌情发出安全警报。
在应用代码中输出安全日志,需要执行IO的写操作,对性能会有一些影响。在设计方案时,要考虑到这种写日志的动作是否会频繁发生。在正常情况下,应用也会频繁地执行写日志的动作,那么这个日志并不适合启用。安全日志也属于机密信息,应该实时地保存到远程服务器。
18.5 紧急响应流程
入侵检测系统或其他安全监控产品的规则被触发时,根据攻击的严重程度,最终会产生“事件”(Event)或“报警”(Alert),报警是一种主动通知管理员的提醒方式。常见的报警方式有三种。
邮件报警
IM报警
短信报警
监控与报警都建立后,就可以开始着手制定“紧急响应流程”了。紧急响应流程是在发生紧急安全事件时,需要启动的一个用于快速处理事件的流程。很多时候由于缺乏紧急响应流程,或者紧急响应流程执行不到位,使得一些本来可以快速平息的安全事件,最终造成巨大的损失。
建立紧急响应流程,首先要建立“紧急响应小组”,这个小组全权负责对紧急安全事件的处理、资源协调工作。小组成员需要包括:
技术负责人
产品负责人
最了解技术架构的资深开发工程师
资深网络工程师
资深系统运维工程师
资深DBA
资深安全专家
监控工程师
公司公关
小组成员中包含公司公关,是因为遇到一些影响较大的安全事件时,需要公关发对外的新闻稿。由于公关一般不太了解技术,因此公司公关对外发的新闻稿需要参考安全专家的意见,以免出现言辞不当的情况。
在处理安全问题时,有两个需要注意的地方。
一是需要保护安全事件的现场。
二是以最快的速度处理完问题。
18.6 小结
公司安全的发展蓝图可以分为“Find and Fix”、“Defend and Defer”、“Secure at the Source”三个方向,每一个方向的最终结果都需要由“安全运营”来保证。
安全运营实施的好坏,将决定公司安全是否能健康地发展。只有把安全运营起来,在变化中对抗攻击,才能真正让安全成为一个持续的过程,才能走在正确的道路上。
(附)谈谈互联网企业安全的发展方向
讨论范围限定在互联网公司,是为了避免和一些安全公司打口水战。我一向认为互联网公司的安全做到极致后,是不太需要购买安全软件或解决方案的,因为一个大的互联网公司发展到一定程度后,其规模和复杂程度决定了世界上没有哪一家安全公司能够提供这样的解决方案,一切都得自力更生。当然这句话也不是绝对的,一些非关键领域或者基础安全领域还是需要安全厂商的支持,比如防火墙设备、桌面安全设备、防DDOS设备等。
但我今天要说的是互联网公司安全的方向。我的命题是:我们今天做了什么,做得够不够,接下来我们还需要做些什么?
在过去的很长时间内,无论是漏洞挖掘者还是安全专家们,都在致力于研究各种各样的漏洞,以此为代表的是OWASP每隔几年就会公布的Top 10威胁List。所以在很长一段时间内,互联网公司的安全专家们,包括安全厂商的产品专家们,都在致力于做一件事情:不管是产品还是方案,尽可能地消灭这些漏洞。
因此,我把互联网公司安全的第一个目标,定义为:让工程师写出的每一行代码都是安全的!
这第一个目标应该理解为互联网公司的产品安全。一个以产品(包括网站、在线服务等,在互联网公司里在线服务也被称为产品)驱动的公司,要做安全,第一件事情必然是要保证核心业务的健康发展。为了达到这个目标,微软有了SDL,基于对软件工程的改造,SDL可以帮助工程师编写出安全的代码。微软的SDL达成了“让微软的工程师写出的大部分代码都是安全的”这一目标。所以我认为SDL是伟大的创造,它在无限接近终极目标。
在这个SDL中,我们就有很多东西需要去完善,也促进了相当多的衍生技术研究和技术产品。比如代码安全扫描工具的研究,仅此一项,就涉及语法分析、词法分析、数据关联、统计学等诸多问题;再比如fuzzing,则涉及各类协议或文件格式、统计学、数据处理、调试与回溯、可重用的测试环境建设等诸多复杂问题。把每一项做精,都不是件容易的事情。
所以SDL是一项需要长期坚持和不断完善的工作。但是光有这个还无法100%保证不会出现安全问题,于是我定义了互联网公司安全的第二个目标:让所有已知的、未知的攻击,都能在第一时间发现,并迅速报警和追踪。
这第二个目标也挺宏伟的,涉及许多IDS、IPS、蜜罐方面的研究,但光有现有的这些技术,还是远远无法完成这个目标的,因为现在已有的商业的、开源的IDS及IPS都存在着种种局限性,而互联网公司的海量数据和复杂需求,也对这些现有产品提出了严峻的挑战。只有借助大规模超强的计算能力,实施有效的数据挖掘和数据关联工作,或者建立更加立体化的模型,才能逐渐逼近这一目标。
这个目标也是需要无限逼近去完成的一个宏伟目标。我目前在公司做的部分事情,就是在向着这个目标努力,所以无法在这里详谈、深谈。
光前面两个目标,就不知道需要投入多少人力、时间来努力,但我还有点不满足,所以我定义了第三个目标:让安全成为公司的核心竞争力,深入到每一个产品的特性中,能够更好地引导用户使用互联网的习惯。
在一开始,我们使用电脑时,是不需要安装任何杀毒软件的。但是到了今天,如果一个普通用户新买了电脑,却没有安装任何的杀毒软件或者桌面保护软件,那么大家都会担心他会不会中病毒或木马。这种需求和市场,就完全是病毒和杀毒软件厂商培养和熏陶出来的。所以在今天,很多电脑生产商甚至在电脑出厂时就会预装一个杀毒软件。
前两天我去超市,看到乐事的薯片捆绑销售一盒小的番茄酱。我马上想到了肯德基和麦当劳,我不知道在它们之前是否还有别的速食品是把薯条和番茄酱配在一起销售的,但是我认为肯德基和麦当劳改变了人们吃薯条的习惯:是要蘸着番茄酱吃的。所以乐事的薯片捆绑销售番茄酱,也可以看做是被肯德基做出来的需求和市场。
所以,我认为做互联网公司安全需要达成的一个目标是让安全成为深深植入产品骨髓的一个功能和特性,引导用户使用互联网的习惯,把这个需求和市场做出来。这更是一件需要长期投入和坚持的事情。
我还有最后一个目标:能够观测到整个互联网安全趋势的变化,对未来一段时间内的风险做出预警。
这个预警的目标也是我们部门当初草创时的目标之一,我至今还没有很好的头绪来想这些问题。但是这个目标反而是今天列举的这些目标中最容易达到的一个,因为已经有公司在做了,而且比较成功。比如McAfee和赛门铁克每隔一段时间都会有互联网威胁报告,国外一些组织比如SANS等也有类似的报告。腾讯这几年一直在做挂马检测方面的工作,所以他们也能在一定程度上预警挂马方面的趋势。
由于有前人的榜样,再借助大规模的客户端或者是强力搜索引擎的海量数据,要做这件事情的路线和方法还是非常清晰的,只是要想做好,还得花上很多的时间和精力。
安全技术一直是依附于技术发展的,不光是技术发展开辟了新的需要安全的领域,技术发展也能给安全技术带来更多的想象空间。
比如10年前,甚至是5年前,可能我们都不需要去想手机是否需要安全这件事情。但是在今天,手机安全已经成为刻不容缓的一个战场,比如前两天报道的在澳洲传播的iPhone蠕虫,这些已经是实实在在的威胁。
而手机安全反过来也促进了一些新的安全技术,比如手机认证能够起到与客户端证书类似的作用,甚至比客户端证书更进一步,因为手机不是装在电脑上的,而是放在用户的裤兜里的。类似的还有随着计算能力的提升,已经能够处理更大规模的数据,从而使得安全分析会有一些新的发展和变化,这些都是在过去不敢想象的。
在互联网公司做安全一定要有想象力,同时需要紧密关注其他技术领域的发展,这样就不会止步于几种漏洞的研究,而会发现有非常多的有趣的事情正等着去做,这是一个非常宏伟的蓝图。
序言
安全是一个动态的过程,因为敌方攻击手段在变,攻击方法在变,漏洞不断出现;我方业务在变,软件在变,人员在变,妄图通过一个系统、一个方案解决所有的问题是不现实的,也是不可能的,安全需要不断地运营、持续地优化。
前言
加入的过程颇具传奇色彩,在面试的过程中主管要求我展示自己的能力,于是我远程关闭了阿里巴巴内网上游运营商的一台路由设备,导致阿里巴巴内部网络中断。
第一篇 世界观安全
第1章 我的安全世界观
互联网本来是安全的,自从有了研究安全的人之后,互联网就变得不安全了。
1.1 Web安全简史
不想拿到“root”的黑客,不是好黑客。
黑客们使用的漏洞利用代码,被称为“exploit”
只懂得编译别人的代码,自己并没有动手能力,这种黑客被称为“Script Kids”,即“脚本小子”。
而在今天已经形成产业的计算机犯罪、网络犯罪中,造成主要破坏的,也是这些“脚本小子”。
1.1.1 中国黑客简史
此时期的黑客群体因为互相之间缺失信任已经不再具有开放和分享的精神,最为纯粹的黑客精神实质上已经死亡。
1.1.2 黑客技术的发展历程
运营商、防火墙对于网络的封锁,使得暴露在互联网上的非Web服务越来越少,且Web技术的成熟使得Web应用的功能越来越强大,最终成为了互联网的主流。黑客们的目光,也渐渐转移到了Web这块大蛋糕上。
1.1.3 Web安全的兴起
PHP语言至今仍然只能靠较好的代码规范来保证没有文件包含漏洞,而无法从语言本身杜绝此类安全问题的发生。
SQL注入的出现是Web安全史上的一个里程碑。
XSS(跨站脚本攻击)的出现则是Web安全史上的另一个里程碑。
1.2 黑帽子,白帽子
“破坏永远比建设容易”,但凡事都不是绝对的。
白帽子选择的方法,是克服某种攻击方法,而并非抵御单次的攻击。
1.3 返璞归真,揭秘安全的本质
安全检查的过程按照需要进行过滤
被划分出来的具有不同信任级别的区域,我们称为信任域,划分两个不同信任域之间的边界,我们称为信任边界。
数据从高等级的信任域流向低等级的信任域,是不需要经过安全检查的;数据从低等级的信任域流向高等级的信任域,则需要经过信任边界的安全检查。
安全问题的本质是信任的问题。
假设我们有份很重要的文件要好好保管起来,能想到的一个方案是把文件“锁”到抽屉里。这里就包含了几个基本的假设,首先,制作这把锁的工匠是可以信任的,他没有私自藏一把钥匙;其次,制作抽屉的工匠没有私自给抽屉装一个后门;最后,钥匙还必须要保管在一个不会出问题的地方,或者交给值得信任的人保管。反之,如果我们一切都不信任,那么也就不可能认为文件放在抽屉里是安全的。
因为极端的条件往往意味者小概率以及高成本,因此在成本有限的情况下,我们往往会根据成本来设计安全方案,并将一些可能性较大的条件作为决策的主要依据。
把握住信任条件的度,使其恰到好处,正是设计安全方案的难点所在,也是安全这门学问的艺术魅力所在。
1.4 破除迷信,没有银弹
安全是一个持续的过程。
1.5 安全三要素
安全三要素,简称CIA
安全三要素是安全的基本组成元素,分别是机密性(Confidentiality)、完整性(Integrity)、可用性(Availability)。
1.6 如何实施安全评估
安全评估的过程
1.6.1 资产等级划分
简单网站信任模型
1.6.2 威胁分析
在安全领域里,我们把可能造成危害的来源称为威胁(Threat),而把可能会出现的损失称为风险(Risk)
STRIDE是6个单词的首字母缩写,我们在分析威胁时,可以从以下6个方面去考虑。
1.6.3 风险分析
DREAD也是几个单词的首字母缩写,它指导我们应该从哪些方面去判断一个威胁的风险程度。
1.6.4 设计安全方案
好的安全方案对用户应该是透明的,尽可能地不要改变用户的使用习惯。
最终,一个优秀的安全方案应该具备以下特点:
能够有效解决问题;
用户体验好;
高性能;
低耦合;
易于扩展与升级。
1.7 白帽子兵法
1.7.1 Secure By Default原则
实际上,“Secure by Default”原则,也可以归纳为白名单、黑名单的思想。如果更多地使用白名单,那么系统就会变得更安全。
1.7.1.1 黑名单、白名单
所以在选择使用白名单时,需要注意避免出现类似通配符“*”的问题。
1.7.1.2 最小权限原则
Secure By Default的另一层含义就是“最小权限原则”。
1.7.2 纵深防御原则
Defense in Depth(纵深防御)也是设计安全方案时的重要指导思想。
就入侵的防御来说,我们需要考虑的可能有Web应用安全、OS系统安全、数据库安全、网络环境安全等。在这些不同层面设计的安全方案,将共同组成整个防御体系,这也就是纵深防御的思想。
纵深防御的第二层含义,是要在正确的地方做正确的事情
XSS防御技术的发展过程
1.7.3 数据与代码分离原则
浏览器将用户数据里的<script>标签当做代码来解释——这显然不是程序开发者的本意。
1.7.4 不可预测性原则
提高了攻击的门槛
1.8 小结
安全是一门朴素的学问,也是一种平衡的艺术。
(附)谁来为漏洞买单?
我们定义一个功能是否是漏洞,只看后果,而不应该看过程。
一个业务安全设计得好的网站,往往loginID和nickname(昵称)是分开的。登录ID是用户的私有信息,只有用户本人能够看到;而nickname不能用于登录,但可以公开给所有人看。这种设计的细节,是网站积极防御的一种表现。
在未来互联网发展的过程中,也必然会有更多、更古怪的攻击方式出现,也必然会让更多的原本是“功能”的东西,变成漏洞。
第二篇 客户端脚本安全
第2章 浏览器安全
浏览器才是互联网最大的入口,绝大多数用户使用互联网的工具是浏览器。
2.1 同源策略
同源策略(Same Origin Policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略的基础之上的,浏览器只是针对同源策略的一种实现。
浏览器的同源策略,限制了来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。
对于JavaScript来说,以下情况被认为是同源与不同源的。
在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以跨域加载资源,而不受同源策略的限制。这些带“src”属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。
XMLHttpRequest受到同源策略的约束,不能跨域访问资源,在AJAX应用的开发中尤其需要注意这一点。
W3C委员会制定了XMLHttpRequest跨域访问标准。它需要通过目标域返回的HTTP头来授权是否允许跨域访问,因为HTTP头对于JavaScript来说一般是无法控制的,所以认为这个方案可以实施。
同源策略一旦出现漏洞被绕过,也将带来非常严重的后果,很多基于同源策略制定的安全方案都将失去效果。
2.2 浏览器沙箱
这种在网页中插入一段恶意代码,利用浏览器漏洞执行任意代码的攻击方式,在黑客圈子里被形象地称为“挂马”。
Google Chrome是第一个采取多进程架构的浏览器。Google Chrome的主要进程分为:浏览器进程、渲染进程、插件进程、扩展进程。插件进程如flash、java、pdf等与浏览器进程严格隔离,因此不会互相影响。
渲染引擎由Sandbox隔离,网页代码要与浏览器内核进程通信、与操作系统通信都需要通过IPC channel,在其中会进行一些安全检查。
Google Chrome的Sandbox架构
IE 8的架构
多进程架构最明显的一个好处是,相对于单进程浏览器,在发生崩溃时,多进程浏览器只会崩溃当前的Tab页,而单进程浏览器则会崩溃整个浏览器进程。这对于用户体验是很大的提升。
2.3 恶意网址拦截
Google也公开了其内部使用的SafeBrowsing API,任何组织或个人都可以在产品中接入,以获取Google的恶意网址库。
主流浏览器都开始支持EV SSL证书(Extended Validation SSL Certificate),以增强对安全网站的识别。
2.4 高速发展的浏览器安全
Firefox 4中推出了Content Security Policy(CSP)。这一策略是由安全专家Robert Hanson最早提出的,其做法是由服务器端返回一个HTTP头,并在其中描述页面应该遵守的安全策略。
2.5 小结
浏览器的安全以同源策略为基础,加深理解同源策略,才能把握住浏览器安全的本质。
第3章 跨站脚本攻击(XSS)
3.1 XSS简介
跨站脚本攻击,英文全称是Cross Site Script,本来缩写是CSS,但是为了和层叠样式表(Cascading Style Sheet, CSS)有所区别,所以在安全领域叫做“XSS”。
XSS根据效果的不同可以分成如下几类。
第一种类型:反射型XSS
黑客往往需要诱使用户“点击”一个恶意链接,才能攻击成功。反射型XSS也叫做“非持久型XSS”(Non-persistent XSS)。
第二种类型:存储型XSS
存储型XSS会把用户输入的数据“存储”在服务器端。这种XSS具有很强的稳定性。
第三种类型:DOM Based XSS
通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
3.2 XSS攻击进阶
3.2.1 初探XSS PayIoad
XSS攻击成功后,攻击者能够对用户当前浏览的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器。这些用以完成各种具体功能的恶意脚本,被称为“XSS Payload”。
一个最常见的XSS Payload,就是通过读取浏览器的Cookie对象,从而发起“Cookie劫持”攻击。
Cookie中一般加密保存了当前用户的登录凭证。Cookie如果丢失,往往意味着用户的登录凭证丢失。换句话说,攻击者可以不通过密码,而直接登录进用户的账户。
Cookie的“HttpOnly”标识可以防止“Cookie劫持”
3.2.2 强大的XSS PayIoad
3.2.2.1 构造GET与POST请求
所以XSS攻击后,攻击者除了可以实施“Cookie劫持”外,还能够通过模拟GET、POST请求操作用户的浏览器。
3.2.2.2 XSS钓鱼
对于验证码,XSS Payload可以通过读取页面内容,将验证码的图片URL发送到远程服务器上来实施——攻击者可以在远程XSS后台接收当前验证码,并将验证码的值返回给当前的XSS Payload,从而绕过验证码。
3.2.2.3 识别用户浏览器
由于浏览器之间的实现存在差异——不同的浏览器会各自实现一些独特的功能,而同一个浏览器的不同版本之间也可能会有细微差别。所以通过分辨这些浏览器之间的差异,就能准确地判断出浏览器版本,而几乎不会误报。这种方法比读取UserAgent要准确得多。
3.2.2.4 识别用户安装的软件
扫描Firefox扩展时,只需在JavaScript中加载这张图片,如果加载成功,则扩展存在;反之,扩展不存在。
3.2.2.5 CSS History Hack
其原理是利用style的visited属性——如果用户曾经访问过某个链接,那么这个链接的颜色会变得与众不同。
Firefox在2010年3月底决定修补这个问题,因此,未来这种信息泄露的问题可能在Mozilla浏览器中不会再继续存在了。
3.2.2.6 获取用户的真实IP地址
很多时候,用户电脑使用了代理服务器,或者在局域网中隐藏在NAT后面。网站看到的客户端IP地址,是内网的出口IP地址,而并非用户电脑真实的本地IP地址。如何才能知道用户的本地IP地址呢?
JavaScript本身并没有提供获取本地IP地址的能力,有没有其他办法?一般来说,XSS攻击需要借助第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地IP地址。
3.2.3 XSS攻击平台
Attack API是安全研究者pdp所主导的一个项目,它总结了很多能够直接使用XSS Payload,归纳为API的方式。比如上节提到的“获取客户端本地信息的API”就出自这个项目。
BeEF曾经是最好的XSS演示平台。不同于Attack API, BeEF所演示的是一个完整的XSS攻击过程。BeEF有一个控制后台,攻击者可以在后台控制前端的一切。
XSS-Proxy是一个轻量级的XSS攻击平台,通过嵌套iframe的方式可以实时地远程控制被XSS攻击的浏览器。
XSS-Proxy的实现原理
3.2.4 终极武器:XSS Worm
3.2.4.1 Samy Worm
一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS Worm攻击。
相对的,如果一个页面只能由用户个人查看,比如“用户个人资料设置”页面,因为缺乏用户之间互动的功能,所以即使存在XSS,也不能被用于XSS Worm的传播。
3.2.4.2 百度空间蠕虫
真正可怕的蠕虫,是那些在无声无息地窃取用户数据、骗取密码的“恶意”蠕虫,这些蠕虫并不会干扰用户的正常使用,非常隐蔽。
3.2.5 调试JavaScript
3.2.6 XSS构造技巧
3.2.6.1 利用字符编码
“%c1\”组成了一个新的Unicode字符,“%c1”把转义符号“\”给“吃掉了”,从而绕过了系统的安全检查,成功实施了XSS攻击。
3.2.6.2 绕过长度限制
最常用的一个“藏代码”的地方,就是“location.hash”。而且根据HTTP协议,location.hash的内容不会在HTTP包中发送,所以服务器端的Web日志中并不会记录下location.hash里的内容,从而也更好地隐藏了黑客真实的意图。
3.2.6.3 使用<base>标签
<base>标签并不常用,它的作用是定义页面上的所有使用“相对路径”标签的hosting地址。
所以在设计XSS安全方案时,一定要过滤掉这个非常危险的标签。
3.2.6.4 window.name的妙用
对当前窗口的window.name对象赋值,没有特殊字符的限制。因为window对象是浏览器的窗体,而并非document对象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。
3.2.7 变废为宝:Mission ImpossibIe
3.2.7.1 Apache Expect Header XSS
注意到服务器在出错返回时,会把Expect头的内容未经任何处理便写入到页面中,因此Expect头中的HTML代码就被浏览器解析执行了。
3.2.7.2 Anehta的回旋镖
在IE中,<iframe>、<img>、<link>等标签都会拦截“第三方Cookie”的发送,而在Firefox中则无这种限制(第三方Cookie即指保存在本地的Cookie,也就是服务器设置了expire时间的Cookie)。
3.2.8 容易被忽视的角落:FIash XSS
由于Flash文件如此危险,所以在实现XSS Filter时,一般都会禁用<embed>、<object>等标签。后者甚至可以加载ActiveX控件,能够产生更为严重的后果。
3.2.9 真的高枕无忧吗:JavaScript开发框架
使用JavaScript框架并不能让开发者高枕无忧,同样可能存在安全问题。除了需要关注框架本身的安全外,开发者还要提高安全意识,理解并正确地使用开发框架。
3.3 XSS的防御
3.3.1 四两拨千斤:HttpOnIy
浏览器将禁止页面的JavaScript访问带有HttpOnly属性的Cookie。
3.3.2 输入检查
常见的Web漏洞如XSS、SQL Injection等,都要求攻击者构造一些特殊字符,这些特殊字符可能是正常用户不会用到的,所以输入检查就有存在的必要了。
3.3.3 输出检查
一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或转义的方式来防御XSS攻击。
3.3.3.1 安全的编码函数
JavascriptEncode与HtmlEncode的编码方法不同,它需要使用“\”对特殊字符进行转义。在对抗XSS时,还要求输出的变量必须在引号内部,以避免造成安全问题。比较下面两种写法:
3.3.3.2 只需一种编码吗
XSS攻击主要发生在MVC架构中的View层。大部分的XSS漏洞可以在模板系统中解决。
3.3.4 正确地防御XSS
XSS的本质还是一种“HTML注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。
想要根治XSS问题,可以列出所有XSS可能发生的场景,再一一解决。
3.3.5 处理富文本
在处理富文本时,还是要回到“输入检查”的思路上来。“输入检查”的主要问题是,在检查时还不知道变量的输出语境。
在标签的选择上,应该使用白名单,避免使用黑名单。比如,只允许 <a>、<img>、<div>等比较“安全”的标签存在。
3.3.6 防御DOM Based XSS
DOM based XSS的防御
以下几个地方是JavaScript输出到HTML页面的必经之路。
document.write()
document.writeln()
xxx.innerHTML =
xxx.outerHTML =
innerHTML.replace
document.attachEvent()
window.attachEvent()
document.location.replace()
document.location.assign()
需要重点关注这几个地方的参数是否可以被用户控制。
除了服务器端直接输出变量到JavaScript外,还有以下几个地方可能会成为DOM Based XSS的输入点,也需要重点关注。
页面中所有的inputs框
window.location(href、hash等)
document.referrer
document.cookie
localstorage
XMLHttpRequest返回的数据
3.3.7 换个角度看XSS的风险
在修补XSS漏洞时遇到的最大挑战之一是漏洞数量太多,因此开发者可能来不及,也不愿意修补这些漏洞。从业务风险的角度来重新定位每个XSS漏洞,就具有了重要的意义。
3.4 小结
XSS漏洞虽然复杂,但却是可以彻底解决的。在设计XSS解决方案时,应该深入理解XSS攻击的原理,针对不同的场景使用不同的方法。同时有很多开源项目为我们提供了参考。
第4章 跨站点请求伪造(CSRF)
CSRF的全名是Cross Site Request Forgery,翻译成中文就是跨站点请求伪造。
4.1 CSRF简介
回顾整个攻击过程,攻击者仅仅诱使用户访问了一个页面,就以该用户身份在第三方站点里执行了一次操作。
这个删除博客文章的请求,是攻击者所伪造的,所以这种攻击就叫做“跨站点请求伪造
4.2 CSRF进阶
4.2.1 浏览器的Cookie策略
攻击者伪造的请求之所以能够被搜狐服务器验证通过,是因为用户的浏览器成功发送了Cookie的缘故。
浏览器持有的cookie有两种类型:"会话cookie",也称为 "临时cookie",以及 "第三方cookie",也称为 "本地cookie"。Cookie",也被称为 "本地Cookie"。
Third-party Cookie是服务器在Set-Cookie时指定了Expire时间,只有到了Expire时间后Cookie才会失效,所以这种Cookie会保存在本地;而Session Cookie则没有指定Expire时间,所以浏览器关闭后,Session Cookie就失效了。
但若CSRF攻击的目标并不需要使用Cookie,则也不必顾虑浏览器的Cookie策略了。
4.2.2 P3P头的副作用
P3P Header是W3C制定的一项关于隐私的标准,全称是The Platform for Privacy Preferences。
如果网站返回给浏览器的HTTP头中包含有P3P头,则在某种程度上来说,将允许浏览器发送第三方Cookie。在IE下即使是<iframe>、<script>等标签也将不再拦截第三方Cookie的发送。
P3P头允许跨域访问隐私数据,从而可以跨域Set-Cookie成功。
正因为P3P头目前在网站的应用中被广泛应用,因此在CSRF的防御中不能依赖于浏览器对第三方Cookie的拦截策略,不能心存侥幸。
很多时候,如果测试CSRF时发现<iframe>等标签在IE中居然能发送Cookie,而又找不到原因,那么很可能就是因为P3P头在作怪。
4.2.3 GET? POST?
在CSRF攻击流行之初,曾经有一种错误的观点,认为CSRF攻击只能由GET请求发起。因此很多开发者都认为只要把重要的操作改成只允许POST请求,就能防止CSRF攻击。
这种错误的观点形成的原因主要在于,大多数CSRF攻击发起时,使用的HTML标签都是<img>、<iframe>、<script>等带“src”属性的标签,这类标签只能够发起一次GET请求,而不能发起POST请求。
4.2.4 FIash CSRF
除了URLRequest外,在Flash中还可以使用getURL, loadVars等方式发起请求。
4.2.5 CSRF Worm
即使没有XSS漏洞,仅仅依靠CSRF,也是能够发起大规模蠕虫攻击的。
4.3 CSRF的防御
4.3.1 验证码
CSRF攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码,则强制用户必须与应用进行交互,才能完成最终请求。因此在通常情况下,验证码能够很好地遏制CSRF攻击。
4.3.2 Referer Check
Referer Check在互联网中最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”。
比如一个“论坛发帖”的操作,在正常情况下需要先登录到用户后台,或者访问有发帖功能的页面。在提交“发帖”的表单时,Referer的值必然是发帖表单所在的页面。如果Referer的值不是这个页面,甚至不是发帖网站的域,则极有可能是CSRF攻击。
4.3.3 Anti CSRF Token
4.3.3.1 CSRF的本质
CSRF为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜测到的。
4.3.3.2 Token的使用原则
因此在使用Token时,应该尽量把Token放在表单中。把敏感操作由GET改为POST,以form表单(或者AJAX)的形式提交,可以避免Token泄露。
CSRF的Token仅仅用于对抗CSRF攻击,当网站还同时存在XSS漏洞时,这个方案就会变得无效,因为XSS可以模拟客户端浏览器执行任意操作。在XSS攻击下,攻击者完全可以请求页面后,读出页面内容里的Token值,然后再构造出一个合法的请求。这个过程可以称之为XSRF,和CSRF以示区分。
4.4 小结
CSRF攻击是攻击者利用用户的身份操作用户账户的一种攻击方式。设计CSRF的防御方案必须先理解CSRF攻击的原理和本质。
根据“不可预测性原则”,我们通常使用Anti CSRF Token来防御CSRF攻击。在使用Token时,要注意Token的保密性和随机性。
第5章 点击劫持(ClickJacking)
5.1 什么是点击劫持
点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。
5.2 Flash点击劫持
攻击者制作了一个Flash游戏,并诱使用户来玩这个游戏。这个游戏就是让用户去点击“CLICK”按钮,每次点击后这个按钮的位置都会发生变化。
Flash上隐藏的iframe窗口
某些点击是有意义的
5.3 图片覆盖攻击
一名叫sven.vetsch的安全研究者最先提出了这种Cross Site Image Overlaying攻击,简称XSIO。sven.vetsch通过调整图片的style使得图片能够覆盖在他所指定的任意位置。
5.4 拖拽劫持与数据窃取
“拖拽劫持”的思路是诱使用户从隐藏的不可见iframe中“拖拽”出攻击者希望得到的数据,然后放到攻击者能控制的另外一个页面中,从而窃取数据。
5.5 ClickJacking 3.0:触屏劫持
手机上的屏幕范围有限,手机浏览器为了节约空间,甚至隐藏了地址栏,因此手机上的视觉欺骗可能会变得更加容易实施。
5.6 防御ClickJacking
5.6.1 frame busting
通常可以写一段JavaScript代码,以禁止iframe的嵌套。这种方法叫frame busting。
5.6.2 X-Frame-Options
X-Frame-Options可以说是为了解决ClickJacking而生的,当值为DENY时,浏览器会拒绝当前页面加载任何frame页面;若值为SAMEORIGIN,则frame页面的地址只能为同源域名下的页面;若值为ALLOW-FROM,则可以定义允许frame加载的页面地址。
5.7 小结
ClickJacking相对于XSS与CSRF来说,因为需要诱使用户与页面产生交互行为,因此实施攻击的成本更高,在网络犯罪中比较少见。
第6章 HTML 5安全
6.1 HTML 5新标签
6.1.1 新标签的XSS
HTML 5中新增的 <video>标签,这个标签可以在网页中远程加载一段视频。与<video>标签类似的还有<audio>标签,用于远程加载一段音频。
6.1.2 iframe的sandbox
<iframe>标签一直以来都为人所诟病。挂马、XSS、ClickJacking等攻击中都能看到它不光彩的身影。
在HTML 5中,专门为iframe定义了一个新的属性,叫sandbox。使用sandbox这一个属性后,<iframe>标签加载的内容将被视为一个独立的“源”(源的概念请参考“同源策略”),其中的脚本将被禁止执行,表单被禁止提交,插件被禁止加载,指向其他浏览对象的链接也会被禁止。
sandbox属性可以通过参数来支持更精确的控制。有以下几个值可以选择:
allow-same-origin:允许同源访问;
allow-top-navigation:允许访问顶层窗口;
allow-forms:允许提交表单;
allow-scripts:允许执行脚本。
6.1.3 Link Types: noreferrer
在HTML 5中为<a>标签和<area>标签定义了一个新的Link Types:noreferrer。
顾名思义,标签指定了noreferrer后,浏览器在请求该标签指定的地址时将不再发送Referer。
6.1.4 Canvas的妙用
<canvas>标签让JavaScript可以在页面中直接操作图片对象,也可以直接操作像素,构造出图片区域。Canvas的出现极大地挑战了传统富客户端插件的地位,开发者甚至可以用Canvas在浏览器上写一个小游戏。
通过Canvas自动破解验证码,最大的好处是可以在浏览器环境中实现在线破解,大大降低了攻击的门槛。HTML 5使得过去难以做到的事情,变为可能。
6.2 其他安全问题
6.2.1 Cross-Origin Resource Sharing
浏览器实现的同源策略(Same Origin Policy)限制了脚本的跨域请求。但互联网的发展趋势是越来越开放的,因此跨域访问的需求也变得越来越迫切。
6.2.2 postMessage——跨窗口传递消息
在HTML 5中,为了丰富Web开发者的能力,制定了一个新的API:postMessage。
postMessage允许每一个window(包括当前窗口、弹出窗口、iframes等)对象往其他的窗口发送文本消息,从而实现跨窗口的消息传递。这个功能是不受同源策略限制的。
在使用postMessage()时,有两个安全问题需要注意。
在必要时,可以在接收窗口验证Domain,甚至验证URL,以防止来自非法页面的消息。这实际上是在代码中实现一次同源策略的验证过程。
在本例中,接收的消息写入textContent,但在实际应用中,如果将消息写入innerHTML,甚至直接写入script中,则可能会导致DOM based XSS的产生。根据“Secure By Default”原则,在接收窗口不应该信任接收到的消息,而需要对消息进行安全检查。
6.2.3 Web Storage
Web Storage分为Session Storage和Local Storage。Session Storage关闭浏览器就会失效,而Local Storage则会一直存在。Web Storage就像一个非关系型数据库,由Key-Value对组成,可以通过JavaScript对其进行操作。
Firefox还单独实现了一个globalStorage,它是基于SQLite实现的。
6.3 小结
攻击者有可能利用HTML 5中的一些特性,来绕过一些未及时更新的防御方案。要对抗这些“新型”的攻击,就必须了解HTML 5的方方面面。
0 条评论
下一页