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

第一篇:世界观安全

第一章:我的安全世界观

一个网站的数据库,在没有任何保护的情况下,数据库服务端口是允许任何人随意连接的;在有了防火墙的保护后,通过ACL可以控制只允许信任来源的访问。这些措施在很大程度上保证了系统软件处于信任边界之内,从而杜绝了绝大部分的攻击来源。

1.1.3Web安全的兴起

常见攻击:SQL注入,XSS(跨站脚本攻击)

“破坏往往比建设容易”,但凡事都不是绝对的。一般来说,白帽子选择的方法,是克服某种攻击方法,而并非抵御单次的攻击。比如设计一个解决方案,在特定环境下能够抵御所有已知的和未知的SQL Injection问题。假设这个方案的实施周期是3个月,那么执行3个月之后,所有的SQL Injection问题都得到了解决,也就意味着黑客再也无法利用SQL Injection这一可能存在的弱点入侵网站了。如果做到了这一点,那么白帽子们就在SQL Injection的局部对抗中化被动为主动了。

跟机场安全检查进行类比。通过一个安全检查(过滤,净化)的过程,可以梳理未知的人或物,使其变得可信任。被划分出来的具有不同信任级别的区域,我们成为信任域,划分两个不同信任域之间的边界,我们称之为信任边界

数据从高等级的信任域流向低等级的信任域,是不需要经过安全检查的;数据从低等级的信任域流向高等级的信任域,是需要经过信任边界的安全检查。

安全问题的本质是信任的问题

一切的安全方案设计的基础,都是建立在信任关系上的。我们必须相信一些东西,必须要有一些最基本的假设,安全方案才能得以建立

1.5安全的三要素

安全的三要素是安全的基本组成元素,分别为机密性(Confidentiality)完整性(Integrity)可用性(Availability)

机密性要求数据内容不能泄露,加密是实现机密性要求的常见手段。如果不将文件存在抽屉里,而是放在透明的盒子里,那么虽然无法得到这个文件,但是文件的内容将会被泄露。

完整性则要求保护数据内容是完整,没有被篡改的。常见的保证一致性的技术手段是数字签名。

可用性要求保护资源是“随需而得”。

举例来说,假如有100个车位,有一天一个坏人搬了100块大石头将车位全占了,那么停车场无法再提供正常服务。在安全领域中叫做拒绝服务攻击,简称DoS(Denial of Service)。拒绝服务攻击破坏的是安全的可用性。

1.6如何实施安全评估

一个安全评估的过程,可以简单地分为4个阶段:1.资产等级划分2.威胁分析3.风险分析4.确认解决方案

1.6.1资产等级划分

资产等级划分是所有工作的基础,这项工作能够帮助我们明确目标是什么,要保护什么。

互联网安全的核心问题,就是数据安全的问题

1.6.2威胁分析

在安全领域,我们把可能造成危害的来源成为威胁(Threat),而把可能会出现的额损失称为风险(Risk)。

威胁分析: 
1.头脑风暴 
2.STRIDE模型 

Spoofing 伪装
Tampering 篡改
Repudiation 抵赖
InformationDisclosure 信息泄露
Denial of Service 拒绝服务
Elevation of Privilege 提升权限
笔记《白帽子讲Web安全》吴翰清


1.6.2风险分析

风险是由以下因素组成: 
Risk=Probability * Damage Potential

衡量风险: 
1.DREAD模型 
笔记《白帽子讲Web安全》吴翰清

1.7白帽子兵法

1.7.1Secure By Default原则

白名单,黑名单

实际上,Secure By Default原则,也可以归纳为白名单,黑名单的思想如果更多地使用白名单,那么系统就会变得更安全

最小权限原则

最小原则要求系统只授予主体必要的权限,而不要过度授权,这样能有效地减少系统,网络,应用,数据库出错的机会。

如果网站只提供Web服务,只允许开启80,443端口,屏蔽其它端口。

纵深防御原则

纵深防御原则包含两层含义

1.要在各个不同层面,不同方面实施安全方案,避免出现疏漏,不同安全方案之间需要相互配合,构成一个整体;

2.要在正确的地方做正确的事情,即:在解决根本问题的地方实施针对性的安全方案。

1.7.3数据与代码分离原则

这一原则适用于各种由于“注入”而引发安全问题的场景

实际上,缓冲区溢出,也可以认为是程序违背了这一原则的后果——程序在栈或者堆中,将用户数据当做代码执行,混淆了代码与数据的边界,从而导致安全问题的发生。

1.7.4不可预测性原则

微软使用的ASLR技术,在较新版本的Linux内核中也支持。在ASLR的控制下,一个程序每次启动时,其进程的栈基址都不相同,具有一定的随机性,对于攻击者来说,这就是“不可预测性”。

不可预测性,能有效地对抗基于篡改,伪造的攻击。

不可预测性的实现往往需要用到加密算法,随机数算法,哈希算法,好好利用这条规则,在设计安全方案时往往会事半功倍。

1.8小结

第二篇:客户端脚本安全

第二章:浏览器安全

一些主要浏览器的安全功能

2.1同源策略

这一策略极其重要,如果没有同源策略,可能a.com的一段JS脚本,在b.com未曾加载此脚本时,也可以随意修改b.com的页面(在浏览器显示中)。为了不发生混乱,浏览器提出“Origin”(源)的概念。来自不同Origin的对象无法相互干扰。 
 笔记《白帽子讲Web安全》吴翰清
从上表可以看出,影响”源”的因素有:

1.host(域名或IP地址) 
2.子域名 
3.端口 
4.协议

需要注意的是,对于当前页面来说,页面内存放JS文件的域并不重要,重要的是加载JS的页面所在的域是什么。举例说明: 
a.com通过代码<script src=http://b.com/b.js ></script>加载了b.com上的b.js。因为b.js是运行在a.com上的,所以b.js的域就是a.com。

