版权信息

书名:Web应用安全权威指南

作者:(日) 徳丸浩

译者:赵文,刘斌

ISBN:978-7-115-37047-1

本书由北京图灵文化发展有限公司发行数字版。版权所有,侵权必究。


您购买的图灵电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


图灵社区会员 ptpress(libowen@ptpress.com.cn) 专享 尊重版权

 

推荐序

译者序

前言

谢辞

第 1 章 什么是 Web 应用的安全隐患

1.1 安全隐患即“能用于作恶的 Bug”

1.2 为什么存在安全隐患会有问题

1.3 产生安全隐患的原因

1.4 安全性 Bug 与安全性功能

1.5 本书的结构

第 2 章 搭建试验环境

2.1 试验环境概要

2.2 安装 VMware Player

2.3 安装虚拟机及运行确认

2.4 安装 Fiddler

第 3 章 Web 安全基础 : HTTP、会话管理、同源策略

3.1 HTTP 与会话管理

3.2 被动攻击与同源策略

第 4 章 Web 应用的各种安全隐患

4.1 Web 应用的功能与安全隐患的对应关系

4.2 输入处理与安全性

4.3 页面显示的相关问题

4.3.1 跨站脚本(基础篇)

4.3.2 跨站脚本(进阶篇)

4.3.3 错误消息导致的信息泄漏

4.4 SQL 调用相关的安全隐患

4.4.1 SQL 注入

4.5 关键处理中引入的安全隐患

4.5.1 跨站请求伪造(CSRF)

4.6 不完善的会话管理

4.6.1 会话劫持的原因及影响

4.6.2 会话 ID 可预测

4.6.3 会话 ID 嵌入 URL

4.6.4 固定会话 ID

4.7 重定向相关的安全隐患

4.7.1 自由重定向漏洞

4.7.2 HTTP 消息头注入

4.7.3 重定向相关的安全隐患总结

4.8 Cookie 输出相关的安全隐患

4.8.1 Cookie 的用途不当

4.8.2 Cookie 的安全属性设置不完善

4.9 发送邮件的问题

4.9.1 发送邮件的问题概要

4.9.2 邮件头注入漏洞

4.10 文件处理相关的问题

4.10.1 目录遍历漏洞

4.10.2 内部文件被公开

4.11 调用 OS 命令引起的安全隐患

4.11.1 OS 命令注入

4.12 文件上传相关的问题

4.12.1 文件上传问题的概要

4.12.2 通过上传文件使服务器执行脚本

4.12.3 文件下载引起的跨站脚本

4.13 include 相关的问题

4.13.1 文件包含攻击

4.14 eval 相关的问题

4.14.1 eval 注入

4.15 共享资源相关的问题

4.15.1 竞态条件漏洞

第 5 章 典型安全功能

5.1 认证

5.1.1 登录功能

5.1.2 针对暴力破解攻击的对策

5.1.3 密码保存方法

5.1.4 自动登录

5.1.5 登录表单

5.1.6 如何显示错误消息

5.1.7 退出登录功能

5.1.8 认证功能总结

5.2 账号管理

5.2.1 用户注册

5.2.2 修改密码

5.2.3 修改邮箱地址

5.2.4 密码找回

5.2.5 账号冻结

5.2.6 账号删除

5.2.7 账号管理总结

5.3 授权

5.3.1 什么是授权

5.3.2 典型的授权漏洞

5.3.3 授权管理的需求设计

5.3.4 如何正确实现授权管理

5.3.5 总结

5.4 日志输出

5.4.1 日志输出的目的

5.4.2 日志种类

5.4.3 有关日志输出的需求

5.4.4 实现日志输出

5.4.5 总结

第 6 章 字符编码和安全

6.1 字符编码和安全概要

6.2 字符集

6.3 字符编码方式

6.4 由字符编码引起的漏洞总结

6.5 如何正确处理字符编码

6.6 总结

第 7 章 如何提高 Web 网站的安全性

7.1 针对 Web 服务器的攻击途径和防范措施

7.1.1 利用基础软件漏洞进行攻击

7.1.2 非法登录

7.1.3 对策

7.2 防范伪装攻击的对策

7.2.1 网络伪装的手段

7.2.2 钓鱼攻击

7.2.3 Web 网站的伪装攻击对策

7.3 防范网络监听、篡改的对策

7.3.1 网络监听、篡改的途径

7.3.2 中间人攻击

7.3.3 对策

7.4 防范恶意软件的对策

7.4.1 什么是 Web 网站的恶意软件对策

7.4.2 恶意软件的感染途径

7.4.3 Web 网站恶意软件防范对策概要

7.4.4 如何确保服务器不被恶意软件感染

7.5 总结

第 8 章 开发安全的 Web 应用所需要的管理

8.1 开发管理中的安全对策概要

8.2 开发体制

8.3 开发过程

8.3.1 规划阶段的注意事项

8.3.2 招标时的注意事项

8.3.3 需求分析时的注意事项

8.3.4 概要设计的推进方法

8.3.5 详细设计和编码阶段的注意事项

8.3.6 安全性测试的重要性及其方法

8.3.7 Web 健康诊断基准

8.3.8 承包方测试

8.3.9 发包方测试(验收)

8.3.10 运维阶段的注意事项

8.4 总结

 

推荐序

我投身信息安全产业领域已经有十五个年头了。过去我通过端口扫描,探测服务器的操作系统类型;防火墙出现后,我又转攻 Web 应用安全,结交了很多业内的顶级信息安全专家,与他们进行了大量的交流。

互联网的出现使得大家从传统的纸质信件传递转变为通过互联网电子邮件收发邮件;社交网络的出现,让我们得以通过互联网来结交更多的朋友。然而,我们在享受这些便利的同时,也承受着恶意钓鱼、跨站脚本攻击、恶意网马植入等风险。这些行为造成用户的信息泄漏,银行卡、信用卡信息被恶意盗刷,以致产生大量的经济损失。

通过国际权威的 Web 应用安全机构 OWASP 所发布的 TOP Ten,可以看出 Web 安全的重要性。现在全球有效的网络攻击中,基于 Web 的占 80% ,SQL 注入与跨站脚本攻击一直都位于 OWASP Top Ten 的前两名,这两种攻击通常都发生在 Web 应用当中。

