读书笔记——吴翰清《白帽子讲Web安全》

目录

第一篇 世界观安全

一 我的安全世界观

第二篇 客户端脚本安全

一 浏览器安全
二 跨站脚本攻击(XSS)
三 跨站点请求伪造(CSRF)
四 点击劫持(ClickJacking)
五 HTML5 安全

第三篇 服务端应用安全

一 注入攻击
二 文件上传漏洞
三 认证与会话管理
四 访问控制
五 加密算法与随机数
六 Web框架安全
七 应用层拒绝服务攻击
八 PHP安全
九 Web Server配置安全

第四篇 互联网公司安全运营 

一 互联网业务安全
二 安全开发流程(SDL)
三 安全运营

第一篇 世界观安全

一 我的安全世界观

1.安全问题的本质是信任的问题。

2.安全是一个持续的过程。

3.安全三要素:机密性(Confidentiality)、完整性(Integrity)、可用性(Availability),简称CIA。

  • 机密性要求保护数据内容不能泄露,加密是实现机密性要求的常见手段。
  • 完整性要求保护数据内容是完整的,没有被篡改的。
  • 可用性要求保护资源是“随需而得”。
  • 扩展:可审计性,不可抵赖性。

4.如何实施安全评估?4个阶段:资产等级划分-->威胁分析-->风险分析-->确认解决方案。

(1)资产等级划分

  • 互联网安全的核心问题,是数据安全的问题。所以,对互联网公司的资产等级划分,就是对数据做等级划分,然后要划分信任域和信任边界。

(2)威胁分析

  • 威胁分析就是把所有的威胁都找出来。
  • 一般采用头脑风暴法和威胁建模法(比如微软提出的STRIDE模型)。
  • 漏洞的定义:系统中可能被威胁利用以造成危害的地方。

(3)风险分析

  • 风险由以下因素组成:Risk(风险)=Probability(发生的可能性)*Damage Potential(损失的大小)
  • 一种科学衡量风险的方法:微软提出的DREAD模型。
  • 注意:模型是死的,人是活的。模型只能起到辅助作用,人要灵活运用。

(4)设计安全方案

  • 一个优秀的安全方案应该具备以下特点:
  1. 能够有效解决问题
  2. 用户体验好
  3. 高性能
  4. 低耦合
  5. 易于扩展与升级

5.安全方案设计技巧

(1)Secure By Default原则

  • 黑名单、白名单原则(尽可能使用白名单,不用或者少用黑名单)
  • 最小权限原则(要求系统只授予主体必要的权限,而不要过度授权)

(2)Defence In Depth(纵深防御)原则

  • 纵深防御包含2层含义:首先,要在各个不同层面、不同方面实施安全方案,避免出现疏漏,不同安全方案之间需要相互配合,构成一个整体;其次,要在正确的地方做正确的事情。即:在解决根本问题的地方实施针对性的安全方案。

(3)数据与代码分离原则

(4)不可预测性原则

  • 不可预测性原则能够有效地对抗基于篡改、伪造的攻击。

第二篇 客户端脚本安全

一 浏览器安全

1.同源策略(Same Origin Policy)

  • 同源策略是一种约定,它是浏览器最核心也最基本的安全功能。
  • 浏览器的同源策略,限制了来自不同源的“document”或脚本,对当前“document”读取或者设置某些属性。
  • 影响“源”的因素有:host、子域名、端口、协议。
  • 在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以跨域加载资源,而不受同源策略的限制。
  • 对于浏览器来说,除了DOM、Cookie、XMLHttpRequest会受到同源策略的限制外,浏览器加载的一些第三方插件也有各自的同源策略。最常见的一些插件如Flash、Java Applet、Silverlight、Google Gears等都有自己的控制策略。

2.浏览器沙箱

  • 挂马:在网页中插入一段恶意代码,利用浏览器漏洞执行任意代码的攻击方式。
  • 浏览器的多进程架构,将浏览器的各个功能模块分开,各个浏览器实例分开,当一个进程崩溃时,也不会影响到其他的进程。
  • SandBox即沙箱,泛指“资源隔离类模块”,设计目的是为了 让不可信任的代码运行在一定的环境中,限制不可信任的代码访问隔离区之外的资源。

3.恶意网址拦截

  • 工作原理:浏览器周期性地从服务端获取一份最新的恶意网址黑名单,如果用户上网时访问的网址存在于此黑名单中,浏览器就会弹出一个警告页面。
  • 常见的恶意网址分为2类:挂马网站&钓鱼网站。
  • 除了恶意网址黑名单拦截功能外,主流浏览器都开始支持EV SSL证书,以增强对安全网站的识别。

4.高速发展的浏览器安全

  • 微软在IE8推出来XSS Filter功能,用以对抗反射型XSS。
  • FireFox在FireFox4推出来Centent Security Policy(CSP),但并未得到推广。
  • 浏览器加载的插件也是浏览器安全需要考虑的一个问题。

二 跨站脚本攻击(XSS)

1.XSS简介

  • 跨站脚本攻击,英文全称Cross Site Script,简称XSS。
  • XSS攻击,通常指黑客通过“HTML注入”篡改了页面,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。
  • XSS分类:反射型XSS(也叫非持久型XSS)、存储型XSS(也叫持久型XSS)、DOM Based XSS。

2.XSS攻击进阶

2.1 XSS Payload

  • XSS Payload就是XSS攻击成功后,攻击者对用户当前浏览的页面植入的能够完成具体功能的一些恶意脚本。
    • (1)Cookie劫持——一个最常见的XSS Payload就是通过读取浏览器的cookie对象,从而发起“Cookie劫持”攻击,直接登录进用户的账户。Cookie的“HttpOnly”标识或者把cookie与客户端IP绑定可以防止“Cookie劫持”。
    • (2)构造GET、POST请求
    • (3)XSS钓鱼——举例:利用JavaScript在当前页面上“画出”一个伪造的登录框,当用户在登录框中输入用户名与密码后,其密码将被发送到黑客的服务器上。
    • (4)识别用户浏览器——如何通过JS脚本识别浏览器版本?1通过XSS读取浏览器的UserAgent对象,存在误报问题;2根据各个浏览器之间存在的实现差异——不同的浏览器会各自实现一些独特的功能,从而写代码识别出不同的浏览器。
    • (5)识别用户安装的软件——举例:IE中,可以通过判断ActiveX控件的某个classid是否存在,来推测用户是否安装了该软件。FireFox的插件列表存放在一个DOM对象中,通过查询DOM可以遍历出所有的插件。Chrome中,通过检测扩展的图标,来判断某个特定的扩展是否存在。
    • (6)CSS History Hack——CSS History Hack就是通过CSS,来发现一个用户曾经访问过的网站。其原理就是利用style的visited属性——如果用户曾经访问过某个链接,那么这个链接的颜色会变得与众不同。
    • (7)获取用户的真实IP地址

2.2 XSS攻击平台有:Attack API、BeEF、XSS-Proxy等。

2.3 终极武器:XSS Worm(蠕虫)

  • 发起XSS Worm攻击的条件:一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS Worm攻击。
  • 比如发送站内信、用户留言等页面,都是XSS Worm的高发区。
  • 举例:Samy Worm(具有里程碑意义的第一个XSS Worm)、百度空间蠕虫等。

2.4 常见的调试JavaScript的工具:Firebug、IE开发者工具、Fiddler、HttpWatch等。

2.5 常见XSS构造技巧

  • (1)利用字符编码
  • (2)绕过长度限制——比如将XSS Payload写到别处,再通过简短的代码加载这段XSS Payload。在某些环境下,也可以利用注释符绕过长度限制。
  • (3)使用<base>标签——<base>标签并不常用,它的作用是定义页面上的所有使用“相对路径”标签的hosting地址。攻击者如果在页面中插入了<base>标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用“相对路径”的标签。
  • (4)window.name的妙用——window对象是浏览器的窗体,而并非document对象,因此很多时候window对象不受同源策略的限制。对当前窗口的window.name赋值,没有特殊字符的限制。举例:利用window.name可以实现数据的跨域传递、缩短XSS Payload的长度等。

2.6 变废为宝:Mission Impossible

  • Apache Expect Header XSS漏洞曾经一度被认为是“鸡肋”漏洞,但是后来有人提出了“使用Flash构造请求”的方法,成功地利用了这个漏洞。
  • Anehta 的回旋镖的思路如下:如果在B域上存在一个反射型XSS_B,在A域上存在一个存储型XSS_A,当用户访问A域上的XSS_A时,同时嵌入B域上的XSS_B,则可以达到在A域的XSS攻击B域用户的目的。即将要利用的反射型XSS嵌入一个存储型XSS中。这个攻击技巧的缺点是,尽管跳转花费的时间很短,但用户还是会看到浏览完地址栏的变化。

2.7 容易被忽视的角落:Flash XSS

  • 前文讲到的XSS攻击都是基于HTML的,其实在Flash中同样也有可能造成XSS攻击。原因是在Flash中是可以嵌入ActionScript脚本的。因此应该尽可能地禁止用户能够上传或加载自定义的Flash文件。如果一定要使用Flash,则可以通过Flash的配置参数进行限制,如果是视频文件,则要求转码为“flv文件”。