在浏览器中,<script>,<img>,<iframe>,<link>等标签都可以跨域加载资源,而不受同源策略的限制。这些带”src”属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JS的权限,使其不能读,写返回的内容。

对于XMLHttpRequest,它收到同源策略的约束,不能跨域访问资源,在AJAX应用的开发中尤其需要注意到这一点。

2.2浏览器沙箱

2.3恶意网站拦截

2.4高速发展的浏览器安全

第三章:跨站脚本攻击(XSS)

3.1XSS简介

跨站脚本攻击,英文全称为Cross Site Script,在安全领域叫做”XSS”。XSS攻击,通常指黑客通过”HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。

XSS根据效果的不同可以分为如下几类。

一:反射型XSS

反射型XSS只是简单地把用户输入的数据“反射”给浏览器。也就是说,黑客往往需要诱使用户“点击”一个恶意链接,才能攻击成功。反射型XSS也叫做“非持久型XSS”(Non-persistent XSS)。

二:存储型XSS

存储型XSS会把用户输入的数据“存储”在服务器端。这种XSS具有很强的稳定性。也叫做“持久型XSS”(Persistent XSS)。

三:DOM Based XSS

通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。

3.2XSS攻击进阶

可以利用XSS payload来窃取Cookie。但”Cookie劫持”并非所有的时候都会有效,有的网站可能会在Set-Cookie时给关键的Cookie**植入HttpOnly标识;有的网站会把Cookie与客户端IP绑定**。


XSS构造技巧
(1)利用字符编码
GBK 占2个字节,Utf一个字节,因为编码不同,可以让转码符号发生截断,让其无效。
(2)绕过长度限制
A.利用事件,但缩短的字符是有限的
B.代码加载
C.使用location.hash藏代码,location.hash的内容不会在Http包中发送。
location.hash本身没有长度限制,但输入栏是有限制的,如果输入栏长度都不够还可以加载远程js
D.使用注释符
(3)使用<base>标签
base标签定义页面上相对路径,作用于标签后面的所有元素。
(4)window.name
对window.name 赋值没有符号限制,window属于浏览器窗体,而不是document对象,不受同源策略限制。

Mission impossible
Apache Expect Header XSS
使用flash构建带XSS请求头

Anehta 回旋镖
将反射型的XSS嵌入到存储型的XSS中

容易忽视的Flash XSS
Flash是可以嵌入ActionScript脚本,可以发起网络请求。
解决:
实现XSS Filter时禁用<embed> <object> 等标签。
仅仅是视频文件要求转成flv文件。
带动态脚本的Flash配置参数限制。
一个重要的参数allowscriptaccess 定义Flash能否跟Html页面通讯

值:

always 总是

sameDomain 默认,同源,要确保Flash不是用户上传的

never 禁止

参数 allowNetworking 控制Flash能否访问网络

all 默认,允许所有网络

internal 不能与浏览器通信,但可以调用其它Api

none 禁止任何网络通信


javaScript开发框架XSS漏洞

Dojo 的 Dom Bsaed XSS

YUI 的 Dom Bsaed XSS

jQuery html() 方法


3.3XSS的防御

1.四两拨千斤:HttpOnly

浏览器将禁止页面的JS访问带有HttpOnly属性的Cookie。只能防止XSS后的Cookie劫持攻击。

一个Cookie的使用过程如下:

STEP1.浏览器向服务器发起请求,这个时候没有Cookie 
STEP2.服务器返回时发送Set-Cookie头,向客户端浏览器写入Cookie 
STEP3.在该Cookie到期前,浏览器访问该域下的所有页面,都将发送该Cookie

在java EE中,给Cookie设置HttpOnly代码如下:

response.setHeader("Set-Cookie","cookieName=value;path=/;Domain=domainValue;Max-Age=seconds;HTTPOnly");

HttpOnly的作用是为了防止Cookie被劫持 ,添加了HttpOnly不等于解决了XSS问题。

XSS攻击带来的不光是Cookie劫持的问题,还有窃取用户信息,模拟用户身份执行操作等诸多严重的后果。如前文所述,攻击者利用AJAX构造HTTP请求,以用户身份完成的操作,就是在不知道用户Cookie的情况下进行的。

多个Cookie可以针对认证相关的Cookie设置HttpOnly。

使用HttpOnly有助于缓解XSS攻击,但仍然需要其他能够解决XSS漏洞的方案。


2.输入检查

常见的Web漏洞如XSS,SQL Injection等,都要求攻击者构造一些特殊字符,这些特殊字符可能是正常用户用不到的,所以输入检查就有必要了。

格式检查,有点像一种”白名单”,也可以让一些基于特殊字符的攻击失效。

输入检查的逻辑,必须放在服务器端代码中实现。如果只是在客户端使用JS进行输入检查,是很容易被攻击者绕过的。

目前Web开发的普遍做法,是同时在客户端JS中和服务器端代码中实现相同的输入检查。客户端JS的输入检查,可以阻挡大部分误操作的正常用户,从而节约服务器资源。

比较智能的”输入检查”,会匹配XSS的特征。这种输入检查的方式,可以称为”XSS Filter”。有很多”XSS Filter”的实现。

XSS Filter在用户提交数据时获取变量,并进行XSS检查;但此时用户数据并没有结合渲染页面的HTML代码,因此XSS Filter对语境的理解并不完整

XSS攻击主要发生在MVC架构中的View层。大部分的XSS漏洞可以在模板系统中解决。比如Python的开发框架Django自带的模板系统”Django Templates”,或者其他的”Thymeleaf Templates”。


3.输出检查

使用编码或转义 