本次受图灵公司的邀请,参与了本书的校译工作,在进行校译期间看到了赵文和刘斌两位译者深厚的日文专业技术功底,同时也深深地感受到了日本人工作的严谨,作者在书中为大家准备了详实的应用案例和代码。

我作为 OWASP 中国北京的负责人,有幸组织和参与了在中国区域内召开的信息安全峰会与亚洲应用安全峰会,发现国外的信息安全专家更善于总结。他们能通过有效的方法论有效地进行一些精尖技术的推广和学习,而国内的信息安全专家在介绍一些高精技术时一般只告知结果,而不介绍过程。

《Web 应用安全权威指南》这本书的作者是日本 Web 安全第一人,足见其编程功底之深厚。本书没有欧美作者的那些诙谐幽默的用语,更多的是严谨而实用的陈述。作者以 Web 应用的安全隐患为引子,将产生安全隐患的原因作为整个主线来描述,同时还生动地介绍了试验这些安全隐患的环境的搭建,以及缺陷代码的示例。同时本书又给大家做了很好的补充说明,讲述了 Web 安全的基础协议和原理,帮助读者打好 Web 安全的基本功。

最难能可贵的是,本书详尽地讲解了 SQL 注入、XSS、CSRF 等的基本原理,同时又增加了详尽的代码解析。这是一本难得的 Web 应用安全指南。无论你是 Web 安全的爱好者,还是研究者,都可以将它作为一本很好的参考书籍。个人建议一些高校的学生通过学习本书,实现从 Web 安全的基础入门到精通。

OWASP 中国北京区负责人、51CTO 信息安全专家

陈亮(OWASP 子明)

 

译者序

2011 年,索尼遭受了 3 次大规模攻击,造成 7700 万 PlayStation Network(PSN)用户的个人信息泄漏。攻击令 PSN 网络服务瘫痪了 23 天,给索尼造成了上亿美元的经济损失。

2011 年 12 月,国内知名开发者社区 CSDN 遭到攻击,600 万用户账号及明文密码泄漏并在网络上被大量传播。

2013 年 3 月,全球知名的云笔记应用 Evernote 遭到攻击,导致 5000 万用户的邮箱地址和加密密码泄漏。

写下这篇文字时,又正值全球最大的众筹网站 Kickstarter 被攻击而导致用户信息被窃取。

一件件触目惊心的事件无一不在提醒着我们网络安全的重要性。造成这些事件的罪魁祸首或许只是代码中一些不起眼的地方,但引发的影响及后果却骇人听闻。掌握如何在编程时不引入漏洞已成为了 Web 应用开发者不可或缺的技能。

然而,当开发者想要系统性地学习 Web 应用安全时,却发现市面上充斥着以攻击者的视角写作的“XX 攻防大全”等书籍,却鲜有站在开发者立场的优秀的权威性书籍可供参考。图灵公司引进的这本《Web 应用安全权威指南》正好填补了这一领域的空缺。

“在那本‘德丸本’中有透彻的讲解。”这是译者在日本工作期间,向同事询问“什么是 CSRF”时得到的答复。没错,“德丸本”就是本书在日本的昵称,几乎在每个 Web 开发小组的案头都能发现它的身影。

本书的作者德丸浩先生在日本被誉为“Web 应用安全领域第一人”,他在经营着一家 Web 安全咨询公司的同时,还在博客上笔耕不辍,孜孜不倦地分享着自己 Web 安全方面的知识,得此称号可谓实至名归。这本书是目前为止德丸浩先生出版的唯一一本图书,可以说是从业多年的经验沉淀下来的精华。

看过日系技术书的读者,一定会对其通俗易懂、深入浅出、谦虚谨慎等特点印象深刻,本书也不例外。SQL 注入、XSS、CSRF 等对于 Web 开发人员来说耳熟能详却可能一知半解的术语,都将在这本书中详细剖析。本书既适合从头到尾通读来进行系统性学习,也适合作为参考书时常查阅。

最后,再一次感谢图灵文化的编辑们能将这本书引入到国内。感谢另一位译者刘斌的辛勤付出,使得本书能够成功地问世。还要感谢妻子马超对我使用业余时间进行翻译工作的鼓励和支持。

希望本书能够让您受益。

赵文

2014 年 2 月于无锡

 

前言

近年来,利用 Web 应用存在的安全隐患(即所谓的“漏洞”)展开攻击的案例层出不穷,受害者也与日俱增。虽说只要消除安全隐患就能够杜绝这些攻击,但这就需要 Web 应用开发人员掌握正确的安全性方面的知识。

目前,网络上充斥着大量关于安全性的信息,但多数内容都只是流于表面,无法解答开发人 员的困惑。具体来说,主要存在以下几点疑问。

而本书就是为了解答这些疑问而创作的。为此,从安全隐患产生的原理到具体的对策,以及采用该对策的根据,本书都将尽可能地详细讲述。本书的目标读者包括程序员、设计师、项目经理、质量管理负责人等参与 Web 应用开发的全部人员。另外,本书也会站在 Web 应用的发包方(甲方)的立场上,尽可能地为其提供有用的信息。

虽然本书面向的是开发人员,但对攻击的手段也做了详细的解说。目的就是为了能够让读者切实感受到安全隐患所造成的影响。但有一点需要注意的是,如果没有得到网站管理员的许可就尝试实施攻击的话,就有可能会触犯相关的法律法规。由于非专业人员很难判断自己的行为是否违法,因此,请不要在没有得到许可的情况下攻击正式的网站。

为了让读者能够放心地体验攻击流程,本书提供了在 VMware Player 的虚拟机环境中尝试安全隐患攻击的方法。希望读者能够通过亲自动手,来加深对安全隐患的理解。

最后,虽然本书中的示例代码主要使用了 PHP 语言,但讲述的内容对其他语言也是同样适用的。

 

谢辞

笔者在写作本书时,在网上征集了一些试读者,并根据试读者的意见和反馈不断地进行了调整。试读者不仅指出了错别字及语法问题,还提出了各种各样的改进方案,甚至还就安全隐患进行了深入的探讨,实在令笔者受益匪浅。如果没有这些建议和探讨,本书就不会是现在的样子。衷心感谢以下这些试读者(恕笔者省略敬称):

大崎雅幸、太田良典、kaito834、加藤泰文、小邨孝明、坂井隆二、下冈叶子、高木正弘、竹迫良范、东内裕二、塙与志夫、日野洋一郎、山崎圭吾、山下太郎、Masahiro Yamada(masa141421356)、山本阳平