2.8 真的高枕无忧吗?JavaScript开发框架

  • 常见的JavaScript框架,Dojo、YUI、jQuery等。
  • 使用JavaScript框架并不能让开发者高枕无忧,同样可能存在安全问题。除了需要关注框架本身的安全外,开发者还要提高安全意识,理解并正确地使用开发框架。

3.XSS的防御

3.1 HttpOnly

  • 浏览器禁止页面JavaScript访问带有HttpOnly属性的Cookie,从而防止Cookie劫持问题。

3.2 输入检查

  • 举例1:输入格式检查:有点像白名单,可以让一些基于特殊字符的攻击失效。输入检查逻辑必须放在服务端代码中实现,放在前端易被绕过。
  • 举例2:XSS Filter:在用户提交数据时获取变量,并进行XSS检查,但此时用户数据并没有结合渲染页面的HTML代码,因此XSS Filter对语境的理解并不完整。

3.3 输出检查

(1)使用安全的编码函数

  • HtmlEncode:针对Html代码的编码方式,它的作用是将字符转换成HTMLEntities,对应的标准是ISO-8859-1。HtmlEncode要求至少转换以下字符:(&-->&amp;)(<-->&lt;)(>-->&gt;)("-->&quot;)('-->')(//)。在OWASP ESAPI中推荐了一种更严格的HtmlEncode——除了字母、数字外,其他所有的特殊字符都被编码成HTMLEntities。
  • JavascriptEncode:针对JavaScript的编码方式,使用“\”对特殊字符进行转义,要求输出的变量必须在引号内。还有一个更加严格的函数来保证安全——除了数字、字母外的所有字符,都使用十六进制“\xHH”的方式进行编码。

(2)只需一种编码吗

  • XSS攻击主要发生在MVC架构中的View层,大部分的XSS漏洞可以在模板系统中解决。比如Python的2个常用的开发框架Django和web2py都选择在View层默认escape所有变量(即HtmlEncode所有变量)以对抗xss,但是并非在模板引擎中使用了auto-escape就万事大吉了,XSS防御需要区分情况对待。

3.4 正确地防御XSS

  • XSS可能发生的场景及对应的防御方法:
  • 场景1:在HTML标签中输出 ——>防御方法是使用HtmlEncode。
  • 场景2:在HTML属性中输出——>防御方法是使用HtmlEncode。
  • 场景3:在<script>标签中输出——>首先确保输出的变量在引号中,防御方法是使用JavascriptEncode。
  • 场景4:在事件中输出——>防御方法是使用JavascriptEncode。
  • 场景5:在CSS中输出——>一般来说,要尽可能禁止用户可控制的变量在“<style>标签”、“HTML标签的style属性”以及“CSS文件”中输出,如果一定有这样的需求,则推荐使用OWASP ESAPI中的encodeForCSS()函数——除了字母数字外的所有字符都被编码成十六进制形式“\uHH”。
  • 场景6:在地址中输出——>如果变量在在URL的路径或者参数中输出,使用URLEncode即可,URLEncode会将字符转换为“%HH”形式,比如空格就是“%20”;如果在URL的协议与host中输出,则不能使用严格URLEncode函数,因为会把“://”、“.”等都编码掉;如果在整个URL中输出,则应该先检查变量是否以“http”开头(如果不是自动添加),以保证不会出现伪协议类的XSS攻击,然后再对变量进行URLEncode。

3.5 处理富文本

  • 有些时候,网站需要允许用户提交一些自定义的HTML代码,称之为富文本。
  • 在过滤富文本时,请谨记以下几条:
  • (1)事件以及一些危险的标签,比如<iframe>、<script>、<base>、<form>等,应该被严格禁止。
  • (2)在标签、属性、事件的选择上,应该使用白名单,避免使用黑名单。
  • (3)尽可能禁止用户自定义CSS与style。如果一定要允许用户自定义样式,则只能像过滤富文本一样过滤CSS,这需要一个CSS Parser对样式进行智能分析,检查其中是否包含危险代码。
  • (4)有一些比较成熟的开源项目,比如Anti_Samy、HTMLPurify等,实现了对富文本的XSS检查。

3.6 防御DOM Based XSS

  • DOM Based XSS是从JavaScript中输出数据到HTML页面中,需要分语境使用不同的编码函数。

3.7 从业务风险的角度看XSS的风险

  • 存储型XSS的风险高于反射型XSS。因为存储型XSS会保存在服务器上,有可能会跨页面存在,甚至可能绕过一些检测工具。
  • 反射型XSS一般需要诱使用户点击一个包含XSS代码的URL链接,而存储型XSS只需要用户查看一个正常的URL链接。这样的漏洞极其隐蔽且埋伏在用户的正常业务中,风险颇高。
  • 网站的PageView越高,对应页面受XSS攻击后的影响越大。

4.小结

  • 理论上,XSS漏洞虽然复杂,但却是可以彻底解决的。在设计XSS解决方案时,应该深入理解XSS攻击的原理,针对不同的场景使用不同的方法。同时有很多开源项目为我们提供了参考。

三 跨站点请求伪造(CSRF,Cross Site Request Forgery)

1.CSRF简介

  • 攻击者在自己的域构造一个页面,在这个页面上伪造一个请求,然后诱使目标用户访问这个页面,从而以该用户身份在第三方站点里执行了一次操作。这就是“跨站点请求伪造”。
  • CSRF为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜到的。

2.CSRF进阶

2.1 浏览器的Cookie策略

  • 浏览器的Cookie分为2种:
  • Session Cookie(临时Cookie):没有指定Expire时间,浏览器一关闭即失效。保存在浏览器进程的内存空间中。
  • Third-party Cookie(本地Cookie):服务器在Set-Cookie时指定了Expire时间,只有到了Expire时间后Cookie才会失效,所以这种Cookie会保存在本地。
  • 一些浏览器默认策略是,允许在<img>、<iframe>、<script>、<link>等标签中发送用于认证的第三方Cookie,从而导致CSRF攻击成功。

2.2 P3P头的副作用

  • P3P头允许跨域访问隐私数据,从而可以允许浏览器跨域发送第三方Cookie。P3P头只需要由网站设置一次即可,之后每次请求都会遵循此策略。

2.3 GET?POST?

  • 因为大多数CSRF攻击发起时,使用的都是<img>、<iframe>、<script>、<link>等带有src属性的标签,而这类标签只能够发起一次GET请求,不能发起POST请求,所以很多开发者就认为只要把重要的操作改成只允许Post请求就能防止CSRF攻击,其实这种观点是错误的。因为对于攻击者来说,有若干种方法可以构造出一个POST请求。比如在一个页面中构造好一个form表单,然后使用JavaScript自动提交这个表单。

2.4 Flash CSRF

  • 在Flash中可以通过URLRequest、getUrl、loadVars等多种方式发起网络请求,包括POST请求。

2.5 CSRF Worm

  • 2008年百度的CSRF Worm展示了CSRF的破坏性——即使没有XSS漏洞,仅仅依靠CSRF,也是能够发起大规模蠕虫攻击的。

3. CSRF的防御

3.1 验证码

3.2 Referer Check

  • Referer Check通过检查请求是否来自合法的“源”来防御CSRF的攻击。
  • 它的缺陷在于,服务器并非什么时候都能取到Referer。而且,某些客户端插件允许发送自定义的Referer头。

3.3 Anti CSRF Token(主要手段)

  • 由于token足够随机,使攻击者无法再构造出一个完整的URL实施CSRF攻击。
  • Token需要同时放在表单和Session中。在提交请求时,服务器只需要验证表单中的Token与用户Session(或Cookie)中的token是否一致,如果一致,则认为是合法的请求,如果不一致,或者有一个为空,则认为请求不合法,可能发生了CSRF攻击。
  • Token的使用原则(注意随机性和保密性)
    • (1)Token的生成一定要足够随机,需要使用安全的随机数生成器生成Token。
    • (2)为了使用方便,可以允许在一个用户的有效生命周期内,在token消耗掉前都使用同一个token。如果Token保存在cookie中,为解决多页面共存的问题,可以考虑生成多个有效的token。
    • (3)注意Token的保密性。尽量把Token放在表单中,把敏感操作由GET改为POST,以form表单(或者AJEX)的形式提交,可以避免Token泄漏。
    • (4)CSRF的Token仅仅用于对抗CSRF攻击,如果网站还同时存在XSS漏洞,这个方案就无效了。因为XSS攻击者可以请求页面后读出页面内容里的Token值,然后再构造一个合法的请求。这个过程可以称之为XSRF。

四 点击劫持(ClickJacking)

1.什么是点击劫持?

  • 点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

2.Flash点击劫持

  • 举例:攻击者制作了一个Flash游戏,诱使用户来玩这个游戏,在完成一系列复杂的动作后,最终控制了用户电脑的摄像头。

3.图片覆盖攻击(Cross Site Image Overlaying,简称XSIO)

  • XSIO攻击原理:通过调整图片的style使得图片能够覆盖在他所指定的任意位置。用户点击此图片的话,会被链接到其他网站。或者不需要点击,图片本身就是一个虚假信息。
  • XSIO防御:需要检查用户提交的HTML代码中,<img>标签的style属性是否可能导致浮出。

4.拖拽劫持与数据窃取

  • 思路:诱使用户从隐藏的不可见的iframe中“拖拽”出攻击者希望得到的数据,然后放到攻击者能控制的另外一个页面,从而窃取数据。

5.ClickJacking 3.0:触屏劫持(TapJacking)

  • 通过将一个不可见的iframe覆盖到当前网页上,可以劫持用户的触屏操作。

6.防御ClickJacking

6.1 使用frame busting方法

  • 写一段JavaScript代码,以禁止iframe的嵌套,这种方法叫frame busting。
  • frame busting的缺陷是,由于它是用JavaScript写的,控制能力不是特别强,因此有许多方法可以绕过它。

6.2 使用一个HTTP头——X-Frame-Options

  • X-Frame-Options有3个可选值:
  • 当值为DENY时,浏览器会拒绝当前页面加载任何frame页面;
  • 当值为SAMEORIGIN时,frame页面的地址只能为同源域名下的页面;
  • 当值为ALLOW_FROM origin时,则可以定义运行frame加载的页面地址。

五 HTML5 安全

1.HTML5新标签

1.1 新标签的XSS

  • 比如笔者曾经使用了html5中新增的<video>标签(用于远程加载一段视频)写了一段XSS代码,成功地绕过来百度空间的XSS Filter。

1.2 iframe的sandbox

  • HTML5专门为iframe定义了一个新的属性,叫Sandbox。它极大增强了应用使用iframe的安全性。
  • 使用sandbox这一属性后,<iframe>标签加载的内容将被视为一个独立的“源”,其中的脚本将被禁止执行,表单被禁止提交,插件被禁止加载,指向其他浏览对象的链接也会被禁止。
  • sandbox属性可以通过参数来支持更精确的控制。有以下几个值可选:
    • allow-same-origin:允许同源访问;
    • allow-top-navigation:允许访问顶层窗口;
    • allow-forms:允许提交表单;
    • allow-scripts:允许执行脚本。

1.3 Link Types:noreferrer

  • 在HTML5中为<a>标签和<area>标签定义了一个新的Link Types:noreferrer。
  • 标签指定了noreferrer后,浏览器在请求该标签指定的地址时将不再发生Referer。
  • 这种设计是为了保护敏感信息和隐私。
  • <a href="xxx" rel="noreferrer">test</a>

1.4 Canvas的妙用

  • <canvas>标签让JavaScript可以在页面中直接操作图片对象,也可以直接操作像素,构造出图片区域。
  • 通过Canvas可以实现自动破解验证码功能,大大降低了攻击的门槛。

2.其他安全问题

2.1 Cross-Origin Resource Sharing

  • 浏览器实现的同源策略限制了脚本的跨域请求,而随着跨域请求的需求增多,W3C委员会制定了一个新的标准来解决日益迫切的跨域访问问题。
  • 标准叙述如下:假设A网页需要发起一个跨域请求,来请求B网页的数据,则A网页在发起请求时必须带上一个Origin Header以证明自己是一个合法的“源”,如果B网页服务器返回一个HTTP Header——Access-Control-Allow-Origin:http://www.a.com,那么这个来自A网页的跨域请求会被通过。

2.2 postMessage——跨窗口传递消息

  • postMessage是HTML5制定的一个新的API,它允许每一个window(包括当前窗口、弹出窗口、iframes等)对象往其他的窗口发送文本消息,从而实现跨窗口的消息传递。这个功能是不受同源策略限制的。
  • 使用win.postMessage()注意事项:
    • (1)为防止消息来自非法页面,可以在接收窗口验证Domain,甚至验证URL;
    • (2)在接收窗口不应信任接收到的消息,需要对消息进行安全检查;
    • (3)使用postMessage也会使XSS Payload变得更加灵活。

2.3 Web Storage

  • Web Storage是HTML5 提出的一个解决在客户端本地存储的功能。
  • Web Storage分为Session Storage和Local Storage,Session Storage关闭浏览器就会失效,而Local Storage则会一直存在。Web Storage就像一个非关系型数据库,由Key-Value对组成,可以通过JavaScript对其进行操作。
  • 使用方法如下:
    • 设置一个值:window.sessionStorage.setItem(key,value);
    • 读取一个值:window.sessionStorage.getItem(key);
    • 此外,Firefox还单独实现了一个globalStorage:window.globalStorage.namedItem(domain).setItem(key,value);
  • Web Storage缺点:
    • 攻击者有可能将恶意代码保存在Web Storage中,从而实现跨页面攻击。
    • 当Web Storage保存有敏感信息时,也有可能成为攻击对象。

第三篇 服务端应用安全

一 注入攻击

  • 注入攻击的本质,就是把用户输入的数据当做代码执行。这里有2个关键条件,第一个是用户能够控制输入,第二个是原本程序要执行的代码,拼接了用户输入的数据。注入攻击是应用违背了“数据与代码分离原则”导致的结果。

1.SQL注入

  • 如果网站的web服务器开启了错误回显,披露了敏感信息,则会对攻击者构造SQL注入语句提供巨大便利。

1.1 盲注(Blind Injection)

  • 盲注就是在服务器没有错误回显时完成的注入攻击。此时攻击者可以构造简单的条件语句,根据返回页面是否发生变化,来判断SQL语句是否得到执行,从而判断出SQL注入漏洞是否存在。

1.2 Timing Attack

  • 在mysql中有一个用于测试函数性能的BENCHMATK()函数,它可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断出注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack。Timing Attack是盲注的一种高级技巧。在不同数据库中,都有着类似于BENCHMATK()的函数可以被Timing Attack所利用。

2.数据库攻击技巧

2.1 常见的攻击技巧

  • (1)SQL注入可以猜测出数据库的对应版本。
  • (2)利用union select可以确认某个表名是否存在,以及列名是否存在。
  • (3)进一步可以通过判断字符的范围,一步一步读出某字段的值。
  • (4)这个过程非常繁琐,可以使用自动化注入工具sqlmap.py来帮助完成。
  • (5)在注入攻击过程中,常常会用到一些读写文件的技巧。比如mysql中,就可以通过LOAD_FILE()读取系统文件,通过INTO DUMPFILE写入本地文件,通过LOAD DATA INFILE将文件导入创建的表中,最后就可以通过一般的注入技巧直接操作表数据了。所以,在设计数据库安全方案时,可以禁止普通用户具备操作文件的权限。

2.2 命令执行

  • 在MySQL中除了可以通过导出webshell间接地执行命令外,还可以利用“用户自定义函数”的技巧,即UDF(User-Defined Functions)来执行命令。比如通过lib_mysqludf_sys提供的几个函数执行系统命令。
  • 其他数据库也有类似UDF的功能,利用UDF功能实施攻击的技巧也大同小异。
  • 在Oracle数据库中,如果服务器同时还有Java环境,那么也可能造成命令执行。当SQL注入后可以执行多语句的情况下,可以在Oracle中创建Java的存储过程执行系统命令。
  • 一般来说,在数据库执行系统命令要求具有较高的权限。因此在建立数据库账户时应该遵循“最小权限原则”,尽量避免给Web应用使用数据库的管理员权限。

2.3 攻击存储过程

  • (1)利用存储过程直接攻击。比如在MS SQL Server中,可以直接使用存储过程“xp_cmdshell”执行系统命令,使用存储过程“xp_regread”等来操作注册表,等等。
  • (2)存储过程本身也可能会存在注入漏洞。比如存储过程中的某些变量由外部传入,且未经过任何处理,将直接造成SQL注入的问题。

2.4 编码问题

  • 基于字符集的注入攻击的解决方法:统一数据库、操作系统、Web应用所使用的字符集,以避免各层对字符的理解存在差异。统一设置为UTF-8是一个很好的办法。如果因为种种原因无法统一字符编码,则需要单独实现一个用于过滤或转义的函数,这个函数根据系统所使用的不同字符集来限制用户输入数据的字符允许范围,以实现安全过滤。

2.5 SQL Column Truncation

  • 在MySQL的配置选项中,有一个sql_mode选项。当MySQL的sql_mode设置为宽松模式时,即没有开启STRICT_TRANS_TABLES选项时,MySQL对于用户插入的超长值只会提醒warning,而不是error(如果是error则插入不成功),这可能导致发生一些“截断”问题。
  • 例如:数据库中存在一个表user,该表中有一个字段为username,username的字段类型为varchar(10),如果我在插入数据的时候,插入一个值“admin(55个空格)x”,显然它超过了设定的字段长度10。那么,如果MySQL事先设置的是宽松模式,则此时会报warning,数据自动截断,插入成功;如果MySQL事先设置的是严格模式,则报error,数据插入失败。
  • 当攻击者插入一个与数据库中已存在的同名username时,则可能使攻击者通过某些认证,从而造成一些越权访问。比如通过注册一个用户名为“admin(55个空格)x”的用户,就可以修改原管理员的密码了。

3.正确地防御SQL注入

3.1 使用预编译语句

  • 一般来说,防御SQL注入的最佳方式,就是使用预编译语句,绑定变量。比如在Java语言中,使用PreparedStatement()方法,绑定变量。
  • mybatis的#{}和${}语法区别:#相当于对数据 加上 双引号,$相当于直接显示数据。mybatis使用#{}语法参数化来避免SQL注入。

3.2 使用安全的存储过程

3.3 检查输入数据的数据类型

  • 比如输入数字时,检查输入数据只能为整型,或者输入邮箱时,严格按照邮箱的格式检查等。

3.4 使用安全的编码函数

  • 比如ESAPI.encoder().encodeForSQL( new OracleCode(), queryparam );

3.5 最小权限原则

  • 数据库使用“最小权限原则”,避免Web应用之间使用root、dbowner等最高权限账户直接连接数据库。如果有多个不同的应用使用同一个数据库,则也应该为每个应用分配不同的账户。Web应用使用的数据库账户,不应该有创建自定义函数,操作本地文件的权限。

4.其他注入攻击

4.1 XML注入

  • XML注入与HTML注入类似。解决方法就是对用户输入数据中包含的“语言本身的保留字符”进行转义即可。

4.2 代码注入

  • 代码注入与命令注入往往都是由一些不安全的函数或者方法引起的,其中的典型代表就是eval()。其他的还有比如利用Java的脚本引擎实施代码注入、PHP和JSP的动态include导致代码注入、利用system()函数执行系统命令等。
  • 对抗代码注入、命令注入是,需要禁用eval()、system()等可以执行命令的函数。如果一定要使用这些函数,则需要对用户的输入数据进行处理。此外,在PHP/JSP中避免动态include远程文件,或者安全地处理它。此外,在开发过程中,应尽量避免使用危险函数。

4.3 CRLF注入

  • CRLF实际上是两个字符:CR是carriage return(回车,ASCII 13,\r),LF是line feed(换行,ASCII 10,\n)。即\r\n,其十六进制编码分别为0x0d、0xa。
  • CRLF常被用做不同语义之间的分隔符。因此t通过“注入CRLF字符”,就有可能改变原有的语义。凡是使用CRLF作为分隔符的地方都有可能存在这种注入,比如log注入、“注入HTTP头”等。
  • 在HTTP协议中,HTTP头是通过“\r\n”来分隔的。因此如果服务器端没有过滤“\r\n”,而又把用户输入的数据放在HTTP头中,则有可能导致安全隐患。这种在HTTP头中的CRLF注入,又可以称为“Http Response Splitting”。比如通过2次CRLF注入可以将恶意代码注入到HTTP Body中,通过1次CRLF注入可以注入一个Link头造成XSS、注入一个X-XSS-Protection:0头以关闭IE8的XSS Filter功能等。
  • 对抗CRLF的方法非常简单,只要处理好“\r”、“\n”这两个保留字符即可,尤其是那些使用换行符作为分隔符的应用。

二 文件上传漏洞

1.文件上传漏洞概述

  • 文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。
  • 文件上传后导致的常见安全问题一般有~~~~~
  • 通过文件上传漏洞进行攻击需要满足3个条件:
  • (1)上传的文件能被web容器解释执行。
  • (2)用户能够从Web*问这个文件。
  • (3)用户上传的文件若被安全检查、格式化、图片压缩等功能改变了内容,则也可能导致攻击不成功。

1.1 从FCKEditor文件上传漏洞谈起

  • FCKEditor是一款非常流行的富文本编辑器,它一般是作为第三方应用集成到网站中的,它有一个文件上传功能,在存在漏洞的版本中,是通过检查文件的后缀来确定是否安全的,以黑名单的的方式限制文件上传的类型,因此有一些不在黑名单中的文件,比如后缀为php2,asa,cer等的文件都可能导致发生安全问题。

1.2 绕过文件上传检查功能

  • 很多应用通过判断文件名后缀的方法来验证文件的安全性——攻击者可以手动修改上传过程的POST包,在文件名后添加一个%00字节,则可以截断某些函数对文件名的判断,达到攻击目的。
  • 有的应用通过判断上传文件的文件头来验证文件的类型——攻击者可以伪造一个合法的文件头,而将真实的PHP等脚本代码附在合法的文件头之后。

2.功能还是漏洞

2.1 Apache文件解析问题

  • Apache对于文件名的解析是从后往前的,直到遇见一个它认识的文件类型为止。Apache又是根据定义在自身mime.types文件中的内容来认识文件类型。在Apache 1.x、2.x中,Apache不认识.rar文件类型,所以在解析Phpshell.php.rar.rar.rar.rar.rar文件时,它会从后往前一直遍历后缀到.php,然后认为这是一个PHP类型的文件。从而导致脚本被执行。

2.2 IIS文件解析问题

  • IIS 6漏洞一:分号字符截断问题,比如将文件名abc.asp;xx.jpg解析为abc.asp,从而导致脚本被执行。
  • IIS 6漏洞二:因为处理文件夹扩展名出错,导致将/*.asp/目录下的所有文件都作为ASP文件进行解析。
  • ISS中由于支持PUT功能导致的上传脚本问题:在IIS中,如果目录支持写权限,同时开启了WebDev,则会支持PUT方法,再结合MOVE方法,就能够将原来只允许上传的文本文件改为脚本文件从而执行webshell。Move能否执行成功,取决于IIS服务器是否勾选了“脚本资源访问”复选框。
  • 一般要实施此攻击过程,攻击者应先通过OPTIONS方法探测服务器支持的HTTP方法类型,如果支持PUT,则使用PUT上传一个指定的文本文件,最后通过MOVE改写为脚本文件。

2.3 PHP CGI路径解析问题

  • Nginx配置fastcgi使用PHP时,会存在文件解析漏洞。比如当访问http://www.xxx.com/path/test.jpg/notexist.php时,会将test.jpg当做PHP进行解析,notexist.php是不存在的文件。
  • 这样导致的后果是,如果在任何配置为fastcgi的PHP应用里上传一张图片,其图片内容是PHP文件,则将导致代码执行。
  • 官方建议是将PHP的配置文件中与此有关的一个关键选项cgi.fix_pathinfo设置为0(态度消极)。

2.4 利用上传文件钓鱼

  • 钓鱼网站在传播时,会通过利用XSS、服务器端302跳转等功能,从正常的网站跳转到钓鱼网站。但是这种钓鱼会在URL中暴露真实的钓鱼网站地址,易被发现。
  • 而利用文件上传功能,钓鱼者可以先将包含了HTML的文件(比如一张图片)上传到目标网站,然后通过传播这个文件的URL进行钓鱼,则URL中不会出现钓鱼地址,更具有欺骗性。

3.设计安全的文件上传功能

  • (1)文件上传的目录设置为不可执行
  • (2)判断文件类型(推荐白名单方式)
  • (3)使用随机数改写文件名和文件路径
  • (4)单独设置文件服务器的域名

三 认证与会话管理

1.Who am I?

  • 认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么。
  • 认证实际上就是一个验证凭证的过程。如果只有一个凭证被用于认证,则称为“单因素认证”(用户体验好),如果有2个或者多个凭证被用于认证,则称为“双因素认证”或“多因素认证”(强度高)。

2.密码那些事儿

  • 密码是最常见的一种认证手段。
  • 密码强度——是设计密码认证方案时第一个需要考虑的问题,每个网站在其选择上,都有自己的策略。目前并没有一个标准。笔者介绍的OWASP推荐策略大家可以参考。
  • 密码保存——密码必须以不可逆的加密算法,或者是单项散列函数算法,加密后存储在数据库中。目前普遍做法是将明文密码经过哈希后(MD5或者SHA-1)再保存到数据库中,使用MD5加密密码容易被“彩虹表”方法破解,为了对抗“彩虹表”类攻击,在计算密码明文的哈希值时,可以增加一个“Salt”。“Salt”是一个随机字符串,作用是为了增加明文的复杂度。Salt使用如下:MD5(Username+Password+Salt)。

3.多因素认证

  • 多因素认证提高了攻击的门槛。比如支付宝是使用了支付密码、手机动态口令、数字证书、保令、支付盾、第三方证书等进行多因素认证。

4.Session与认证

  • 当认证成功后,就需要替换一个对用户透明的凭证,这个凭证,就是SessionID。一般会把SessionID加密后保存在Cookie中,因为Cookie会随着HTTP请求头发送,且受到浏览器同源策略的保护。
  • 为了安全,一要保证SessionID的随机性,二要防止SessionID劫持。

5.Session Fixation攻击

  • Session Fixation攻击过程——攻击者先获取到一个未经认证的SessionID,然后将这个SessionID交给用户去认证,用户完成认证后,服务器并未更新此SessionID的值,所以攻击者可以直接凭借此SessionID登录仅用户的账户。
  • Session Fixation解决方法——在登录完成后,重写SessionID。

6.Session保持攻击

  • Session保持攻击1——有一些系统,出于用户体验的考虑,只要这个用户还活着,就不会让这个用户的Session失效,从而攻击者可以通过不停地发起访问请求(比如刷新页面),让session一直活下去。
  • Session保持攻击2——还有很多系统,服务器端并不维护Session,而把Session放在Cookie中加密保存,利用Cookie的Expire标签来控制Session的失效时间。而Cookie的Expire时间是完全可以由客户端控制的。篡改这个时间并使其永久有效就有可能获得一个永久有效的Session。甚至攻击者可以为Session Cookie增加一个Expire时间,使得原本浏览器关闭就会失效的Cookie持久化保存在本地,变成一个第三方Cookie。
  • 如何对抗Session保持攻击?
    • (1)在一定时间后,强制销毁Session。
    • (2)当用户客户端发生变化时,要求用户重新登录。
    • (3)每个用户只允许拥有一个Session。

7.单点登录(Single Sign On,简称SSO)

  • 单点登录实现了用户只登录一次,就可以访问所有的系统。
  • 它有利有弊,利是风险集中化,只需要保护好这一个点,弊是风险被集中了,单点一旦被攻破,影响的范围将涉及所有使用单点登录的系统。
  • 目前最大的单点登录实现是OpenID,但是发展有限。

四 访问控制

1.What Can I do?

  • 访问控制——某个主体对某个客体需要实施某种操作,而系统对这种操作的限制就是权限控制。
  • 在Web应用中,根据访问客体的不同,常见的访问控制可以分为基于 URL/方法/数据的访问控制。
  • 漏洞举例:有些网站后台页面存在未授权访问漏洞,比如一个后台管理页面只有管理员才可以访问,它是不会被链接到前台页面上的,所以正常用户是不知道的。但是它却未对用户访问权限进行控制,导致任意用户只要构造出了正确的URL就可以访问这些页面。解决方法只要加上“基于页面的访问控制”可以了。

2.垂直权限管理(又称为“基于角色的访问控制”)

  • 访问控制就是建立起用户与权限之间的对应关系,一种应用广泛的方法是基于角色的访问控制(Role-based Access  Control),简称RBAC,我们称之为“垂直权限管理”。即高权限角色访问低权限角色的资源往往是被允许的,而低权限角色访问高权限角色资源往往被禁止。为防止发生“越权访问”,在配置权限时,应该使用“最小权限原则”和“默认拒绝”策略。
  • 举例:Spring Security中的权限管理就是RBAC模型的一个实现。

3.水平权限管理(又称为“基于数据的访问控制”)

  • “垂直权限管理”不足之处——同一个角色下的不同用户可能存在私有数据,RBAC模型只会验证用户A是否属于角色RoleX,而不会判断用户A能否访问只属于用户B的数据DataB,因此,发生了“越权访问”。这种问题,我们就称之为“水平权限管理问题”。
  • 水平权限问题与业务需求息息相关,目前并没有通用的解决方案,一般是具体问题具体解决。

4.OAuth简介

  • OAuth是一个在不提供用户名和密码的情况下,授权第三方应用访问Web资源的安全协议。比如它可以使得用户在不需要向人人网提供MSN用户名和密码的情况下,可以授权MSN将用户的好友名单提供给人人网。

五 加密算法与随机数

1.概述

  • 常见的加密算法分为两类:
    • (1)分组加密算法,比如DES、3-DES、Blowfish、IDEA、AES等。
    • (2)流密码加密算法,比如RC4、ORYX、SEAL等。
  • 针对加密算法的攻击,根据攻击者能获得的信息,可以分为:唯密文攻击、已知明文攻击、选择明文攻击、选择密文攻击。

2.流密码加密算法

  • Stream Cipher Attack——流密码的加密是基于异或操作的,每次都只操作一个字节。性能好。

流密码加密算法中的几种常见攻击方法:

2.1 Reused Key Attack

  • 在流密码的使用中,最常见的一个错误就是使用同一个密钥进行多次加解密,这将使破解流密码非常简单。这种攻击叫做“Reused Key Attack”。在这种攻击下,攻击者不需要知道密钥即可还原出明文。
  • 举例——破解authcode()函数加密。
  • 延伸——弱随机IV问题(IV指初始化向量):在anthcode()函数中,它默认使用了4字节的IV,使得破解的难点增大,但其实4字节的IV是很脆弱的,它不够随机,攻击者可以通过“暴力破解”的方式找到重复的IV。

2.2 Bit-Flipping Attack

  • 攻击者在不知道明文的情况下,通过改变密文,使得明文按其需要的方式发生改变的攻击方式,被称为Bit-Flipping Attack。
  • 解决Bit-Flipping攻击的方法是验证密文的完整性。最常见的方法是增加带有KEY的MAC(Message Authentication Code,消息验证码),通过MAC验证密文是否被篡改。
  • 通过哈希算法来实现的MAC,称为HMAC。HMAC由于其性能较好,而被广泛应用。

2.3 WEP破解

  • WEP是以前用的无线加密传输协议,破解了WEP的密钥,就可以免费蹭网了。WEP采用RC4算法,由于存在漏洞易被破解,目前已经被WPA(全名为Wi-Fi Protected Access,有WPA和WPA2两个标准)取代了。

3.分组加密算法中的几种攻击方法

3.1 ECB模式的缺陷

  • 对于分组加密算法,除去算法本身,还有一些通用的加密模式,不同的加密算法会支持同样的几种加密模式。常见的加密模式有:ECB、CBC、CFC、OFB、CTR等,如果加密模式被攻击,那么不论加密算法的密钥有多长,都有可能不再安全。
  • ECB模式是最简单的一种加密模式,它的每个分组之间相对独立,改变分组密文的顺序,将改变解密后的明文顺序;替换某个分组密文,解密后该对应分组的明文也会被替换,而其他分组不受影响。这与链式加密模式(CBC)完全不同,链式加密模式的分组前后之间会互相关联,一个字节的变化,会导致整个密文发生变化。
  • 当需要加密的明文多于一个分组的长度时,应该避免使用ECB模式,而使用其他更加安全的加密模式。

3.2 Padding Oracle Attack

  • 针对CBC模式的Padding Oracle Attack——它可以在不知道密钥的情况下,通过对padding bytes的尝试,还原明文,或者构造出任意明文的密文。
  • padbuster工具可以自动实施Padding Oracle攻击。
  • Padding Oracle Attack的关键在于攻击者能够获知解密结果是否符合padding。在实现和使用CBC模式的分组加密算法时,注意这一点即可。

4.密钥管理

  • 在密码学里有个基本原则:密码系统的安全性应该依赖于密钥的复杂性,而不应该依赖于算法的保密性。
  • 密钥管理中最常见的错误就是将密钥硬编码在代码里,这样做大大提高了密钥泄漏的可能性。
  • 对于web应用,常见的做法是将密钥(包括密码)保存在配置文件或者数据库中,在使用时由程序读出密钥并加载进内存,一定不能把密钥写入本地文件中。

5.伪随机数问题

  • 伪随机数,是通过一些数学算法生成的随机数,并非真正的随机数。密码学上的安全伪随机数应该是不可压缩的。

5.1 弱伪随机数的麻烦

  • 在WEB应用中,密码、key、SessionID、token等许多非常关键的“secret”都是通过伪随机数算法生成的,如果使用了弱伪随机数算法,则可能导致非常严重的安全问题。

5.2 时间真的随机吗

  • 有的程序员直接使用系统时间代替随机数生成,这样生成的随机数时根据时间顺序增长的,可以从时间上进行预测,从而存在安全隐患。
  • 要切记——不要把时间函数当成随机数使用。

5.3 破解伪随机数算法的种子

  • 在PHP中,常用的随机数生成算法有rand()、mt_rand(),最大值分别为32767(3万多)、2147483647(约21.5亿)。
  • rand()范围非常小,如果将其用户一些重要的地方,将会非常危险。
  • mt_rand()也有一些缺陷。可以通过猜测种子,来猜测其产生的伪随机数。
    • 原理:伪随机数是由数学算法实现的,它真正随机的地方在于“种子(seed)”。种子一旦确定后,再通过同一伪随机数算法计算出来的随机数,其值是固定的,多次计算所得值的顺序也是固定的。
    • 攻击方式:
      • (1)通过一些方法猜测出种子的值;
      • (2)通过mt_rand()对猜解出的种子值进行播种;
      • (3)通过还原程序逻辑,计算出对应的mt_rand()产生的伪随机数的值。

5.4 使用安全的随机数

  • 谨记:在重要或敏感的系统中,一定要使用足够强壮的随机数生成算法。比如
    • 在java中,可以使用java.security.SecureRandom;
    • 在Linux中,可以使用/dev/Random或者/dev/urandom;
    • 在PHP中,可以使用openssl_random_pseudo_bytes()函数;
    • 其他,可以在算法上通过多个随机数的组合以增加随机数的复杂性,比如通过给随机数使用MD5算法后,再连接一个随机字符,然后再MD5算法一次。

6.小结

  • 算法的选择和使用之最佳实践:
    • (1)不要使用ECB模式;
    • (2)不要使用流密码(比如RC4);
    • (3)使用HMAC-SHA1代替MD5(甚至是代替SHA1);
    • (4)不要使用相同的key做不同的事情;
    • (5)salts和IV需要随机产生;
    • (6)不要自己实现加密算法,尽量使用安全专家已经实现好的库;
    • (7)不要依赖系统的保密性。
  • 当你不知道如何选择时,有以下建议:
    • (1)使用CBC模式的AES256用于加密;
    • (2)使用HMAC-SHA512用于完整性检查;
    • (3)使用带salt的SHA-256或SHA-512用于Hashing。

六 Web框架安全

1.MVC框架安全

  • MVC是Model-VIew-Controller的缩写,它将Web应用分为三层,View层负责用户视图、页面展示等工作;Controller负责应用的逻辑实现,接收View层传入的用户请求,并转发给对应的Model做处理;Model层则负责实现模型,完成数据的处理。
  • 从数据的流入来看,用户提交的数据先后流经了View层、Controller层、Model层,数据的流出则反过来。
  • 优秀的安全方案应该是在正确的地方做正确的事情,比如在View层解决XSS问题,在Model层解决SQL注入问题等等。
  • 在框架中集中实施安全方案,可以大大节省程序员的工作量,而且可以使所有基于框架开发的业务都能受益,从安全方案的有效性来说,更容易把握。

2.模板引擎与XSS防御

  • 在当前流行的MVC框架中,View层常用的技术是使用模板引擎对页面进行渲染。
  • 最好的XSS防御方案,是在不同的场景使用不同的编码函数,而一些模板引擎却是统一使用HtmlEncode编码来防御XSS攻击,这样很有可能会被攻击者绕过。
  • 不过幸运的是,在模板引擎中可以以实现自定义的编码函数,应用于不同场景。在Django中是使用自定义filters,在Velocity中则可以使用“宏”。通过自定义的方法,使得XSS防御功能得到完善。
  • 在其他的模板引擎中,也可以根据“是否有细分场景使用不同的编码方式”来判断XSS的安全方案是否完整。在使用Web框架时,应该慎重对待安全问题,不可盲从官方文档。

3.Web框架与CSRF防御

  • 在Web框架中可以使用security token解决CSRF攻击的问题。
  • 对应Web框架来说,可以要求所有的写操作都使用HTTP POST,自动地在所有涉及POST的代码中添加token,这些地方包括所有的form表单,所有的Ajex POST请求等。
  • 完整的CSRF防御方案,对于Web框架来说有以下几处需要改动。
    • (1)在Session中绑定token。如果不能保存到服务器端Session中,则可以替代为保存到Cookie里。
    • (2)在form表单中自动填入token字段。
    • (3)在Ajex请求中自动添加token,这可能需要已有的Ajex封装实现的支持(一般是插入一个包含了token的HTTP头,使用HTTP头是为了防止Token泄密,因为一般的JavaScript无法获取到HTTP头的信息,但是存在一些跨域漏洞时可能会出现例外)。
    • (4)在服务器端对比POST提交参数的token与Session中绑定的token是否一致,以验证CSRF攻击。
  • 在Spring MVC以及一些其他的流行Web框架中,并没有直接提供对CSRF的保护,因此这些功能需要自己实现。

4.HTTP Headers管理

  • 在Web框架中,可以对HTTP头进行全局化的处理,因此一些基于HTTP头的安全方案可以很好地实施。比如
    • (1)将Http头看成Key-Value对,对抗CRLF的方案只需在“value”中编码所有的\r\n即可(当然了,用户绝对不能控制key,因为这是非常危险的);
    • (2)在框架中统一管理好跳转的目的地址,比如指定跳转地址只能在白名单中,防止被钓鱼。
    • (3)有很多与安全相关的Headers,也可以统一在Web框架中配置。比如用来对抗ClickJacking的X-Frame-Options,web框架可以封装此功能,并提供页面配置。
    • (4)对所有的Cookie默认添加HttpOnly,不需要此功能的Cookie则单独在配置文件中列出。

5.数据持久层与SQL注入

  • 对抗SQL注入的最佳方式就是使用“预编译绑定变量”。
  • 使用ORM(Object/Relation Mapping)框架对SQL注入是有积极意义的。

6.还能想到什么

  • 凡是在Web框架中可能实现的安全方案,只要对性能没有太大的损耗,都应该考虑实施。比如:
    • (1)在Web框架中为上传文件功能提供一个足够安全的二方库或者函数;
    • (2)保存好安全检查的日志;
    • (3)与时俱进等。

7.Web框架自身安全

  • Web框架曾经出现过的严重漏洞:
    • (1)Struts 2命令执行的漏洞
    • (2)从Struts 2的问题补丁可以看出,其开发者对于安全的理解非常不到位。
    • (3)Spring MVC命令执行漏洞
    • (4)Django命令执行漏洞

七 应用层拒绝服务攻击

1.DDOS简介

  • DDOS又称为分布式拒绝服务,全称是Distributed Denial of Service。DDOS本质是利用合理的请求造成资源过载,导致服务不可用。
  • 常见的DDOS攻击有SYN flood(最经典,利用了TCP协议设计中的缺陷)、UDP flood、ICMP flood等。
  • TCP三层握手过程~~~
  • SYN flood攻击过程~~~
  • 对抗SYN flood的措施主要有SYN Cookie/SYN Proxy、safereset等算法。
  • 在很多对抗DDOS的产品中,一般会综合使用各种算法,结合一些DDOS攻击的特征,对流量进行清洗。

2.应用层DDOS—— CC攻击

  • CC攻击原理:对一些消耗资源较大的应用页面不断发起正常的请求以达到消耗服务器资源的目的。
  • 在Web应用中,查询数据库、读写硬盘文件等操作,相对都会消耗比较多的资源。
  • 应用层DDOS攻击还可以通过以下方式完成:在黑客入侵了一个流量很大的网站后,通过篡改页面,将巨大的用户流量分流到目标网站。

3.防御应用层DDOS

3.1 限制请求频率

  • 最常见的针对应用层DDOS攻击的防御措施,是在应用中针对每个“客户端”做一个请求频率的限制。比如通过IP地址和Cookie定位一个客户端,如果客户端的请求在一定时间内过于频繁,则对之后来自该客户端的所有请求都重定向到一个出错页面。
  • 虽然网站可以根据IP地址定位攻击者,但是在实际的攻击中,攻击者一般会使用代理服务器或者傀儡机来隐藏自己的真实IP地址,从而绕过服务器对单个IP地址请求频率的限制了。
  • 解决应用层DDOS攻击我们可以从以下3个方面入手:
    • (1)应用代码做好性能优化。
    • (2)在网络架构上做好优化(比如利用负载均衡进行分流)。
    • (3)实现一些对抗手段,比如限制每个IP地址的请求频率。

3.2 人机识别

3.2.1 验证码的那些事儿——识别人

  • 验证码(CAPTCHA)的用户体验不好,但是却能够有效地阻止自动化的重发行为。
  • 验证码破解技术:
    • (1)直接利用图像相关算法识别验证码。
    • (2)利用Web实现上可能存在的漏洞破解验证码。比如
      • 原理1:验证码的验证过程,是对比用户提交的明文和服务器端Session里保存的验证码明文是否一致。
      • 对应漏洞:因为验证码消耗掉后SessionID未更新,导致使用原来的SessionID可以一直重复提交同一个验证码。
      • 原理2:还有的验证码实现方式,是提前将所有的验证码图片生成好,以哈希过的字符串作为验证码图片的文件名。使用验证码时,则直接从图片服务器返回已经生成好的验证码。这种设计原本的想法是为了提高性能。
      • 对应漏洞:这种一一对应的验证码文件名会存在一个缺陷:攻击者可以事先采用枚举的方式,遍历所有的验证码图片,并建立验证码到明文之间一一对应关系,从而形成一张“彩虹表”。这也会导致验证码形同虚设。修补的方式是验证码的文件名需要随机化,满足“不可预测性”原则。

3.2.2 识别客户端

  • 一般情况下,服务器端应用可以通过判断HTTP头中的User-Agent字段来识别客户端,但是User-Agent是可以被客户端篡改的,所以不能信任。一种比较可靠的方法是让客户端解析一段JavaScript并给出正确的运行结果,或者发送一个flash让客户端解析。但有的客户端脚本是内嵌在浏览器中的“内挂”,那就无法检测了。

3.3 其他

  • 在Apache的配置文件中,有一些参数可以缓解DDOS攻击。比如调小Timeout、KeepAliveTimeout值,增大MaxClients值。
  • 目前已经有一些开源的Module全部或者部分实现了真的应用层DDOS攻击的保护。比如mod_qos、mod_evasive等。
  • Yahoo的专利。

4.资源耗尽攻击

4.1 Slowloris攻击

  • 原理:由于WebServer对于并发的连接数都有一定的上限,因此若是恶意地占用住这些连接不释放,那么Web Server的所有连接都将被恶意连接占用,从而无法接受新的请求,导致拒绝服务。
  • 攻击:在正常的HTTP包头中,是以两个CLRF表示HTTP Headers部分结束的。因此攻击者可以构造一个不完整的HTTP请求(最后一行只有一个CLRF),Web Server只收到了一个\r\n,因此将认为HTTP Header部分没有结束,并保持此连接不释放,继续等待完整的请求。此时客户端再发送任意HTTP头,保持住连接即可。当构造多个连接后,服务器的连接数很快就会达到上限。

4.2 HTTP POST DOS

  • 原理:在发送HTTP POST包时,指定一个非常大的Content-Length值,然后以很低的速度发包,比如10-100s发一个字节,保持住这个连接不断开。这样当客户端连接数多了以后,占用住了Web Server的所有可用连接,从而导致DOS。

4.3 Server Limit DOS

  • 原理:由于Web Server限制Request Header最大值为8192字节,如果客户端发送的HTTP包头超过这个大小,服务器就会返回一个4xx错误。
  • 攻击:假设攻击者通过XSS攻击,恶意地往客户端写入了一个超长的Cookie,由于Cookie也是放在HTTP包头中发送的,Web Server默认会认为这是一个超长的非正常请求,从而导致拒绝服务,则在该客户端清空Cookie之前,将无法再访问该Cookie所在域的任何页面。
  • 防御:调整Apache配置参数LimitRequestFieldSize,这个参数设置为0时,对HTTP包头大小没有限制。

5 一个正则引发的血案:ReDOS

  • 当正则表达式写的不好从而被恶意输入利用,消耗大量资源,导致DOS。这种攻击被称为ReDOS。
  • 原理:当用户恶意构造输入时,有缺陷的正则表达式会增加正则引擎解析数据时的消耗,就会消耗大量的系统资源(比如CPU和内存),从而导致整台服务器的性能下降,表现的结果是系统速度很慢,有的进程或服务失去响应,与拒绝服务的后果是一样的。

八 PHP安全

1.文件包含漏洞

  • 文件包含是PHP的一种常见用法,主要由4个函数完成:include()、require()、include_once()、require_once()。当使用这4个函数包含一个新的文件时,该文件将作为PHP代码执行,PHP内核并不在意该包含的文件是什么类型。
  • 利用条件:(1)include()等函数通过动态变量的方式引入需要包含的文件;(2)用户能够给控制该动态变量。

1.1 本地文件包含漏洞(Local File Inclusion,LFI)

  • 比如这段代码,include “/home/wwwrun/”.$file.'php';,用户可以控制参数file,当file的值为“../../etc/passwd”时,PHP将访问/etc/password.php文件。
  • 但是这个文件是不存在的,攻击者可以在最后加入一个0字节,截断file变量之后的字符串(因为PHP内核是由C语言实现的,在连接字符串时,0字节(\x00)将作为字符串的结束符)。即“../../etc/passwd\0”,通过Web输入时,只需要URLEncode,变成“../../etc/passwd%00”。
  • 字符截断技巧,也是文件包含中最常用的技巧。但在一般的web应用中,0字节用户其实是不需要使用的,因此完全可以禁用的。
  • 此时,攻击者可以使用另外一个技巧,利用操作系统对目录最大长度的限制,可以不需要0字节而达到截断的目的。目录字符串,在Windows下256字节、Linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。如何构造出这么长的目录呢?通过“./”即可。比如“./././././././././.abc”或者“////////////abc”或者“../1/abc../1/abc../1/abc”。
  • 本地文件包含漏洞能够读取敏感文件或者服务器端脚本的源代码,从而为攻击者进一步攻击奠定基础。
  • 使用了“../../../”这样的方式来返回到上层目录中,这种方式又被称为“目录遍历”。常见的目录遍历漏洞,还可以通过不同的编码方式来绕过一些服务器端逻辑。比如%2e%2e%2f等同于../等等。
  • 目录遍历漏洞是一种跨越目录读取文件的方式,但当PHP配置了open_basedir时,将很好地保护服务器,使得这种攻击无效。open_basedir的值是目录的前缀,如果要限定一个指定的目录,则需要在最后加上“/”。
  • 要解决文件包含漏洞,应该尽量避免包含动态的变量,尤其是用户可以控制的变量。一种变通方法是使用枚举,将$file的值被枚举出来,也就避免了任意文件包含的风险。

1.2 远程文件包含漏洞(Remote File Inclusion,RFI)

  • 攻击者可以构造攻击URL,用来执行任意命令。

1.3 本地文件包含的利用技巧

以下几种常见技巧,用于本地文件包含后执行PHP代码。

  • (1)包含用户上传的文件。——最简单的方法,用户上传的文件内容中如果包含PHP代码,那么这些代码被include()加载后将会执行。但是能否攻击成功,取决于文件上传功能的设计,比如要求知道用户上传后文件所在的物理路径,有时候这个路径很难猜到。
  • (2)包含data://或PHP://input等伪协议。——伪协议需要服务器支持,同时要求allow_url_include设置为ON。
  • (3)包含Session文件。——需要攻击者能控制部分Session文件的内容。
  • (4)包含日志文件。——间接地将PHP代码写入日志中,然后包含日志文件即可。但是当日志文件过大时,PHP进程可能会僵死。因此在凌晨时包含日志文件将提高攻击的成功性,因为此时日志文件可能非常小。
  • (5)包含/proc/self/environ文件。——它是Web进程运行时的环境变量,其中很多都是用户可以控制的,最常见的做法是在User-Agent中注入PHP代码,完成攻击。
  • (6)包含上传的临时文件。——以上方法,如果PHP配置了open_basedir,则很可能会失效。但PHP创建的上传临时文件,往往处于PHP允许访问的目录范围内。该临时文件的文件名是随机的,但并没有使用安全的随机函数,所以可以使用暴力破解文件名。
  • (7)包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等,需要具体情况具体分析。

2.变量覆盖漏洞

2.1 全局变量覆盖

  • 变量如果未被初始化,且能被用户所控制,那么很可能会导致安全问题,而在PHP中,这种情况在register_globals为ON时尤为严重。

2.2 extract()变量覆盖

  • extract()函数能将变量从数组导入当前的符号表。当extract()函数从用户可以控制的数组中导出变量时,可能发生变量覆盖。
  • 安全做法是确定register_globals=OFF后,在调用extract()时使用ECTR_SKIP参数保障已有变量不会被覆盖,并且extract()的来源数组不能被用户控制。

2.3 遍历初始化变量

  • 常见的一些以遍历的方式释放变量的代码,可能导致变量覆盖。

2.4 import_request_variables变量覆盖

  • bool import_request_variable( string $types [, string $prefix])
  • import_request_variables()将GET、POST、Cookie中的变量导入到全局,使用这个函数只需要简单地指定类型即可。其中第二个参数是为导入的变量添加的前缀,如果没有指定,则将覆盖全局变量。

2.5 parse_str()变量覆盖

  • parse_str()函数往往被用于解析URL的query string,但是当参数值能被用户控制时,很可能导致变量覆盖。

2.6 防御变量覆盖

  • (1)确保register_globals=OFF。若不能自定义php.ini,则应该在代码中控制。
  • (2)熟悉可能造成变量覆盖的函数和方法,检查用户是否能控制变量的来源。
  • (3)养成初始化变量的好习惯。

3.代码执行漏洞

  • 条件(1)用户能够控制函数输入(2)存在可以执行代码的危险函数。

3.1 “危险函数”执行代码

  • 危险函数popen()、system()、passthru()、exec()等都可以直接执行系统命令。
  • 此外,eval()函数也可以执行PHP代码。
  • 3.1.1 phpMyAdmin 3.4.3.1 远程代码执行漏洞——这是一个典型的parse_str()覆盖变漏洞。
  • 3.1.2 MyBB 1.4 远程代码执行漏洞——这是一个间接控制eval()函数输入的漏洞。
  • 挖掘此类漏洞的过程,通常需要先找到危险函数,然后回溯函数的调用过程,最终看整个调用的过程中用户是否有可能控制输入。

3.2 “文件写入”执行代码

  • 在PHP中对文件的操作一定要谨慎,如果文件操作的内容用户可以控制,则也极容易成为漏洞。

3.3 其他执行代码方式

(1)直接执行代码的函数

  • 比如eval()、assert()、system()、exec()、shell_exec()、passthru()、escapeshellcmd()、pcntl_exec()等。
  • 最好禁用这些函数。在审计代码时可以检查代码中是否存在这些函数,然后回溯危险函数的调用过程,看用户是否可以控制输入。

(2)文件包含

  • 高度关注能够包含文件的函数:include()、require()、include_once()、require_once()。

(3)本地文件写入

  • 重点关注能够往本地文件里写入内容的函数,比如file_put_contents()、fwrite()、fputs()等。
  • 注意,写入文件的功能可以和文件包含、危险函数执行等漏洞结合,最终使得原本用户无法控制的输入变成可控。在代码审计时要注意这种“组合类”漏洞。

(4)preg_replace()代码执行

  • preg_replace()的第一个参数如果存在/e模式修饰符,则允许代码执行。
  • 当第一个参数中包含变量,并且用户可控,有可能通过注入/e%00的方式截断文本,注入一个“/e”。

(5)动态函数执行

  • 用户自定义的动态函数可以导致代码执行,需要注意这种情况。

(6)Curly Syntax

  • PHP的Curly Syntax也能导致代码执行,它将执行花括号间的代码,并将结果替换回去。

(7)回调函数执行代码

  • 很多函数都可以执行回调函数,当回调函数用户可控时,将导致代码执行。
  • 可以执行回调函数的函数有array_map()、ob_start()等。

(8)unserialize()导致代码执行

  • unserialize()函数可以将序列化的数据重新映射为PHP变量。但是unserialize()在执行时如果定义了__destruct()函数,或者是__wakeup()函数,则这2个函数将执行。
  • unserialize()代码执行有2个条件,一是unserialize()的参数用户可以控制,这样可以构造出需要反序列化的数据结构;二是存在__destruct()函数或者是__wakeup()函数,这2个函数实现的逻辑决定了能执行什么样的代码。

4.定制安全的PHP环境

通过配置php.ini加固PHP的运行环境。

  • (1)设置register_globals=OFF,防止出现变量覆盖问题。
  • (2)给open_basedir设置一个值,限制PHP只能操作指定目录下的文件。
  • (3)设置allow_url_include=OFF,allow_url_fopen=OFF,以对抗远程文件包含。
  • (4)正式环境中设置display_errors=OFF,log_errors=ON,关闭错误回显,将错误信息记录在日志中。
  • (5)推荐magic_quotes_gpc=OFF。
  • (6)若PHP是以CGI的方式安装,则需要关闭cgi.fix_pathinfo选项(cgi.fix_pathinfo=0),以避免出现文件解析问题。
  • (7)设置session.cookie_httponly=1,开启HttpOnly。
  • (8)若是全站HTTPS则请开启session.cookie_secure选项(session.cookie_secure=1)。
  • (9)如果是共享环境(比如APP Engine)则建议开启安全模式safe_mode(它会影响很多函数),和disable_functions配合使用;如果是单独的应用环境,则可以考虑关闭它,更多地依赖于disable_functions控制运行环境安全。
  • (10)disable_functions能够在PHP中禁用函数。

九 Web Server配置安全

1.Apache安全

  • (1)检查Apache安全的第一件事情,就是检查Apache的Module安装情况,根据“最小权限原则”,应该尽可能地减少不必要的Module,对于要使用的Module,则检查其对应版本是否存在已知的安全漏洞。
  • (2)使用单独的低权限用户身份运行Apache,这个用户身份不应该具备shell(一定不要使用root或者admin身份),它唯一的作用就是用来运行Web。
  • (3)Apache还提供了一些配置参数,可以用来优化服务器的性能,提高对抗DDOS攻击的能力。
  • (4)要保护好 Apache Log。比如实时地发送到远程的syslog服务器上等,防止黑客入侵后修改、删除入侵痕迹。

2.Nginx安全

  • (1)多多关注Nginx的漏洞信息,并及时将软件升级到安全的版本。
  • (2)使用单独的用户身份运行Nginx。
  • (3)调整Nginx配置参数,以缓解一些DDOS和CC攻击。

3.jBoss远程命令执行

  • JBoss有一个管理后台——JMX-Console,默认安装的JMX-Console是没有任何认证的,黑客可以通8080端口访问/jmx-console进入到这个管理界面。在JMX-Console中,有多种可以远程执行命令的方法,最简单的方法就是通过DeploymentScanner远程加载一个war包。或者通过JMX-Console提供的BSH Deployment方法,同样也可以部署war包。
  • 在加固时,需要删除JMX-Console后台,如果因为业务需要不得不使用JMX-Console,则应该使用一个强壮的密码,且运行JMX-Console的端口不应该面向整个Internet开放。

4.Tomcat远程命令执行

  • Tomcat的Tomcat Manager作用与JMX-Console类似,管理员也可以在Tomcat Manager中部署war包。庆幸的是,Tomcat Manager部署war包需要有manager权限,而这一权限是在配置文件中定义的。需要由管理员修改此文件,定义出manager角色。但是像下面这种配置,就存在安全隐患了。
  • <role rolename="manager"/>
  • <user username="tomcat" password="tomcat" roles="tomcat,manager"/>
  • 它直接将Tomcat用户添加为manager角色,而Tomcat用户的密码很可能是一个默认密码,这种配置违背了“最小权限原则”。
  • 加固时,强烈建议删除这一后台。

5.HTTP Parameter Pollution

  • HPP攻击原理:通过GET或者POST向服务器发起请求时,提交两个相同的参数,比如提交/?a=test1&a=test2,某些服务器环境中,会只取第一个参数或者只取第二个参数,而在另外一些环境中,比如.net环境中,则会变成:a=test1,test2。利用这种特性,攻击者可以构造一些参数值绕过一些服务器的逻辑判断。
  • 比如如下代码:/index.aspx?page=select 1& page=2,3 from table where id=1,通过HPP混淆参数,从而绕过ModSecurity对于SQL注入的检测。

第四篇 互联网公司安全运营 

一 互联网业务安全

1.产品需要什么样的安全

  • 如果我们的产品能够潜移默化地培养用户的安全习惯,将用户往更安全的行为上引导,那么这样的安全就是最理想的产品安全。

2.业务逻辑安全

3.账户是如何被盗的

4.互联网的垃圾

  • 垃圾注册、垃圾消息等的危害及处理

5.关于网络钓鱼

  • 5.1 钓鱼网站简介
  • 5.2 邮件钓鱼
    • 目前有许多识别发件人邮箱的安全技术,大部分都是基于域名策略的,比如SPF、雅虎的DomainKeys、微软的Sender ID技术等。
  • 5.3 钓鱼网站的防控
    • (1)控制钓鱼网站的传播途径
    • (2)直接打击钓鱼网站
    • (3)用户教育
    • (4)自动化识别钓鱼网站
  • 5.4 网购流程钓鱼

6.用户隐私保护

二 安全开发流程(SDL)

1.SDL简介

  • SDL全称是Security Development Lifestyle,即安全开发生命周期。它是由微软最早提出的。
  • 微软的SDL过程大致分为16个阶段:
    • 培训(1核心安全培训)-->
    • 要求(2确定安全要求、3创建质量门/bug栏、4安全和隐私风险评估)-->
    • 设计(5确定设计要求、6分析并减小攻击面、7威胁建模)-->
    • 实施(8使用指定的工具、9弃用不安全的函数、10静态分析)-->
    • 验证(11动态代码分析、12模糊测试、13攻击面评析)-->
    • 发布(14事件响应计划、15最终安全评析、16发布存档)-->
    • 响应(17执行时间响应计划)

2.敏捷SDL

  • SDL适用于采用瀑布法进行开发的软件开发团队,微软为敏捷开发专门设计了敏捷SDL,以变化的观点实施安全工作。

3.SDL实战经验

  • (1)与项目经理进行充分沟通,排出足够的时间。
  • (2)规范公司的立项流程,确保所有项目都能通知到安全团队,避免遗漏。
  • (3)树立安全部门的权威,项目必须由安全部门审核完成后才能发布。
  • (4)将技术方案写入开发、测试的工作手册中。
  • (5)给工程师培训安全方案。
  • (6)记录所有的安全bug,激励程序员编写安全的代码。

4.需求分析与设计阶段

  • 此阶段,安全工程师需要关心产品主要功能上的安全强度和安全体验是否足够,主要需要思考安全功能。另外,可以对项目经理、产品经理或者架构师进程访谈,以了解产品背景和技术架构,并给出相应建议。

5.开发阶段

  • 开发阶段应该力求代码实现上的安全,做到“安全的功能”。

5.1 提供安全的函数

  • 将安全方案写入开发规范中,真正地让安全方案落地。

5.2 代码安全审计工具

  • 目前还没有比较完美的自动化代码审计工具,代码审计工具的结果仍需要人工处理。耗费人力。
  • 实际上,对于甲方公司来说,完全可以根据开发规范来定制代码审计工具。其核心思想是,并非直接检查代码是否安全,而是检查开发者是否遵守了开发规范。

6.测试阶段

  • 安全测试,一般分为自动化测试和手动测试2种方式。
  • 自动化测试以覆盖性的测试为目的,可以通过“Web安全扫描器”对项目或产品进行漏洞扫描。比如Appscan、skipfish等。
  • 通过扫描器产生的安全报告可能会存在误报与漏报,需要经过安全工程师确认,并结合手动测试的结果,最终形成一份安全测试报告。

三 安全运营

1.把安全运营起来

  • 安全是一个持续的过程,而“安全运营”的目的,就是把这个“持续的过程”执行起来。
  • 公司安全的发展蓝图可以分为“Find and Fix”、“Defend and Defer”和“Secure at the source”三个方向,每一个方向的最终结果都需要由“安全运营”来保证。

2.建立漏洞修补流程

  • (1)建立类似bugtracker的漏洞跟踪机制,并为漏洞的紧急程度选择优先级;
  • (2)建立漏洞分析机制,并与程序员一起制定修补方案,同时review补丁的代码实现;
  • (3)对曾经出现的漏洞进行归档,并定期统计漏洞修补情况。

3.安全监控

4.入侵检测

  • 常见的安全监控产品有IDS(入侵检测系统)、IPS(入侵防御系统)、DDOS监控设备等。
  • 相对于传统的IDS,WAF(Web应用防火墙)专注于应用层攻击的检测和防御。
  • 优秀的开源WAF有ModSecurity、PHPIDS等。
  • ModSecurity是Apache的一个Module,它能获取到所有访问Apache Httped Server的请求,并根据自己的规则对这些请求进行匹配,以检测哪些请求存在攻击行为。
  • PHPDIS是为PHP应用设计的一套入侵检测系统,它与应用代码的结合更为紧密,需要修改应用代码才能加载并使用它。

5.紧急响应流程

  • 紧急响应流程就是在发生紧急安全事件时,需要启动一个用户快速处理事件的流程。
  • 当安全事件发生时,首先应该通知到安全专家,并由安全专家着急紧急响应现在,处理相关问题。

(完)

上一篇:增加用户为SiteCollection的管理员


下一篇:Iterator(迭代器)的使用