Html代码编码:HtmlEncode

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

JavaScript编码:JavascriptEncode

使用JavascriptEncode的变量输出还要包含在引号内。

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

输出:
笔记《白帽子讲Web安全》吴翰清

第二个是安全的

注意:编码后的代码长度会发生变化,要注意某些功能的限制

如果网站使用了MVC架构,那么XSS就发生在View层——在应用拼接变量到HTML页面时产生。所以在用户提交数据处进行输入检查的方案,其实并不是在真正发生攻击的地方做防御。

并不是使用了编码就可以防范XSS攻击了,防范XSS攻击需要看应用的场景。

例子:

<body>

<a href="#" onclick="alert('$var');">test</a>

</body>

$var = htmlencode("');alert('2");

对变量进行HtmlEncode之后:

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

对浏览器来说htmlparser优先于JavaScript Parser执行。执行流程就是先解码再执行JavaScript代码,上面的编码就是没有意义的。
经过解码之后:
笔记《白帽子讲Web安全》吴翰清
会执行XSS代码

3.正确地防御XSS

为了更好设计XSS防御方案,需要了解其本质。

XSS的本质还是一种“HTML注入”用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义

常见的场景

在HTML标签中输出

<div>$var</div>

<a href=#>$var</a>


在HTML属性中输出

<div id="abc" name="$var"></div>


在<script>标签中输出

攻击者需要闭合引号才能实施XSS攻击

<script>

var c = "";alert(/XSS/);//";

</script>

使用JavascriptEncode防御


在事件中输出

在<script>标签中输出类似

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


在CSS中输出

形成XSS的方式多样化

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


尽可能禁止用户可控变量在<style>标签,html标签的style属性以及css文件中输出。
可使用OWASP ESAPI严格的encodeForCSS()函数。

在地址中输出
在URL的path或参数输出,使用URLEncode
笔记《白帽子讲Web安全》吴翰清
如果整个URL都能被用户控制,是不能使用URLEncode的,因为协议部分的特殊符号会被转码出现语意不符。
如果整个URL都能被用户控制,先检查变量是否以http开头(如果不是则添加Http头),,再对变量进行URLEncode,就可以保证不会XSS

3.3.5 处理富文本
标签处理:使用白名单,比如只允许<a><img><div>等比较安全的标签。
CSS处理:需要一个CSS Parser对样式进行过滤。

开源XSS Filter :Anti-Samy
php开源 :HTMLPurify

3.3.6 防御Dom Based XSS
从Javascript中输出数据到Html页面里,也相当于一次XSS输出过程。
在$var 变量输出到<script>时,进行一次javascriptEncode,在document.write输出到HTML页面时,如果是输出到事件或脚本,则要再做一次javascriptEncode,如果是输出到HTMl内容或属性,则要做一次HtmlEncode。
笔记《白帽子讲Web安全》吴翰清

服务器端从Javascript中输出数据到Html页面的几个必经之路,重点关注参数是否容易被控制:
document.write()
document.writeln()
xxx.innerHTML = 
xxx.outerHTML = 
innerHTML.replace
document.attachEvent()
window.attachEvent()
document.location.replace()
document.location.assign()
...
还有几个容易成为输入点的地方:
页面中所有的inputs框
window.location(href、hash等)
window.name
document.referrer
document.cookie
localstorage
XMLHttpRequest 返回的数据
...

3.3.7换个角度看XSS的风险

一般来说,存储型XSS的风险会高于反射型XSS。因为存储型XSS会保存在服务器上,有可能会跨页面存在。

从攻击过程来说,反射型XSS,一般要求攻击者诱使用户点击一个包含XSS代码的URL链接;而存储型XSS,则只需要让用户查看一个正常的URL链接,比如一个Web邮箱的邮件正文页面存在一个存储型的XSS漏洞,当页面打开一封新邮件时,XSS Payload会被执行。这样的漏洞极其隐蔽,且埋伏在用户的正常业务中,风险颇高。

第四章:跨站请求伪造(CSRF)

CSRF的全名是Cross Site Request Forgery,翻译成中文就是跨站点请求伪造。

4.2CSRF进阶

在上节提到的例子里,攻击者伪造的请求之所以能够被搜狐服务器验证通过,是因为用户的浏览器成功发送了Cookie的缘故。

浏览器所持有的Cookie分为两种:一种是“Session Cookie”,又称”临时Cookie”;另一种是”Third-party Cookie”,也称为“本地Cookie”

两者的区别在于:

Third-party Cookie是服务器在Set-Cookie时指定了Expire时间,只有到了Expire时间后Cookie才会失效,所以这种Cookie会保存在本地,而Session Cookie则没有指定Expire时间,所以浏览器关闭后,Session Cookie就失效了

在浏览网站的过程中,若是一个网站设置了Session Cookie,那么在浏览器进程的生命周期内,即使浏览器新打开了Tab页,Session Cookie也都是有效的。Session Cookie保存在浏览器进程的内存空间中,而Third-party Cookie则保存在本地。

如果浏览器从一个域的页面中,要加载另一个域的资源,由于安全的原因,某些浏览器会阻止Third-party Cookie的发送

举例说明:

http://www.a.com/cookie.php中,会给浏览器写入两个Cookie,一个为Session Cookie,一个为Third-party Cookie。

<?php
header("Set-Cookie:cookie1=123;");
header("Set-Cookie:cookie2=456;expires=Thu,01-Jan-2030 00:00:01 GMT;",false);
 ?>

访问该页面,发现浏览器同时接收了这两个Cookie。

这时再打开一个新的浏览器Tab页,访问同一个域中的不同页面。因为新Tab页在同一个浏览器进程中,因此Session Cookie将被发送