另外,长谷川阳介先生对本书提出了宝贵意见。同时笔者还在 Twitter 上收到了很多人士的建议。在此一并表示感谢。

最后还要感谢本书的编辑——SB Creative 股份有限公司信息书籍编辑部的友保健太先生,友保先生不仅对写作进度缓慢的笔者颇为照顾,还时常给出宝贵的意见和建议。在此向您致以衷心的感谢。

2011 年 1 月

德丸浩

 

第 1 章 什么是 Web 应用的安全隐患

本章将对“安全隐患”这一贯穿全书的主题加以概述,包括什么是安全隐患,安全隐患会带来哪些问题,安全隐患是如何产生的,等等。本章最后会给出全书的结构和学习方法。

程序 Bug 对于开发者来说如同家常便饭。应用程序有了 Bug,就会出现各种不正常的现象。例如,显示出错误的结果、需要进行的处理迟迟不能结束、网页布局错乱、响应速度极为缓慢等。而这其中,有一种 Bug 能被恶意利用。此类 Bug 被称为安全隐患(Vulnerability),有时也被称为安全性 Bug。

以下是一些恶意利用的常见案例。

1 能看到其他用户个人信息的 Bug 虽不是故意作恶,但由此而偶然造成的不良后果也被视为安全隐患。

如同程序员对一般的 Bug(无奈地)习以为常一样,Web 应用程序开发者对安全隐患也同样已经司空见惯。倘若开发 Web 应用程序时对安全隐患一无所知,就会开发出能被用来进行上述恶举的网站。针对这一问题,本书将从原理到具体对策,来详细讲述如何在开发 Web 应用时杜绝安全隐患。

为什么存在安全隐患会有问题,这是个越思考就越深入的课题。接下来,就让我们从几个方面来探讨一下必须杜绝安全隐患的原因。

2 这种策略被称为“风险自留”。

3 本节阐述的是日本的相关法律,供中国读者参考。遗憾的是,截至译稿时(2013 年 9 月),中国在网络安全隐患方面还没有推出相应的法律法规。——译者注

4 俗称“肉鸡”。 ——译者注

接下来本节将说明安全隐患产生的原因,据此就可以理解为何笔者之前会说“Web 应用程序开发者对安全隐患已经司空见惯”。

首先,产生安全隐患的原因可分为以下两类。

(A)由 Bug 造成

(B)由检验功能不完善造成

情况(A)包含 SQL 注入(SQL Injection)和跨站脚本(Cross Site Scripting,简称 XSS)等极具影响力的著名的安全隐患。此类隐患不仅发生场所与安全性毫不相关,而且波及范围能扩散至整个应用程序,着实让人头疼。因此,开发团队的每一个成员在编写应用程序时就必须具有极强的安全意识,但可惜目前还有很多开发团队并未这么做。

另一方面,目录遍历(Directory Traversal)漏洞是情况(B)中一个代表性的例子。产生此类安全隐患的原因是很多开发者缺乏执行安全检验的意识,而且同(A)一样,它造成的影响也会波及整个应用程序。

由此可见,Web 应用的安全隐患可以被形象地比喻为“在意想不到的地方隐藏着的一个很深的陷阱”。因此,一直以来安全隐患都在源源不断地产生。但是,与真正的陷阱不同的是,我们能够通过学习提前得知哪里会有陷阱。

本章开头我们提到安全隐患是一种 Bug,但有时即使修正了所有 Bug 也不能保证应用程序绝对安全。举例来说,没有使用 HTTPS 协议(超文本传输安全协议)来加密传输的状态并不能算作是 Bug,这种情况下,虽然不存在(狭义的)安全隐患,但是传输的内容却存在被窃听的可能性。

如同使用 HTTPS 来对传输内容进行加密那样,积极主动地加强安全性的措施在本书中被称为“安全性功能”。安全性功能实为应用程序的一种需求,所以也被称为安全性需求。

从开发管理这一层面上来说,将应用程序安全性方面的 Bug 和需求这两者整理清楚也是至关重要的。如同 Bug 必须被消除一样,消除安全隐患也应当是理所当然的。另一方面,是否将安全性功能加入到项目需求中,则应该由软件的发包方结合项目经费作出决定。

为了让读者有意识地区分安全性 Bug 和安全性功能,本书特意将两者分别独立成章来加以细述。

本书结构如下。

第 1 章,引入安全隐患这个概念,介绍安全隐患是如何产生的,说明安全性 Bug 和安全性功能的区别。

第 2 章,搭建本书的试验环境。本书通过 VMware 的虚拟机提供了可以实际体验安全隐患的环境。该章会介绍搭建此虚拟机环境和安装诊断用工具的方法。

第 3 章,讲述 HTTP、Cookie、会话(Session)管理等 Web 应用安全方面的基础知识,还会介绍同源策略。

第 4 章,全书的核心章节。针对 Web 应用的每一个功能中易产生的安全隐患模式,对其原理及对策等各个方面加以详细说明。

第 5 章,讲述认证、账号管理、授权、日志输出等典型的安全性功能。

第 6 章,讲述字符编码与安全性的关系。Web 应用安全隐患的起因很多都涉及字符编码。本章将讲述字符编码的基础知识、安全隐患产生的原因和相应的对策。

第 7 章,从 Web 应用以外的方面,描绘提高网站安全性措施的全景。

第 8 章,讲述如何开发安全无虞的 Web 应用。

 

第 2 章 搭建试验环境

本章将讲解如何搭建本书中安全隐患用例的运行环境,其中的截图是在 Windows 7 中取得的,但这些操作同样适用于 Windows XP 或 Windows Vista。

本书中安全隐患用例的运行环境如下:

为了方便使用 Windows 操作系统的读者,本书为大家准备了已经将上述环境搭建完毕的 VMware 虚拟机。下图展示了在 VMware 中运行 Linux 系统的情形。

{%}

图 2-1 本书的试验环境

虽然虚拟机中的 Linux 服务器事实上是在读者自己的计算机中运行的,但请将其想像成互联网上的一台远程服务器。通过使用虚拟机,我们就能在自己的计算机上模拟近似于互联网上的服务器环境。

本章需要安装以下软件。

VMware Player 和 Fiddler 是免费公开的软件。虚拟机则是指为了能够在 VMware Player 上运行本书代码而配置的 Linux 环境。