此时在另外一个域中,有一个页面http://www.b.csrf-test.html,此页面构造了CSRF以访问www.a.com。

<iframe src="http://www.a.com"></iframe>

这时会发现,只能发送出Session Cookie,而Third-party Cookie被禁止了。

对于第三方Cookie的默认拦截策略,不同浏览器的策略不一样,不能一概而论。

若CSRF攻击的目标并不需要使用Cookie,那也不必顾虑浏览器的Cookie策略了。

p3p 头的副作用

设置了p3p头,将允许浏览器发送第三方Cookie,在IE下即使是<iframe><script>等标签也不再拦截。

4.3CSRF的防御

1.验证码

验证码被认为是对抗CSRF攻击最简洁而有效的防御方法。

CSRF攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码,则强制用户必须与应用进行交互,才能完成最终请求,因此在通常情况下,验证码能够很好地遏制CSRF攻击。 
出于用户体验考虑,网站不能给所有的操作都加上验证码。因此,验证码只能作为防御CSRF的一种辅助手段。

2.Referer Check

源检查

3.Anti CSRF Token

业界针对CSRF的防御,一致的做法是使用一个Token。

CSRF的本质:

CSRF为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜测到的

攻击者只有预测出URL的所有参数与参数值,才能成功地构造一个伪造的请求;反之,攻击者将无法攻击成功。

出于这个原因,可以想到一个解决方案:把参数加密,或者使用一些随机数,从而让攻击者无法猜测到参数值,这是”不可预测性原则”的一种应用。

举例说明,一个删除操作的URL是:

http://host/path/delete?username=abc&item=123

把其中的username参数改成哈希值:

http://host/path/delete?username=md5(salt+abc)&item=123

这样在攻击者不知道salt的情况下,是无法构造出这个URL的。

但是!这个方法存在一些问题。

1.加密或混淆后的URL变得非常难读,对普通用户非常不友好; 
2.如果加密的参数每次都改变,则某些URL无法被用户收藏; 
3.普通的参数如果也被加密或者哈希,会给数据分析工作带来很大的困扰。

更常用的方案就是要讲的Anti CSRF Token

会上面的URL中,新增加一个参数Token。这个Token的值是随机的,不可预测:

http://host/path/delete?username=md5(salt+abc)&item=123&token=[random(seed)]

Token需要足够随机,必须使用安全的随机数生成算法,或者采用真随机数生成器(物理随机)。Token应该作为一个”秘密”,为用户与服务器所共同持有,不能被第三者知晓。在实际应用中,Token可以放在用户的Session中,或者浏览器的Cookie中

Token需要同时放在表单和Session中。这提交请求时,服务器只需验证表单中的Token,与用户Session(或Cookie)中的Token是否一致。

在使用Token时,应该尽量把Token放在表单中。把敏感操作由GET改为POST,以form表单(或者AJAX)的形式提交,可以避免Token泄露。

4.4总结

CSRF攻击是攻击者利用用户的身份操作用户账户的一种攻击方式。

第五章:点击劫持(clickjacking)

5.1 点击劫持

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

5.2  Flash 点击劫持

5.3  图片覆盖攻击

5.4  拖拽劫持与数据窃取

拖拽不受同源策略影响

5.5 ClickJacking 3.0 触屏劫持

可以写一段 JavaScript 代码,以禁止 iframe 的嵌套。 这种方法叫frame busting。
if ( top.location != location ) {
top.location = self.location;
} 

常见的frame busting
if (top != self)
if (top.location != self.location)
if (top.location != location)
if (parent.frames.length > 0)
if (window != top)
if (window.top !== window.self)
if (window.self != window.top)
if (parent && parent != window)
if (parent && parent.frames && parent.frames.length>0)
if((self.parent&&!(self.parent===self))&&(self.parent.frames.length!=0))
top.location = self.location
top.location.href = document.location.href
top.location.href = self.location.href
top.location.replace(self.location)
top.location.href = window.location.href
top.location.replace(document.location)
top.location.href = window.location.href
top.location.href = "URL"
document.write('')
top.location = location 
top.location.replace(document.location)
top.location.replace('URL')
top.location.href = document.location
top.location.replace(window.location.href)
top.location.href = location.href
self.parent.location = document.location
parent.location.href = self.document.location
top.location.href = self.location
top.location = window.location
top.location.replace(window.location.pathname)
window.top.location = window.self.location
setTimeout(function(){document.body.innerHTML='';},1);
window.self.onload = function(evt){document.body.innerHTML='';}
var url = window.location.href; top.location.replace(url) 

frame busting 方法因为是JavaScript写的,控制能力并不是很强。
对parent.location 的frame busting,可以嵌套多个iframe绕过
如:
if ( top.location != self.location) {
parent.location = self.location ;
} 
下面绕过frame busting
Attacker top frame:
<iframe src="attacker2 .html">
Attacker sub-frame:
<iframe src="http://www.victim.com"> 

限制iframe页面JavaScript脚本执行也可使frame busting失效。

5.6 X-Frame-Options
frame busting可以被绕过,比较好的方案是使用一个HTTP头X-Frame-Options。
3个参数:
DENY 拒绝当前页面加载任何frame页面
SAMEORIGIN 只能是同源域名下的frame页面
ALLOW_FROM origin 定义可以加载的frame页面地址

第六章:HTML5安全

Html5 新增的标签和属性,容易出现新的XSS漏洞

6.1.2 iframe 的sandbox
Html5 专门为iframe定义的新属性sandbox,<iframe>加载的内容被视为一个独立的源,脚本被禁止执行,表单被禁止提交,插件被禁止加载,指向其它浏览器的链接也被禁止。
设置参数更精确的控制
笔记《白帽子讲Web安全》吴翰清
有的行为即使设置了allow-scripts也是无效的,例如弹出窗口
笔记《白帽子讲Web安全》吴翰清
6.1.3 Link Types:noreferrer
HTML5 为<a><area>标签定义新属性:Link Types:noreferrer
作用:浏览器请求地址不再发送Referer
<a href="xxx" rel="noreferrer">test</a>

6.1.4 Canvas 妙用 **验证码

6.2 其它安全问题
6.2.1 Cross-Origin Resource Sharing
W3C 定义新跨域请求标准

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

请求必须带上一个Origin Header,服务器回返回Access-Control-Allow-Origin:* 表示允许跨域请求。使用通配符*等于不实用任何安全限制,是很危险的。

6.2.2 postMessage 跨窗口传递消息
postMessage 允许每一个window对象往其它窗口发送消息,不受同源策略限制。

6.2.3 Web Storage
以前浏览器存储信息的方式:
Cookie
Flash Shared Object --- Adobe和微软自己的功能
IE UserData --- Adobe和微软自己的功能

W3C 提出的Web Storage,受同源策略限制,每个域的信息只保存在自己的域下。
Web Storage 分为 Session Storage和Local Storage。
Session Storage 关闭浏览器就会失效,由Key-Value 对组成。
使用方式:
设置:window.sessionStorage.setItem(key,value);
读取:window.sessionStorage.getItem(key);

Firefox单独实现的globalStorage,基于SQLite
window.globalStorage.namedItem(domain).setItem(key,value);

第三篇:服务器端应用安全

第七章:注入攻击

注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件

1.用户能够控制输入 
2.原本程序要执行的代码,拼接了用户输入的数据

7.1SQL注入

在SQL注入的过程中,如果网站的Web服务器开启了错误回显,则会为攻击者提供极大的便利。

7.1.1盲注(Blind Injection)

没有错误回显的情况,实行盲注

举例说明: 
一个应用的URL如下:

http://newspaper/items.php?id=2

执行的SQL语句为:

SELECT title,body FROM items WHERE ID=2

如果攻击者构造如下的条件语句:

http://newspaper/items.php?id=2 and 1=2

实际执行的SQL语句为:

SELECT title,body FROM items WHERE ID=2 and 1=2

“and 1=2”永远是一个假命题,攻击者将看到一个空的结果或者出错页面。 
为了进一步确认注入是否存在,还要构造”and 1=1”,如果能够返回,说明该参数存在SQL注入漏洞!

7.1.2 Timing Attack

7.2 攻击技巧

7.2.1 注入

7.2.2 命令行

用户自定义函数(UDF)来执行命令

7.2.3 攻击存储过程

7.2.4 编码问题

编码不同的差异会发生数据解析的差异

解决:统一数据库、操作系统、web应用的字符集。

HTML页面的<meta>指定页面的编码格式。

无法统一字符编码,需要单独实现过滤或转义的安全函数,检测字符的可能范围:

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


7.2.5 SQL Column Truncation
MySQL配置项中,有一个sql_mode选项,设置为default时(没开启STRICT_ALL_TABLES),对于插入数据长度超出范围发出waring,数据会发生截断。strict模式下会返回error信息,并且插入不成功。


怎样防御SQL注入呢?

一般来说,防御SQL注入的最佳方式,就是使用预编译语句,绑定变量。也就是常用的用?代替将要填充的值。

还可以使用常用的手段来加固,比如检查数据类型使用安全函数等。

在对抗注入攻击时,只需要牢记”数据与代码分离原则”,在”拼凑”发生的地方进行安全检查,就能避免这方面的问题。

7.4 其它注入攻击

7.4.1 xml注入

7.4.2 代码注入

7.4.3 CRLF注入

CR(ASCII 13,\r) 0x0d

LF(ASCII 10,\n) 0x0a

常用作不同语义的分割符。

HTTP头是通过“\r\n”分割的,如果服务器端没有过滤“\r\n”,而且又把用户输入的数据放在HTTP头中,可能存在隐患。

第八章:文件上传漏洞

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。

“文件上传”功能本身没有问题,但有问题的是文件上传后,服务器怎么处理,解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。

大多数情况下,文件上传漏洞一般都是指“上传Web脚本能够被服务器解析”的问题,也就是通常说的webshell的问题。要完成这个攻击,要满足几个条件:

1.上传的文件能够被Web容器解释执行。所以文件上传后所在目录要是Web容器所覆盖到的路径 
2.用户能够从Web*问这个文件。如果文件上传了,但用户无法通过Web访问,或者无法使得Web容器解释这个脚本,就不能称之为漏洞。 
3.用户上传的文件若被安全检查,格式化,图片压缩等功能改变了内容,则可能导致攻击不成功。

8.1.2 绕过文件上传检查

构造文件名(修改POST包)xxx.php[\0].jpg

[\0]为十六进制的0x00字符,在C、PHP等语言常用字符串处理函数中0x00被认为是终止符。对于服务器端因为截断的关系最终会变成xxx.php

解决:文件头判断文件类型。判断文件前10个字节,确定文件类型

浏览器MIME Sniff功能也是通过读取文件前256个字节数据确定文件的类型。

绕过MIME Sniff功能可以构造假文件头。如果后缀是.jpg,服务器端可能把文件当作静态文件解析而不使用php解析器,导致php无法执行。

8.2.1Apache文件解析问题

Apache1.x Apache2.x 对于文件名的解析是从后往前解析的,直到遇见一个Apache认识的文件类型为止。比如: phpShell.php.rar.rar.rar。 
如果Apache不认识.rar这个文件类型,所以一直遍历后缀到.php,然后认为这时一个PHP类型的文件。如果不考虑这些因素,写出的安全检查功能可能会存在缺陷。比如.rar是一个合法的上传需求,在应用里只判断文件的后缀是否是.rar,最终用户上传的是phpShell.php.rar.rar.rar,从而导致脚本被执行。