从下一节开始,我们将依次解说各软件的安装方法。

1 本章的讲解主要针对 Windows 操作系统,但本书附带的虚拟机环境在 Linux 版的 VMware Player 3.1.2,以及 Mac OS X 的 VMware Player 3.1.2 上已经做过测试,均能正常运行。

接下来安装安全隐患用例的虚拟机。虚拟机的安装,请先到本书的支持页面下载 WASBOOK.ZIP 文件:链接:http://pan.baidu.com/s/1sj3jhA9 密码:ivfp ;然后,解压到合适的路径即可。解压后的大小约为 600M,所以请安装到至少还有 800M 以上剩余空间的盘符中。也可以安装至 U 盘或 SD 卡中。

假定解压路径为“文档”文件夹。这样,文档文件夹内就会生成一个名为 WASBOOK 的文件夹。

{%}

图 2-6 WASBOOK 文件夹的内容

为了深入理解 HTTP,本书将通过使用免费工具 Fiddler 来观察并修改 HTTP 数据包。本节首先解说 Fiddler 的安装方法。

参考:虚拟机的数据一览

已建立的用户账号

用户名

密码

目的

root

wasbook

Linux的root用户

wasbook

wasbook

应用程序管理者

alice

wasbook

邮件发送者

bob

wasbook

邮件接收者

carol

wasbook

其他

down

(无)

关机用

已安装的软件

服务

软件

版本

OS(Linux)

Ubuntu

10.04.1 LTS

Web服务器

Apache

2.2.14

PHP

PHP

5.3.2

数据库

PostgreSQL

8.4.4

邮件发送服务器

Postfix

2.7.0

POP3服务器

Dovecot

1.2.9

SSH服务器

OpenSSH

5.3

Apache 的根目录

/var/www

参考:如果无法连接试验环境的 POP3 服务器

设置了第 17 页的邮箱账号后,如果无法连接 POP3 服务器,可以在虚拟机上执行以下命令来启动 Dovecot。

# /etc/init.d/dovecot start


{%}

图 2-13 启动 Dovecot

如图 2-13 所示,显示“OK”即表明 Dovecot 已经启动。这时请再次连接 POP3 服务器。

 

第 3 章 Web 安全基础 : HTTP、会话管理、同源策略

本章的内容是 Web 安全的重要基础。首先介绍 HTTP 协议和会话管理,然后讲述浏览器的安全性功能之一,也是理解跨站脚本等主要安全隐患的原理的必备知识——同源策略。

为什么要学习 HTTP

Web 应用的安全隐患有些源于网络的固有特性。在 Web 应用中,哪些信息容易泄漏,哪些信息容易被篡改,如何才能保证信息安全?正是因为开发人员缺乏这些知识,才会在开发时埋下安全隐患。为了理解诸如此类源自 Web 特性的安全隐患,就必须要掌握 HTTP 和会话管理的相关知识。而这也是本节要讲述的内容。

最简单的 HTTP

在正式开始前,先来体验下最简单的 HTTP 吧。31-001.php 中有如下 PHP 代码。这段脚本的功能为显示当前时间。

代码清单 /31/31-001.php

<body>
<?php echo htmlspecialchars(date('G:i')); ?>
</body>



访问 http://example.jp/31/ 的菜单(以下写作“/31/ 菜单”),点击“31-001: 当前时间”链接(图 3-1),就可以在虚拟机上执行这段脚本了。

{%}

图 3-1 /31/ 菜单

执行结果如图 3-2 所示。

{%}

图 3-2 显示时间脚本

与此同时,在后台,浏览器会向服务器发送 HTTP 请求(HTTP Request),而收到浏览器请求的服务器则会向浏览器发回 HTTP 响应(HTTP Response)(图 3-3)。

{%}

图 3-3 HTTP 的请求与响应

1 如果 HTTP 协议版本为 1.0,Host 头信息也可以省略。

2 将 HTTP 比喻成对话的灵感,源于书籍《Web 背后的技术》[1] 与《Web 技术入门》[2]。

输入 - 确认 - 注册模式

这里,通过观察“输入-确认-注册”模式中输入表单(Input Form)的 HTTP 消息,希望能够有助于读者更深入地理解 HTTP。

以下分别为输入页面(31-002.php)、确认页面(31-003.php)和注册页面(31-004.php)的代码。

代码清单 /31/31-002.php

<html>
<head><title> 个人信息输入 </title></head>
<body>
<form action="31-003.php" method="POST">
姓名 <input type="text" name="name"><br>
邮箱地址 <input type="text" name="mail"><br>
性别 <input type="radio" name="gender" value=" 女 "> 女
<input type="radio" name="gender" value=" 男 "> 男 <br>
<input type="submit" value=" 确认 ">
</form>
</html>



代码清单 /31/31-003.php

<?php
  $name = @$_POST['name'];
  $mail = @$_POST['mail'];
  $gender = @$_POST['gender'];
?>
<html>
<head><title> 确认 </title></head>
<body>
<form action="31-004.php" method="POST">
姓名 :<?php echo htmlspecialchars($name, ENT_NOQUOTES, 'UTF-8'); ?><br>
邮箱地址 :<?php echo htmlspecialchars($mail, ENT_NOQUOTES, 'UTF-8'); ?><br>
性别 :<?php echo htmlspecialchars($gender, ENT_NOQUOTES, 'UTF-8'); ?><br>
<input type="hidden" name="name" value="<?php echo htmlspecialchars($name, ENT_COMPAT, 'UTF-8'); ?>">
<input type="hidden" name="mail" value="<?php echo htmlspecialchars($mail, ENT_COMPAT, 'UTF-8'); ?>">
<input type="hidden" name="gender" value="<?php echo htmlspecialchars($gender, ENT_COMPAT, 'UTF-8'); ?>">
<input type="submit" value=" 注册  ">
</form>
</html>



代码清单 /31/31-004.php

<?php
  $name = @$_POST['name'];
  $mail = @$_POST['mail'];
  $gender = @$_POST['gender'];
  // 下面开始处理
?>
<html>
<head><title> 注册成功 </title></head>
<body>
姓名 :<?php echo htmlspecialchars($name, ENT_NOQUOTES, 'UTF-8'); ?><br>
邮箱地址 :<?php echo htmlspecialchars($mail, ENT_NOQUOTES, 'UTF-8'); ?><br>
性别 :<?php echo htmlspecialchars($gender, ENT_NOQUOTES, 'UTF-8'); ?><br>
已注册
</body></html>



要在虚拟机上执行的话,可以点击 /31/ 菜单中的“31-002:输入-确认-注册”链接。然后就会显示如下页面(图 3-8)。

{%}

图 3-8 输入页面

在页面上填入姓名、邮箱和性别后点击“确认”按钮。这时,HTTP 请求消息就可以在 Fiddler 中看到(图 3-9)。

{%}

图 3-9 在输入页面填写完毕后点击“确认”时 Fiddler 中显示的 HTTP 请求消息

3 百分号编码属于 URL(URI)的规范,application/x-www-form-unlencoded 属于 HTML 的规范,所以两者存在细微差别。

4 关于使用 Fiddler 来改变参数,后面讲 hidden 参数时会进行详述。

5 http://tools.ietf.org/html/rfc2616

6 虽然 RFC2616、RFC1738 及 RFC3986 中并未规定 URL 的长度上限,但各个浏览器都存在上限值。

7 与此相反,像 FTP 和 telnet 这种能够记忆当前状态的特性,叫作有状态性。

无状态的 HTTP 认证

HTTP 支持认证功能。HTTP 认证根据实现方式可细分为 Basic 认证、NTLM 认证和 Digest 认证等。正如 HTTP 是无状态的协议一样,HTTP 认证同样也是无状态的。

下面让我们看一下 HTTP 认证中最简单的 Basic 认证。

Cookie 与会话管理

前面我们已经提到,由于 HTTP 协议的无状态性,服务器端不能保存客户端的状态。但是,在应用程序中,保持客户端的状态却是相当常见的需求。

比如,在线购物网站中的“购物车”就是一个典型的案例。购物车记住了用户在哪些商品上点击了“购买”按钮。

另外,记住用户登录后的认证状态也是一种常见的需求。虽然使用 HTTP 认证就能使浏览器记住 ID 和密码,但不使用 HTTP 认证时,记忆认证状态的任务就落在了服务器身上。而像这种记忆应用程序状态的功能就叫作“会话管理”。

为了实现会话管理,HTTP 引入了名为 Cookie 的机制。Cookie 相当于服务器下达给浏览器的命令,让其记住发送给它的“名称 = 变量”这种格式的值。由于 Cookie 会被用于实现会话管理,因此,下面就让我们结合 PHP 中的会话管理来对其进行说明。

下面的示例应用是用户认证和用户信息显示的简化版。由以下 3 个页面构成:ID 和密码输入页面(31-020.php)、ID 和密码认证页面(31-021.php)、个人信息(ID)显示页面(31-022.php)。在虚拟机上执行时,可在 /31/ 菜单中点击“31-020: 使用 Cookie 的会话管理”。

代码清单 /31/31-020.php

<?php
  session_start();  // 会话开始
?>
<html>
<head><title> 请登录 </title></head>
<body>
<form action="31-021.php" method="POST">
用户名 <input type="text" name="ID"><br>
密码 <input type="password" name="PWD"><br>
<input type="submit" value=" 登录 ">
</form>
</body>
</html>



代码清单 /31/31-021.php

<?php
  session_start();  // 会话开始
  $id = @$_POST['ID'];
  $pwd = @$_POST['PWD'];
  // 用户名和密码中任意一项未输入时则登录失败
  if ($id == '' || $pwd == '') {
    die(' 登录失败 ');
  }
  $_SESSION['ID'] = $id;
?>
<html>
<head><title> 登录 </title></head>
<body>
登录成功
<a href="31-022.php"> 我的账号 </a>
</body>
</html>



代码清单 /31/31-022.php

<?php
  session_start();  // 会话开始
  $id = $_SESSION['ID'];
  if ($id == '') {
    die(' 请登录 ');
  }
?>
<html>
<head><title> 我的账号 </title></head>
<body>
用户名 :<?php echo htmlspecialchars($id, ENT_NOQUOTES, 'UTF-8'); ?>
</body>
</html>



同 Basic 认证的例子一样,随便输入 ID 和密码就能成功通过认证。页面跳转流程如下图所示。

{%}

图 3-20 示例应用的页面跳转

最初显示 31-020.php 的 ID 和密码输入页面时,返回的响应消息如下(仅列出要点)。

HTTP/1.1 200 OK
Set-Cookie: PHPSESSID=gg5144avrhmdiaelvh80l4lb53; path=/


Content-Length: 279
Content-Type: text/html; charset=UTF-8

<html>
<head><title> 请登录 </title></head>
<body>【以下略】

通过 Set-Cookie 响应头信息,Web 服务器向浏览器下达了记住此 Cookie 值的指示。

在登录页面上输入 ID 和密码后点击“登录”按钮,浏览器就会向服务器发送如下请求。

POST /31/31-021.php HTTP/1.1
Referer: http://example.jp/31/31-020.php
Content-Type: application/x-www-form-urlencoded
Host: example.jp
Content-Length: 18
Cookie: PHPSESSID=gg5144avrhmdiaelvh80l4lb53



ID=user1&PWD=pass1

记住了 Cookie 值的浏览器,从此再向相同网站(example.jp)发送请求时,就会同时发送此 Cookie 值(PHPSESSID=…)。Cookie 可以设置有效期限,没有设置有效期限的 Cookie 会在浏览器被关闭之前一直有效。

Cookie 中 PHPSESSID 的值被称为会话 ID,它是访问会话信息的关键。31-021.php 中,认证成功后的用户 ID 被保存在会话变量 $_SESSION['ID'] 中。随后程序在 31-022.php 中取得了此用户 ID。保存在会话变量中的信息,在会话失效之前随时都能被访问。

8 http://www.cryptrec.go.jp/list.html

总结

为了有助于理解 Web 应用的安全隐患,本节讲述了 HTTP、Basic 认证、Cookie、会话管理的相关知识。当前大多数应用都采用 Cookie 来进行会话管理,这在认证结果的保存等安全性方面扮演着重要角色。

作为本节的应用篇,下节将讲述被动攻击和同源策略。

参考文献

[1] 山本阳平 .(2010).《Web を支える技術-HTTP、URI、HTML、そして REST》(《Web 背后的技术-HTTP、URI、HTML 和 REST》). 技術評論社 .