Apache默认的定义哪些文件是能够被认识的,是在/conf/web.xml中。

<!-- ===================== Default MIME Type Mappings =================== -->
  <!-- When serving static resources, Tomcat will automatically generate    -->
  <!-- a "Content-Type" header based on the resource's filename extension,  -->
  <!-- based on these mappings.  Additional mappings can be added here (to  -->
  <!-- apply to all web applications), or in your own application's web.xml -->
  <!-- deployment descriptor.                                               -->
  <!-- Note: Extensions are always matched in a case-insensitive manner.    -->
  //如果想添加自定义的mapping,可以在这里添加或者在自己项目中的web.xml中
<mime-mapping>
        <extension>rar</extension>
        <mime-type>application/x-rar-compressed</mime-type>
    </mime-mapping>
<mime-mapping>
        <extension>mp3</extension>
        <mime-type>audio/mpeg</mime-type>
    </mime-mapping>

8.2.2 IIS文件解析问题

IIS 6 分号截断问题

PUT上传脚本问题结合MOVE,能够将上传的文本文件改写成脚本文件。在IIS服务器,勾选“脚本资源访问”开启MOVE方法。

8.2.3 PHP CGI路径解析问题

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

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

8.2.4 利用上传文件钓鱼

钓鱼网站在传播时,会通过利用XSS,服务器端302跳转等功能,从正常的网站跳转到钓鱼网站。在一开始,看到的是正常的域名,但这种钓鱼,仍然会在URL中暴露真实的钓鱼网站地址,细心点的用户可能不会上当,这是一般的钓鱼做法

而利用文件上传功能,钓鱼者可以先将包含了HTML的文件(比如一张图片)上传到目标网站,然后通过传播这个文件的URL进行钓鱼,则URL中不会出现钓鱼地址,更具有欺骗性

8.3设计安全的文件上传功能

总结为3点:

1.文件上传的目录设置为不可执行 
只要Web容器无法解析该目录下的文件,即使攻击者上传了脚本文件,服务器本省也不会收到影响。

在实际应用中,很多大型网站的上传应用,文件上传后会放到独立的存储上,做静态文件处理,一方面方便使用缓存加速,降低性能损耗;另一方面也杜绝了脚本执行的可能

2.判断文件类型

强烈推荐白名单的方式,不再使用黑名单。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。

3.使用随机数改写文件名和文件路径

文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些情况中,用户能上传,但不能访问。如果应用使用随机数改写文件名和文件路径,将极大地增加攻击的成本。

4.单独设置文件服务器的域名

由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml,上传包含JS的XSS利用等问题将得到解决。但能否如此设置,还需要看具体的业务环境。

第九章:认证与会话管理

“认证”是最容易理解的一种安全。最常见的认证方式就是用户名和密码,但认证的手段远远不止于此。

9.1Who am I?

认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么

钥匙在认证的过程中,被称为“凭证”(Credential),开门的过程,对应的是登录(Login)

可是开门之后,什么事情能做,什么事情不能做,就是“授权”的管理范围了。

开门之后,“能否进入卧室”这个权限被授予的前提,是需要识别出来的人到底是主人还是客人,所以如何授权是取决于认证的

持有主人钥匙的人一定是主人吗?钥匙仅仅是一个很脆弱的凭证,其他的有诸如指纹,人脸,声音等生物特征来识别一个人的凭证。

认证实际上就是一个验证凭证的过程

9.2密码那些事儿

密码的保存:

密码必须以不可逆的加密算法,或者是单向散列函数算法,加密后存储在数据库中

彩虹表的思路是收集尽可能多的密码明文和明文对应的MD5值。这样只需要查询MD5值,就能找到该MD5值对应的明文。

在计算密码明文的哈希值时,增加一个“Salt”。“Salt”是一个字符串,它的作用是增加明文的复杂度,并使得彩虹表一类的攻击失效

Salt的使用如下:

MD5(Username+Password+Salt)

其中,Salt=acjjfdk…(随机字符串)

Salt应该保存在服务器端的配置文件中,并妥善保管

9.3 多因素认证

9.4 Session与认证

登陆:密码 证书多种认证方式

认证成功后,用户在整个网站的的凭证就是使用SessionID

SessionID加密后保存在Cookie中,因为Cookie会随着HTTP请求头发送,且受到浏览器同源策略的保护。还可以保存在URL中。

SessionID一旦在生命周期内被窃取,等同于账户失窃。同时由于SessionID是用户登录之后才持有的认证凭证,因此黑客不需要再攻击登录过程,在设计安全方案时需要意识到这一点。

SessionID劫持就是一种通过窃取用户SessionID后,使用该SessionID登录进目标账户的攻击方法,此时攻击者实际上是使用了目标账户的有效Session。如果SessionID是保存在Cookie中的,则这种攻击可以成为Cookie劫持。

9.5 Session Fixation攻击

X如果才能让Y使用这个SessionID呢?如果SessionID保存在Cookie中,比较难做到这一点。但若SessionID保存在URL中,则X只需要诱使Y打开这个URL即可

解决Session Fixation的正确做法当然是,登录完成后,重写SessionID

9.6 Session保持攻击

一般来说,Session是由生命周期的,当用户长时间未活动后,或者用户点击退出后,服务器将销毁Session。

Cookie的Expire时间是完全可以由客户端控制的。篡改这个时间,并使之永久有效,就有可能获得一个永久有效的Session,而服务器端是完全无法察觉的

9.7 单点登录(SSO)

单点登录的全称是Single Sign On,简称SSO。它希望用户只需要登录一次,就可以访问所有的系统。

第十章:访问控制