[2] 小森裕介 .(2010).《「プロになるための Web 技術入門」——なぜ、あなたは Web システムを開発できないのか》(《“Web 技术入门”——为什么你无法开发 Web 系统》). 技術評論社 .

本节首先讲述被动攻击这一攻击手法,然后介绍浏览器针对此类攻击的防御策略——沙盒。沙盒技术的核心概念为“同源策略”,它对于理解 Web 应用的安全隐患至关重要,所以,对同源策略这一概念,本节也会进行详细说明。

主动攻击与被动攻击

针对 Web 应用程序的攻击可分为主动攻击(Active Attack)和被动攻击(Passive Attack)。下面先简单介绍这两者的区别,然后再重点讲述被动攻击。

9 含有恶意代码的 HTML,多是指在网络论坛上发布的专门用来攻击的 URL。

浏览器如何防御被动攻击

针对以上被动攻击,浏览器和网站都需要采取相应的防御措施。本书将从第 4 章开始详述网站方面的对策,但其前提是浏览器不存在安全方面的问题。如果浏览器存在安全问题,网站方面即使实施了对策也无法完全确保安全性。

在说明网站的对策之前,让我们先来关注一下浏览器的安全功能。

10 32-001.html 含有 XSS 漏洞。详情参考 4.3 节。

11 主机方面,通过 JavaScript 修改 document.domain 可以使条件放宽,但至少也被限制在了相同域名中不同主机之间的访问。

12 i-mode2.0(日本 NTT DoCoMo)的手机浏览器的同源策略中添加了目录访问的限制。

13 这里所讲解的是使用 iframe 来进行 XSS 攻击的情况,但其实不用 iframe 也同样能发动 XSS 攻击。

JavaScript 以外的跨域访问

前面讲解了 JavaScript 的跨域访问会受到同源策略的严格限制。下面,让我们来看一些能够进行跨域访问的其他浏览器功能。

14 点击劫持是综合利用 iframe 和 CSS 而执行的一种被动攻击,使用视觉上的欺骗手段诱使用户进行操作。

15 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-4089

总结

本节讲述了被动攻击,以及浏览器用来防御被动攻击的同源策略。

被动攻击是攻击 Web 应用的一种手法,经由用户的浏览器来攻击 Web 应用程序。

JavaScript 的同源策略是浏览器防御被动攻击的代表性对策。然而,若浏览器或 Web 应用中存在安全隐患,攻击者就可以绕过同源策略而执行攻击。下一章我们就将重点讲述 Web 应用方面的防御对策。

 

第 4 章 Web 应用的各种安全隐患

本章将详细讲解 Web 应用中各种安全隐患的产生原理、影响范围和防范策略。

4.1 节讲述 Web 应用中功能与安全隐患的对应关系,从而使读者对安全隐患有一个整体印象。

4.2 节讲述 Web 应用的“输入”以及与其相关的安全隐患。

4.3 节以后将分门别类地详细剖析 Web 应用的每个功能容易滋生的安全隐患。其中,一些影响重大的知名隐患,如跨站脚本(XSS)与 SQL 注入等也都将在此进行讲述。

安全隐患产生于何处

在逐项细述 Web 应用的安全隐患之前,让我们先对安全隐患有一个整体认识。图 4-1 展示了 Web 应用的各项功能与安全隐患的对应关系。图中使用经典的“输入-处理-输出”模型来表示 Web 应用。从 HTTP 请求的输入开始,经过应用的各种处理,最后由 HTTP 响应进行输出。而除了 HTTP 响应外,此处的“输出”还包括访问数据库、读写文件、收发邮件等“与外界交流”的操作。

{%}

图 4-1 Web 应用的功能与安全隐患的对应关系

换一个角度来看,图 4-1 中的“输出”也能被理解为向外部媒介输出脚本。Web 应用常见的脚本输出和与其对应的安全隐患如下所示。

关于各隐患的详情在后面的章节中会进行细述,而从图 4-1 中,我们可以得出以下结论。

1 仅限于本书探讨的应用程序的安全性。如果将讨论范围扩大至中间件(Middleware),输入校验时也有可能引入安全隐患。

其实,跨站脚本有时也被称为“HTML 注入”或“JavaScript 注入”,因此,图 4-1 中输出过程产生的安全隐患全部为注入型隐患。

综上所述,安全隐患和 Web 应用的功能息息相关。所以在程序设计或编写代码时,就能够根据此时正在实现的功能而得知应当对哪些安全隐患提高警惕。鉴于这种情况,下一节开始,我们将按照 Web 应用的各项功能分类,来详细阐述与其对应的安全隐患。

由于所有的注入型隐患都是基于一些共同的原理,因此,接下来就让我们首先来看一下注入型隐患产生的原因。

注入型隐患

Web 应用中传递的信息多数为文本格式。HTML、HTTP 和 SQL 等支撑 Web 应用的技术多数都采用了文本格式的接口。

这些文本格式都由各自的语法构成,其中还混合了命令、运算符和数据等。多数情况下,数据部分会通过使用引号(单引号或双引号)或使用被称为分隔符(Delimiter)的符号(逗号、Tab 或换行符等)隔开的方式来加以区分。Web 应用的普遍形式为,首先确定文本的框架结构,然后再将数据填入其中。例如,以下的 SQL 语句中,$id 就是被填入的数据。

SELECT * FROM users WHERE id='$id

'

$id 以外的部分即事先确定的文本结构。然而,如果应用存在安全隐患,就能够更改此 SQL 语句的结构。

举例来说,假设要将以下字符串作为 $id 的值填入 SQL 语句。

';DELETE FROM users --



填入数据后的 SQL 语句如下。阴影部分即 $id 的值。

SELECT * FROM users WHERE id='';DELETE FROM users --

'

外界传入的单引号和分号迫使 SELECT 语句结束后,又被添加了 DELETE FROM 语句,这就是 SQL 注入攻击,详情将在 4.4.1 节讲述。

SQL 注入攻击产生的原因为,在被认定为“数据”的位置插入单引号使得数据部分结束,从而更改了 SQL 语句的构造。

这个原理同样也适用于其他的注入型隐患。通过插入引号或分隔符等用于表示“数据部分边界”的字符,从而改变了文本的结构。

表 4-1 列举了各种注入型攻击采用的恶意手段和表示“数据部分边界”的字符。详情在之后介绍各个隐患时会进行细述,此处首先对注入型隐患的产生有着共同的原理这一事实有一大致印象,将有助于理解后面章节的内容。

表 4-1 注入型隐患的比较

隐患名

接口

恶意手段

数据部分边界

跨站脚本

HTML

注入JavaScript等

< " 等2

HTTP消息头注入

HTTP

注入HTTP响应消息头

换行符

SQL注入

SQL

注入SQL命令

' 等

OS命令注入

Shell脚本

注入系统命令

; | 等

邮件头注入

sendmail命令

注入或更改邮件头或正文

换行符

2 之所以将“<”作为数据部分的边界,是因为 HTML 元素的内容(一般为文本)以“<”为结束符,“<”表示标签的开始。

总结

本节作为讲解安全隐患的序幕,介绍了安全隐患产生地点和安全隐患种类的关联性。此外,对由输出引发的安全隐患,即注入型隐患的产生原理也进行了介绍。

下一节开始,我们将把 Web 应用以功能为单位进行细分,并详细讲解每一功能容易产生的安全隐患。

本节专门讨论 Web 应用中对“输入值”的处理,以及输入处理在安全性策略中的地位。虽然校验输入值本身并不是安全性策略,但是,在安全性对策存在缺陷的情况下,通过校验输入值能够防止危害的发生,或者减轻损害的程度。

什么是 Web 应用的输入处理

Web 应用中的输入即由 HTTP 请求传入的信息,比如 GET、POST、Cookie 等。Web 应用接收到这些值时所做的处理,在本书中称为“输入处理”。以图 4-2 所示的“输入-处理-输出”模型为例,在这一模型中,Web 应用的输入处理即为业务逻辑处理之前的数据准备阶段。

图 4-2 “输入-处理-输出”模型

输入处理就是指对输入值做如下处理。

(a)检验字符编码的有效性 3

3 本章不深入讲解字符编码。详情请参考第 6 章。

(b)必要时转换字符编码

(c)检验参数字符串的有效性

之所以检验字符编码的有效性是因为存在利用字符编码的攻击手段 4 (参考第 6 章)。虽然理论上只要确保所有使用字符串的地方都能正确处理字符编码就不会有问题,但现实中由于编程语言的漏洞或者写代码时的疏忽,安全隐患却防不胜防。而另一方面,如果 Web 应用能够将字符编码不正确的数据拒之门外,就能抵御利用非法字符编码发动的攻击。

4 此外,因为程序的正常运行也要求字符编码没有问题,所以检验字符编码有效性也是为了保证程序的正常运行。

(b)处理中的转换字符编码,指的是在 HTTP 消息与程序内部使用的字符编码不一致的情况下需要进行的处理。

(c)处理中的校验输入值,与其说是安全性方面的要求,不如说是依据应用软件规格执行的操作,但不管怎样,从结果上来看确实对提升应用的安全性起到了辅助作用。

下面让我们来分别看一下上述 3 点的详细内容。

检验字符编码

PHP 中能使用 mb_check_encoding 函数检验字符编码。

格式清单 mb_check_encoding 函数

bool mb_check_encoding(string $var, string $encoding)



第一个参数 $var 是检验对象字符串,第二个参数 $encoding 是字符编码。$encoding 可以省略,省略时函数使用 PHP 的内部字符编码。如果 $var 字符串的字符编码正确则函数返回 true。

其他编程语言中检验字符编码的方法请参考第 6 章。

转换字符编码

转换字符编码的方法因编程语言而异。总体上可分为自动转换字符编码的语言和在脚本中手动转换字符编码的语言。PHP 中通过设置 php.ini 文件,可切换上述两种方式。

表 4-2 主流 Web 开发语言中提供的转换字符编码的方法

语言

自动转换

手动转换

PHP

php.ini 等

mb_convert_encoding

Perl

×

Encode::decode

Java

setCharacterEncoding

String 类

ASP.NET

Web.config

×

表 4-2 中归纳了主流 Web 开发语言中提供的转换字符编码的方法。接下来、让我们以手动转换字符编码的方式为例进行说明。

PHP 中使用 mb_convert_encoding 函数来手动转换字符编码。

格式清单 mb_convert_encoding 函数

string mb_convert_encoding(string $str, string $to_encoding, string $from_encoding)



mb_convert_encoding 函数的 3 个参数分别为:转换前的字符串、转换后的字符编码、转换前的字符编码。返回值为转换后的字符串。

检验并转换字符编码的实例

这里我们来看一个检验并转换字符编码的实例。以下 PHP 脚本表示的是接收 Shift_JIS 编码的文字列 name 后将其显示在页面上。脚本的内部编码为 UTF-8,所以需要使用 mb_convert_encoding 函数来转换文字编码。

代码清单 /42/42-001.php

<?php
  $name = isset($_GET['name']) ? $_GET['name'] : '';
  // 校验字符编码(Shift_JIS)
  if (! mb_check_encoding($name, 'Shift_JIS')) {
    die(' 字符编码有误 ');
  }
  // 转换字符编码(Shift_JIS → UTF-8)
  $name = mb_convert_encoding($name, 'UTF-8', 'Shift_JIS');
?>
<body>
名字为  <?php echo htmlspecialchars($name, ENT_NOQUOTES, 'UTF-8'); ?>
</body>



正常情况下执行结果如图 4-3 所示。

{%}

图 4-3 42-001.php 执行结果示例(正常情况)

下图为使用不符合 Shift_JIS 编码的字符串 %82%21 时的页面显示。由于 Shift_JIS 双字节的第二个字节必须是 0x40 以上的值,而 %20 不符合要求,所以是无效的 Shift_JIS 数据。相关详情可参考第 6 章。

{%}

图 4-4 输入值不符合 Shift_JIS 编码

专栏:字符编码的自动转换与安全性

前面提到 PHP 中能通过编辑 php.ini 使字符编码自动转换。其实,也有些编程语言,如 Java 与 .NET,主要使用自动转换字符编码。

转换字符编码时,不正确的字符会被删除或被替换为其他字符(? 或者 Unicode 的替换字符 U+FFFD),因此,即便是自动转换字符,也能够防御利用字符编码的攻击手段。

虽然使用自动转换能让写代码的工程轻松不少,但也存在以下缺点。

因此,本书专门介绍了检验字符编码和手动转换字符编码的方法。