10.1What Can I Do?

在Web应用中,根据访问客体的不同,常见的访问控制可以分为: 
1.“基于URL的访问控制” 
2.“基于方法的访问控制” 
3.“基于数据的访问控制”

10.2垂直权限管理

访问控制实际上是建立用户与权限之间的对应关系。现在广泛的做法是,“基于角色的访问控制(Role-Based Access Control)”,简称RBAC

Spring Security提供了一系列的“Filter Chain”,每个安全检查的功能都会插入在这个链条中。在与Web系统集成时,开发者只需要将所有用户请求的URL都引入到Filter Chain中即可

10.3水平权限管理

用户A与用户B可能属于同一个角色RoleX,但是用户A与用户B都各自拥有一些私有数据,在正常情况下,应该只有用户自己才能访问自己的私有数据。

但是在上面的RBAC模型下,系统只会验证用户A是否属于角色RoleX,而不会判断用户A是否能访问只属于用户B的数据dataB,因此,发生了越权访问。这种问题,我们称之为“水平权限管理问题”。 

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

水平权限管理又可以称之为”基于数据的访问控制“

10.4 OAuth简介

OAuth是一个在不提供用户名和密码的情况下,授权第三方应用访问Web资源的安全协议

OAuth与OpenID都致力于让互联网变得更加的开放。OpenID解决的是认证问题,OAuth则更注重授权。认证和授权的关系其实是一脉相承的,后来人们发现,其实更多的时候真正需要的是对资源的授权

第十一章:加密算法与随机数

11.2 Stream Cipher Attack 流密码加密攻击
11.2.1 Reused Key Attack
流密码加密算法基于异或,每次只操作一个字节,性能好。常见:RC4、ORYX、SEAL等
Reused Key Attack 流加密算法不能使用同一个**进行多次加/解密。
笔记《白帽子讲Web安全》吴翰清
配合初始化向量可以避免这种情况下的**。

11.2.2 Bit-flipping Attack
Bit-flipping Attack:不知道明文情况下,通过改变密文使明文按其需要的方式发生改变。
解决方法:验证密文完整性
MAC、HMAC(哈希算法实现的MAC,性能好)
笔记《白帽子讲Web安全》吴翰清
笔记《白帽子讲Web安全》吴翰清
例子代码:
笔记《白帽子讲Web安全》吴翰清
前10个字节验证时间是否有效,10~26字节为HMAC,26个字节之后是密文。
HMAC的实现:
md5(substr($result,26).$keyb)

11.2.3 弱随机IV问题
4个字节的IV(authcode函数中的keyc)不够随机。

11.3 WEP**
流密码攻击WEP**。WEP常用的无线加密传输协议,采用RC4算法,也存在Reused Key Attack和Bit-flipping Attack攻击
WEP两个关键:初始化向量IV,消息的CRC-32校验。

IV以明文传输,在WEP中采用24bit的IV,很快会耗光IV值,最后出现重复的IV。

11.4 ECB模式的缺陷
分组加密常见加密模式:ECB CBC CFB OFB CTR等。
如果加密模式被攻击,无论加密算法的**多长也是不安全的。
ECB模式每个分组是独立的,对调任意分组的密文,解密后明文顺序也是对调的。
CBC链式加密模式,分组前后是互相关联的,一个字节变化会导致整个密文发生变化。

11.5 Padding Oracle Attack
分组加密分组大小常见有64bit 128bit 256bit等。
在最后一个分组消息长度没达到分组的大小,需要填充(padding)一些字节。
例如:以8个字节为一个block
PKCS#5标准:填充内容为填充的字节长度
笔记《白帽子讲Web安全》吴翰清
在实现和使用CBC分组加密算法时注意这点。

11.6 **管理

密码学里的基本原则:

密码系统的安全性应该依赖于**的复杂性,而不应该依赖于算法的保密性

在安全领域里,选择一个足够安全的加密算法不是困难的事情,难的是**管理

最常见的错误,就是将**硬编码在代码里

对于Web应用来说,常见的做法是将**(包括密码)保存在配置文件或者数据库中。**所在的配置文件或数据库需要严格的控制访问权限。同时也要确保运维或DBA中具有访问权限的人越少越好。

一个比较安全的**管理系统,可以将所有的**(包括一些敏感配置文件)都集中保存在一个服务器(集群)上,并通过Web Service的方式提供获取**的API。每个Web应用在需要使用**时,通过带认证信息的API请求**管理系统,动态获取**。Web应用不能把**写入本地文件中,值加载到内存,这样动态获取**最大程度地保护了**的私密性。**集中管理,降低了系统对于**的耦合性,也有利于定期更换**。

11.7.4使用安全的随机数

在重要或者敏感的系统中,一定要使用足够强壮的随机数生成算法。在Java中,可以使用java.security.SecureRandom

在算法上还可以通过多个随机数的组合,以增加随机数的复杂性。比如通过给随机数使用MD5算法后,再连接一个随机字符,然后再使用一个MD5算法一次。这些方法,都可以极大地增加攻击的难度。

总结建议:

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

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

第十二章:Web框架安全

在现代Web开发中,使用MVC架构是一种流行的做法。MVC是Model-View-Controller的缩写,它将Web应用分为三层,View成负责用户视图、页面展示等工作;Controller负责应用的逻辑实现,接受View层传入的用户请求,并转发给对应的Model做处理;Model层则负责实现模型,完成数据的处理

从数据的流入来看,用户提交的数据先后流经了View层,Controller层,Model层,数据的流出则反过来

第十三章:应用层拒绝服务攻击

13.1网络层DDOS

在正常情况下,TCP**三次握手过程**如下:

1.客户端向服务器端发送一个SYN包,包含客户端使用的端口号和初始***x;