至于如何选择自动转换与手动转换,需要在了解两者各自的优缺点的前提下,在开发团队中达成统一认识,或者在进行各个项目时分别选择。

输入校验

处理完字符编码的相关操作后,就进入到了输入校验的阶段。下面,让我们首先了解一下 Web 应用中输入校验的概要,并在此基础上探讨输入校验与安全性的关系。

5 详情可参考后续章节中对跨站脚本和 SQL 注入的讲解,以及第 6 章。

6 本书支持页面中的 /42/42-011.php。

7 POSIX 是 IEEE 规定的基于 Unix 操作系统的共通规格,其中也包含了正则表达式的规格。POSIX 字符集合则是指 POSIX 正则表达式中定义的字符集合。

范例

作为以上内容的总结,接下来我们来看一个 PHP 脚本范例,该脚本的目的在于接收 URL 中的查询字符串 name 并将其显示在页面上。

代码清单 /42/42-020.php

<?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>



getParam 函数中进行了读取字符串、校验字符编码、转换字符编码、输入校验等操作。定义此类能够复用的共通方法,能够使后续的开发过程轻松很多。

范例代码中也存在一些不足之处,比如错误消息过于简陋难以理解等。这里笔者希望将代码的改善工作作为习题留给读者。

专栏:输入校验与框架

前面介绍了在应用程序中通过业务逻辑来进行输入校验的方法,而在使用 Web 应用开发框架的情况下,也能利用框架中提供的输入校验功能,从而简化开发流程。

以微软的 .NET Framework 为例,该框架提供了名为“校验控件”的可视化输入校验功能。图 4-9 展示了在 Visual Web Developer 2010 中使用 RangeValidator 校验控件的情形。RangeValidator 能校验输入值的类型与长度范围,可以看出本例中的输入值为 Integer 型,长度范围为 1~100 字符。具体内容请查看图 4-9 中的 TypeMinimumValueMaximumValueErrorMessage 这些属性。

{%}

图 4-9 校验控件中的属性设置

图 4-10 为运行后的页面。

{%}

图 4-10 RangeValidator 的运行示例

截图是输入“101”后将输入焦点移动时的情形。通过 JavaScript 的检验在页面上显示了“请输入范围为 1~100 的整数”的消息。这是在 RangeValidator 的 ErrorMessage 属性中设置的消息。同样的校验也会在服务器端执行。

除 .NET Framework 之外,很多其他的开发框架同样也提供了输入校验的功能,在实际进行开发工作时,可根据情况对其善加利用。

总结

在 Web 应用的入口处,程序会执行以下三类操作,即检验输入字符编码、转换字符编码、输入校验。虽然这些操作并非根本性的安全性策略,但也能够有助于对框架和应用中潜在的安全隐患进行防范。

实施流程如下。

参考:表示“非控制字符的字符”的正则表达式

作为参考,此处介绍一下 PHP、Perl、Java、VB.NET 中表示“非控制字符的字符”的正则表达式。下面各例子的目的都是确认“输入值为 0~100 个字符且不包含控制字符”。

参考文献

[1] 徳丸浩 (.2009 年 6 月 2 日). 主要言語別:入力値検証の具体例~入力に関する対策(3). 参考日期:2011 年 1 月 6 日,参考网址:ITpro: http://itpro.nikkeibp.co.jp/article/COLUMN/20090525/330611/

页面显示处理中会产生的安全性问题有如下两项。

这里,我们将跨站脚本分成 4.3.1(基础篇)和 4.3.2(进阶篇)两部分进行详细讲述。进阶篇将涉及应用程序动态生成的显示内容中包括 URL、JavaScript 和 CSS(Cascading Style Sheets)等的情况。而不涉及动态生成的内容的情况下,则只需彻底掌握基础篇的知识即可。

错误消息导致的信息泄漏将在 4.3.3 节中介绍。

概要

通常情况下,在 Web 应用的网页中,有些部分的显示内容会依据外界输入值而发生变化,而如果生成这些 HTML 的程序中存在问题,就会滋生名为跨站脚本(Cross-Site Scripting)的安全隐患。跨站脚本的英语名称很长,所以经常缩写为 XSS8 。本书也采用 XSS 这一缩写形式。

8 之所以不缩写为 CSS,是为了避免与 Cascading Style Sheets 的缩写混淆。

Web 应用若存在 XSS 漏洞,就会有下列风险。

Web 应用的网页上显示外界传入参数的场所不在少数,只要有一处存在 XSS 漏洞,网站的用户就会有被冒名顶替的风险。

Web 应用中需要防范 XSS 漏洞的地方很多,然而网站运营方却普遍对此疏忽大意,对实施防范措施不够重视。但是,现实中 XSS 攻击是确实存在的,而且 XSS 的受害者也与日俱增,因此,在 Web 应用中采取防范 XSS 漏洞的策略必不可少。

防范 XSS 的策略为,页面显示时将 HTML 中含有特殊意义的字符(元字符)转义(Escape)。具体内容之后会进行详述。

XSS 漏洞总览

{%}

攻击手段与影响

为了更好地理解 XSS 的攻击方法与影响,首先让我们来看一下 XSS 被恶意使用的 3 种方式。

9 IE8 默认启用 XSS 筛选器的情况下,会阻挡通过 XSS 执行的 JavaScript。若要在 IE8 中显示图 4-12 的效果,可以选择“工具”菜单的“Internet 选项”→选择“安全”标签→点击“自定义级别”→脚本→启用 XSS 筛选器→关闭。实验结束后,再将设置改回。

10 实际的攻击中,攻击者会通过设置 CSS 将 iframe 部分隐藏,以不被用户看到。

11 其实 43-091.php 中也存在 XSS 漏洞,但假设攻击者对此并不知情。

12 $_POST 变量前面的“@”为错误控制运算符,用于忽略该 POST 变量未定义时发生的错误。

安全隐患的产生原因

XSS 漏洞产生的原因为,生成 HTML 的过程中,HTML 语法中含有特殊意义的字符(元字符)没有被正确处理,结果导致 HTML 或 JavaScript 被肆意注入,从而使得原先的 HTML 结构产生变化。为了消除元字符的特殊意义,将其转化为普通字符,就需要用到转义(Escape)处理。HTML 的转义处理对于消除 XSS 至关重要。

接下来就让我们来看一下 HTML 中转义的方法,以及不转义时将会遭受的攻击。