2.服务器端收到客户端发送来的SYN包后,向客户端发送一个SYN和ACK都置位的TCP报文,包含确认号x+1和服务器端的初始***y;

3.客户端收到服务器端返回的SYN+ACK报文后,向服务器端返回一个确认号为y+1,序号为x+1的ACK报文,一个标准的TCP连接完成。

而SYN flood在攻击时,首先伪造大量的源IP地址,分别向服务器端发送大量的SYN包,此时服务器端会返回SYN/ACK包,因为源地址是伪造的,所以伪造的IP并不会回答,服务器端没有收到伪造IP的回应,会重试3到5次并且等待一个SYN Time(一般为30秒到2分钟),如果超时则丢弃这个连接。攻击者大量使用这种伪造源地址的SYN请求,服务器端将会消耗非常多的资源(CPU和内存)来处理这种半连接,同时还要不断对这些IP进行SYN+ACK重试。最后的结果是服务器无暇理睬正常的连接请求,导致拒绝服务。

对抗SYN flood的一种方法:SYN Cookie

SYN Cookie的主要思想是为每一个IP地址分配一个“Cookie”,并统计每个IP地址的访问频率。如果在短时间内收到大量的来自同一个IP地址的数据包,则认为受到攻击,之后来自这个IP地址的包将被丢弃。

13.2应用层DDOS

应用层DDOS,不同于网络层DDOS,由于发生在应用层,因此TCP三次握手已经完成,连接已经建立,所以发起的攻击IP都是真实的。但应用层DDOS有时甚至比网络层DDOS攻击更为可怕

应对应用层DDOS攻击:

(1)应用层代码性能优化,将数据库压力转移到内存

(2)网络架构优化:负载均衡,缓解主服务器压力

(3)限制请求频率:

13.2.1CC攻击

CC攻击的原理非常简单,就是对一些消耗资源比较大的应用不断发起正常的请求,以达到消耗服务器资源的目的。在Web应用中,查询数据库,读/写硬盘文件等操作,相对都会消耗比较多的资源。比如下面的这段PHP代码:

$sql = "select * from post where tagid='$tagid' order by postid desc limit $start,30";

当post表数据庞大,翻页频繁,$start数字急剧增加时,查询结果集=$start+30。该查询效率呈现明显下降趋势,而多并发频繁调用,因查询无法立即完成,资源无法立即释放,会导致数据库请求连接过多,数据库阻塞,网站无法正常打开。

应用层DDOS攻击说白了,是针对服务器性能的一种攻击,那么许多优化服务器性能的方法,都或多或少地能缓解这种攻击。比如将使用频率高的数据放在memcache中,相对于查询数据库所消耗的资源来说,查询memcache所消耗的资源可以忽略不计。

13.2.2限制请求频率

最常见的针对应用层DDOS攻击的防御手段,是在应用中针对每个“客户端”做一个请求频率的限制

但道高一尺,魔高一丈。基于IP地址和Cookie的防御机制可能会随着IP的改变而失效。比如使用“代理服务器”,联想到了之前写爬虫是用的同样的IP轮换策略。

13.5资源耗尽攻击

几种攻击策略:

13.5.1 Slowloris 攻击

1.以极低的速度往服务器发送HTTP请求。由于Web Server对于并发的连接数都有一定的上限,因此若是恶意地占用住这些连接不释放,那么Web Server的所有连接都被恶意连接占用,从而无法接受新的请求,导致拒绝服务。要保持住这个连接,要构造一个畸形的HTTP请求,准确地说,是不完整的HTTP请求,让服务器以为后面还有数据没有传输完成,从而一直保持住连接。

从这里,可以看出所有拒绝服务供给的本质实际上是对有限资源的无限制滥用

比如,上面的“有限”的资源是Web Server的连接数。这是一个有上限的值,比如在Apache中这个值是由MaxClinets定义。如果恶意客户端可以无限制地将连接数占满,就完成了对有限资源的恶意消耗,导致拒绝服务。

所以拒绝应用层DDOS的核心思路是,限制住每个不可信任的资源使用者的配额

等等。

13.5.2 HTTP POST DOS 

发送post包时,指定一个非常大的Content-Length值,然后以非常低的速度发包。

13.5.3 Server Limit DOS

Apache能接受最大HTTP包头大小8192字节,请求体2G,超长Cookie会认为非正常请求导致客户端拒绝服务。

13.6 正则ReDOS

写得不好的正则也会消耗掉服务器cpu和内存资源。

第十五章:Web Server配置安全

15.1Apache安全

需要注意的是,Apache以root身份或者admin身份运行是一个非常糟糕的决定

使用高权限身份来运行Apache的结果可能是灾难性的,它会带来两个可怕的后果:

1.当黑客入侵Web成功时,将直接获得一个高权限(比如root或admin)的shell

2.应用程序本身具备比较高权限,当出现bug时,可能会带来较高风险,比如删除本地重要文件,杀死进程等不可预知的结果。

比较好的做法是使用专用的用户身份运行Apache,这个用户身份不应该具备shell,它唯一的作用就是用来运行Web应用。

Apache还提供了一些配置参数,可以用来优化服务器的性能:

TimeOut
KeepAlive
LimitRequestBody
LimitRequestFields
LimitRequestFieldSize
LimitRequestLine
LimitXMLRequestBody
AcceptFilter
MaxRequestWokers

在Apache官方文档中,对如何使用这些参数给出了指导。

15.2Nginx安全

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

第十六章:互联网业务安全

第十七章:安全开发流程(SDL)

安全开发流程,能够帮助企业以最小的成本提高产品的安全性,它符合“Secure at the source”的战略思想。实施好安全开发流程,对企业安全的发展来说,可以起到事半功倍的效果。

第十八章:安全运营