授权
授权确定已通过验证的标识可以执行哪些操作以及可以访问哪些资源。错误授权或弱授权会导致信息泄漏和数据篡改。深入防御是应用程序授权策略的关键安全原则。
以下做法可以增强 Web 应用程序的授权:
• | 使用多重看守。 |
• | 限制用户对系统级资源的访问。 |
• | 考虑授权粒度。 |
使用多重看守
在服务器端,可以使用 IP 安全协议 (IPSec) 策略提供主机限制,以此来限制服务器间的通信。例如,IPSec 策略可以限制远离指定 Web 服务器的任何主机连接到数据库服务器。IIS 提供了 Web 权限、Internet 协议/域名系统 (IP/DNS) 限制。无论用户是什么身份,IIS 的 Web 权限适用于所有通过 HTTP 请求的资源。如果攻击者设法登录到服务器,IIS 的 Web 权限将不提供保护功能。因此,NTFS 权限允许您为每个用户指定访问控制列表。最后,ASP.NET 提供 URL 授权和文件授权以及主要权限需求。将这些看守方法结合使用,可以制定出有效的授权策略。
限制用户对系统级资源的访问
系统级资源包括文件、文件夹、注册表项、Active Directory 对象、数据库对象、事件日志,等等。使用 Windows 访问控制列表 (ACL) 限制哪些用户可以访问哪些资源,以及可以执行哪些类型的操作。要特别注意匿名 Interne 用户帐户;使用 ACL 锁定这些匿名帐户,以防止他们访问明确拒绝匿名用户访问的资源。
有关使用 Windows ACL 锁定匿名 Internet 用户帐户的详细信息,请参阅模块 16:保护 Web 服务器。
考虑授权粒度
有三个常用的授权模型,每个模型都具有不同的粒度和可伸缩性。
最多粒度法建立在模拟的基础上。资源访问是使用调用方的安全上下文实现的。安全资源(通常指文件或表格,或二者都包括)上的 Windows ACL 确定是否允许调用方访问该资源。如果应用程序主要提供对用户特定资源的访问,那么这种方法可能是有效的。它还具有另一个优点,即能够跨应用层执行操作系统级审核,因为原始调用方的安全上下文在操作系统级传送,并用于资源访问的依据。然而,如果应用程序的可伸缩性较差,这种方法的效果会受影响,因为不存在高效的数据库访问连接池。因此,此方法通常应用于规模有限的基于 Intranet 的应用程序中。图 4.5 显示了模拟模型。
图 4.5
模拟模型提供了每位最终用户的授权粒度
最少粒度最大伸缩性方法使用应用程序的过程标识来访问资源。此方法支持数据库连接池,但这说明授予数据库中应用程序标识的权限是公用的,而不考虑原始调用方的标识。初级授权是在应用程序的逻辑中间层通过角色实现的,角色将在应用程序中共享相同权限的用户分为一组。基于调用方的角色成员身份来限制其对类和方法的访问权限。为了支持对用户个人数据的检索,常用方法是在数据库表中添加一个标识列,并使用查询参数限制检索到的数据。例如,可以在应用程序级(而不是操作系统级)使用存储的过程参数将原始调用方的标识传递到数据库中,然后编写类似如下所示的查询语句:
SELECT field1,field2,field3 FROM Table1 WHERE {some search criteria} AND UserName = @originalCallerUserName
此模型被认为是受信任的子系统,有时还被称作受信任的服务器模型。图 4.6 列出了该模型。
图 4.6
支持数据库连接池的受信任子系统模型
第三种方法基于调用方的角色成员身份,使用有限的标识集进行资源访问。实际上它是前面所述的两种模型的综合。调用方被映射到应用程序逻辑中间层中的角色,并基于角色成员身份限制对类和方法的访问权限。使用由当前调用方的角色成员身份所确定的有限标识集来执行下游资源访问。该方法的优势在于可以在每次登录数据库时单独分配权限,而多重连接池仍然有效。多线程访问令牌使用 Windows 验证为下游资源访问建立不同的安全上下文。此方法的劣势在于创建这种令牌是一种特权操作,需要使用特权进程帐户。这是与最少特权原则相违背的。混合模型使用多重受信任服务标识管理对下游资源的访问权限,图 4.7 中显示了这种模型。
图 4.7
混合模型
配置管理
应该仔细考虑 Web 应用程序的配置管理功能。大多数应用程序需要使用接口,通过接口,内容开发人员、操作员和管理员可以配置应用程序和管理事项,如 Web 页内容、用户帐户、用户配置文件信息和数据库连接字符串。如果支持远程管理,如何确保管理界面的安全?如果管理界面存在安全漏洞,结果会很严重,因为攻击者常常利用管理员特权中止程序运行,并能直接访问整个站点。
以下做法可以提高 Web 应用程序配置管理的安全性:
• | 确保管理界面的安全。 |
• | 确保配置存储的安全。 |
• | 维护单独的管理特权。 |
• | 使用最少特权进程和服务帐户。 |
确保管理界面的安全
配置管理功能只能由经过授权的操作员和管理员访问,这一点是非常重要的。关键一点是要在管理界面上实施强身份验证,如使用证书。
如果有可能,限制或避免使用远程管理,并要求管理员在本地登录。如果需要支持远程管理,应使用加密通道,如 SSL 或 VPN 技术,因为通过管理界面传递的数据是敏感数据。此外,还要考虑使用 IPSec 策略限制对内部网络计算机的远程管理,以进一步降低风险。
确保配置存储的安全
基于文本的配置文件、注册表和数据库是存储应用程序配置数据的常用方法。如有可能,应避免在应用程序的 Web 空间使用配置文件,以防止可能出现的服务器配置漏洞导致配置文件被下载。无论使用哪种方法,都应确保配置存储访问的安全,如使用 Windows ACL 或数据库权限。还应避免以纯文本形式存储机密,如数据库连接字符串或帐户凭据。通过加密确保这些项目的安全,然后限制对包含加密数据的注册表项、文件或表的访问权限。
单独分配管理特权
如果应用程序的配置管理功能所支持的功能性基于管理员角色而变化,则应考虑使用基于角色的授权策略分别为每个角色授权。例如,负责更新站点静态内容的人员不必具有更改客户信贷限额的权限。
使用最少特权进程和服务帐户
应用程序配置的一个重要方面是用于运行 Web 服务器进程的进程帐户,以及用于访问下游资源和系统的服务帐户。应确保为这些帐户设置最少特权。如果攻击者设法控制一个进程,则该进程标识对文件系统和其他系统资源应该具有极有限的访问权限,以减少可能造成的危害。
敏感数据
处理诸如信用卡号、地址、病例档案等用户私人信息的应用程序应该采取专门的步骤,来确保这些数据的保密性,并确保其不被修改。另外,实现应用程序时所用的机密数据(如数据库连接字符串)必须是安全的。在永久性存储中存储敏感数据以及在网络上传递敏感数据时,数据的安全性是一个需要解决的问题。
机密
机密包括密码、数据库连接字符串和信用卡号。以下做法可以提高 Web 应用程序机密数据处理的安全性:
• | 尽量避免存储机密。 |
• | 不要在代码中存储机密。 |
• | 不要以纯文本形式存储数据库连接、密码或密钥。 |
• | 避免在本地安全性机构 (LSA) 中存储机密。 |
• | 使用数据保护 API (DPAPI) 对机密数据加密。 |
尽量避免存储机密
在软件中以完全安全的方式存储机密是不可能的。可以接触到服务器的系统管理员可以访问这些数据。例如,当您所要做的仅仅是验证用户是否知道某个机密时,则没有必要存储该机密。在这种情况下,可以存储代表机密的哈希值,然后使用用户提供的值计算哈希值,以验证该用户是否知道该机密。
不要在代码中存储机密
不要在代码中对机密进行硬编码。即使不将源代码暴露在 Web 服务器上,但从编译过的可执行文件中仍然可以提取字符串常量。配置漏洞可能会允许攻击者检索可执行文件。
不要以纯文本形式存储数据库连接、密码或密钥
避免以纯文本形式存储诸如数据库连接字符串、密码和密钥之类的机密。使用加密,并存储经过加密的字符串。
避免在 LSA 中存储机密
避免使用 LSA,因为只有具有管理特权的应用程序才能访问它。而这一点违反了以最少特权运行的核心安全原则。另外,LSA 只能在有限数量的插槽中存储机密。更好的方法是使用 DPAPI,Microsoft Windows® 2000及其以后的操作系统都提供了该功能。
使用 DPAPI 对机密数据加密
要存储诸如数据库连接字符串或服务帐户凭据之类的机密,应使用 DPAPI。使用 DPAPI 的主要优势在于由平台系统管理加密/解密密钥,而不是由应用程序负责。密钥依附于 Windows 用户帐户或特定计算机,这取决于传递到 DPAPI 函数的标志。
当主密钥丢失时(例如,因为服务器被损坏而需要重新安装操作系统),DPAPI 最适合于为可手动重建的信息加密。 对于有些数据(如客户信用卡详细信息),因为不知道其纯文本值而不能恢复,这时需要使用另外一种方法,即使用基于密钥的传统对称加密法,如使用 triple–DES。
有关从 Web 应用程序使用 DPAPI 的详细信息,请参阅模块10:构建安全的 ASP.NET 网页和控件。
敏感的用户个人数据
必须保护敏感数据,如登录凭据和应用程序级数据(如信用卡号、银行帐户号等)。通过加密获得的保密性和通过消息验证代码 (MAC) 获得的完整性是重要因素。
以下做法可以提高 Web 应用程序中敏感的用户个人数据的安全性:
• | 根据需要检索敏感数据。 |
• | 对数据进行加密或确保通信通道的安全。 |
• | 不要在永久性 cookie 中存储敏感数据。 |
• | 不要使用 HTTP-GET 协议传递敏感数据。 |
根据需要检索敏感数据
首选方法是根据需要检索敏感数据,而不是将其保留或高速缓存在内存中。例如,在需要已加密的机密时对其进行检索,然后在解密后使用该数据,最后清空用于保留纯文本机密的内存(变量)。如果考虑性能因素,请注意以下几个选项:
• | 缓存已加密的机密。 |
• | 缓存纯文本机密。 |
缓存已加密的机密
应用程序加载时检索机密,然后将已加密的机密缓存在内存中,当应用程序使用该机密时再将其解密。当程序不再需要该机密时,清除其纯文本副本。这种方法避免了每次请求都要访问数据存储。
缓存纯文本机密
避免因多次解密机密而造成的系统开销,并将机密的纯文本副本存储在内存中。这是最不安全的做法,却提供了最好的性能。在权衡提高了的性能和增大的安全风险之前,应对其他方法做基准检查。
对数据进行加密或确保通信通道的安全
如果在网络上向客户端发送敏感数据,应对数据进行加密或确保通信通道的安全。通常的做法是在客户端与 Web 服务器之间使用 SSL。服务器间的通信通常使用 IPSec。要确保通过多重中间件传输的敏感数据的安全性,如 Web 服务简单对象访问协议 (SOAP) 消息,应使用消息级加密。
不要在永久性 cookie 中存储敏感数据
避免在永久性 cookie 中存储敏感数据。如果存储的是纯文本数据,最终用户能够看到并修改该数据。如果对其加密,必须考虑密钥管理。例如,如果用于加密 cookie 中的数据的密钥已过期且已被回收,则新密钥不能对客户端通过浏览器传递的永久性 cookie 进行解密。
不要使用 HTTP-GET 协议传递敏感数据
应避免使用 HTTP-GET 协议存储敏感数据,因为该协议使用查询字符串传递数据。使用查询字符串不能确保敏感数据的安全性,因为查询字符串经常被服务器记录下来。
会话管理
Web 应用程序基于无界限的 HTTP 协议构建,因此,会话管理是应用程序级职责。对于应用程序总体安全来讲,会话安全是关键因素。
以下做法可以提高 Web 应用程序会话管理的安全性:
• | 使用 SSL 保护会话身份验证 cookie。 |
• | 对身份验证 cookie 的内容进行加密。 |
• | 限制会话寿命。 |
• | 避免未经授权访问会话状态。 |
使用 SSL 保护会话身份验证 Cookie
不要通过 HTTP 连接传递身份验证 cookie。在授权 cookie 内设置安全的 cookie 属性,以便指示浏览器只通过 HTTPS 连接向服务器传回 cookie。有关详细信息,请参阅模块 10:构建安全的 ASP.NET 网页和控件。
对身份验证 cookie 的内容进行加密
即使使用 SSL,也要对 cookie 内容进行加密。如果攻击者试图利用 XSS 攻击窃取 cookie,这种方法可以防止攻击者查看和修改该 cookie。在这种情况下,攻击者仍然可以使用 cookie 访问应用程序,但只有当 cookie 有效时,才能访问成功。
限制会话寿命
缩短会话寿命可以降低会话劫持和重复攻击的风险。会话寿命越短,攻击者捕获会话 cookie 并利用它访问应用程序的时间越有限。
避免未经授权访问会话状态
考虑会话状态的存储方式。为获得最佳性能,可以将会话状态存储在 Web 应用程序的进程地址空间。然而这种方法在 Web 场方案中的可伸缩性和内涵都很有限,来自同一用户的请求不能保证由同一台服务器处理。在这种情况下,需要在专用状态服务器上进行进程外状态存储,或者在共享数据库中进行永久性状态存储。ASP.NET 支持所有这三种存储方式。
对于从 Web 应用程序到状态存储之间的网络连接,应使用 IPSec 或 SSL 确保其安全,以降低被窃听的危险。另外,还需考虑 Web 应用程序如何通过状态存储的身份验证。在可能的地方使用 Windows 验证,以避免通过网络传递纯文本身份验证凭据,并可利用安全的 Windows 帐户策略带来的好处。
加密
基本加密方式提供:
• | 保密性 (机密性)。此服务保持数据的机密性。 |
• | 认可(真实性)。此服务确保用户不能拒绝发送特定消息。 |
• | 防止篡改(完整性)。此服务防止数据被修改。 |
• | 身份验证。此服务确认消息发送方的身份。 |
Web 应用程序通常使用加密方式来确保永久性存储中的数据或在网络上传输的数据的安全性。在使用加密方法时,下列做法可以提高 Web 应用程序的安全性:
• | 不要自创加密方法。 |
• | 将未加密数据存储在算法附近。 |
• | 使用正确的算法和密钥大小。 |
• | 确保加密密钥的安全。 |
不要自创加密方法
成功开发出加密算法和例程是非常难的。因此,应使用平台提供的经过验证和测试的加密服务。这包括 .NET 框架和基础操作系统。不要开发自定义的实现方法,因为这通常会导致保护能力减弱。
将未加密数据存储在算法附近
向算法传递纯文本时,除非需要使用,否则不要获取该数据,并要以尽可能少的修改存储该数据。
使用正确的算法和密钥大小
是否为一项作业选择了正确的算法非常重要,另外,应确保所使用的密钥大小能提供足够的安全级别。密钥越大,安全性越高。以下列表概括了主要算法及其使用的密钥大小:
• | 数据加密标准 (DES) 64 位密钥(8 个字节) |
• | TripleDES 128 位密钥或 192 位密钥(16 或 24 个字节) |
• | Rijndael 128 – 256 位密钥(16 – 32 个字节) |
• | RSA 384 – 16,384 位密钥(48 – 2,048 个字节) |
对于大量数据加密,应使用 TripleDES 对称加密算法。要减慢并加强对大量数据的加密,应使用 Rijndael 算法。要对将暂时存储的数据加密,可以考虑使用较快但较弱的算法,如 DES。对于数字签名,应使用 RSA 或 DSA 算法。对于哈希,应使用 SHA1.0 算法。对于用户键入的哈希,应使用基于哈希的消息验证代码(HMAC)SHA1.0 算法。
确保加密密钥的安全
加密密钥是输入加密及解密进程的秘密数字。为保证加密数据的安全,必须保护好密钥。一旦攻击者得到了解密密钥,加密数据就不再安全了。
以下做法将有助于确保加密密钥的安全:
• | 使用 DPAPI 来回避密钥管理。 |
• | 定期回收密钥。 |
使用 DPAPI 来回避密钥管理
如前所述,使用 DPAPI 的主要优势之一在于密钥管理问题是由操作系统处理的。DPAPI 使用的密钥是从密码中导出的,该密码与调用 DPAPI 函数的进程帐户相关联。使用 DPAPI 将密钥管理的任务交给操作系统。
定期回收密钥
通常,保持不变的机密数据很容易随着时间的推移而被发现。必须牢记以下问题:是否在什么地方写下了密钥?了解这些机密的管理员是否已更换职位或离职?不要过度使用密钥。
参数操作
利用参数操作攻击,攻击者能够修改在客户端与 Web 应用程序间发送的数据。此数据可能是使用查询字符串、表单字段、cookie 或 HTTP 头发送的。以下做法有助于确保 Web 应用程序参数操作的安全:
• | 加密敏感的 cookie 状态。 |
• | 确保用户没有绕过检查。 |
• | 验证从客户端发送的所有值。 |
• | 不要信任 HTTP 头信息。 |
机密敏感的 cookie 状态
Cookie 中可能包含敏感数据,如会话标识符或用作服务器端授权进程一部分的数据。要保护该类型数据,应使用加密方法对 cookie 的内容加密。
确保用户没有绕过检查
确保用户没有通过操作参数而绕过检查。最终用户可以通过浏览器地址文本框操作 URL 参数。例如,URL 地址 http://www.<YourSite>/<YourApp>/sessionId=10 包含一个值 10,通过将该值更改为其他随机数字,可以得到不同的输出。应确保在服务器端代码中执行上述检查,而不是在客户端的 JavaScript 中检查,因为可以在浏览器中禁用 JavaScript。
验证从客户端发送的所有数据
限制可接受用户输入的字段,并对来自客户端的所有值进行修改和验证。如果表单字段中包含预定义值,用户可以更改这些值,并将其传回服务器,以得到不同的结果。只接受已知的有益数据。例如,如果输入字段面向一个州,那么只有与该州邮政编码匹配的输入才能被接受。
不要信任 HTTP 头信息
HTTP 头在 HTTP 请求和响应开始时发送。应确保 Web 应用程序的任何安全决策都不是基于 HTTP 头中包含的信息,因为攻击者很容易操作 HTTP 头。例如,HTTP 头中的“referer”字段包含发出请求的网页的 URL。不要基于“referer”字段值作出任何安全决策,以检查发出请求的页面是否由该 Web 应用程序生成,因为该字段很容易伪造。
异常管理
安全的异常处理有助于阻止某些应用程序级拒绝服务攻击,还可用来防止对攻击者有用的宝贵系统级信息被返回给客户端。例如,如果没有正确的异常处理机制,数据库架构详细信息、操作系统版本、堆栈跟踪、文件名和路径信息、SQL 查询字符串以及对攻击者有用的其他信息可以被返回给客户端。
一种好的方法是设计一个集中式异常管理和记录解决方案,并考虑在异常管理系统中提供挂钩,以支持规范和集中式监视,从而为系统管理员提供帮助。
以下做法有助于确保 Web 应用程序异常管理的安全:
• | 不要向客户端泄漏信息。 |
• | 记录详细的错误信息。 |
• | 捕捉异常。 |
不要向客户端泄漏信息
发生故障时,不要暴露将会导致信息泄漏的消息。例如,不要暴露包括函数名以及调试内部版本时出问题的行数(该操作不应在生产服务器上进行)的堆栈跟踪详细信息。应向客户端返回一般性错误消息。
记录详细的错误信息
向错误日志发送详细的错误消息。应该向服务或应用程序的客户发送最少量的信息,如一般性错误消息和自定义错误日志 ID,随后可以将这些信息映射到事件日志中的详细消息。确保没有记录密码或其他敏感数据。
捕捉异常
使用结构化异常处理机制,并捕捉异常现象。这样做可以避免将应用程序置于不协调的状态,这种状态可能会导致信息泄漏。它还有助于保护应用程序免受拒绝服务攻击。确定如何在应用程序内部广播异常现象,并着重考虑在应用程序的边界会发生什么事情。
有关设计和实现 .NET 应用程序异常管理框架的详细信息,请参阅 MSDN 文章“Exception Management Architecture Guide”,其网址为:http://msdn.microsoft.com/library/en-us/dnbda/html/exceptdotnet.asp(英文)。
审核和记录
应该审核和记录跨应用层的活动。使用日志,可以检测到踪迹可疑的活动。这通常能较早地发现成熟攻击的迹象,日志还有助于解决抵赖问题,即用户拒绝承认其行为的问题。在证明个人错误行为的法律程序中,可能需要使用日志文件作为证据。通常情况下,如果审核的生成时间恰好是资源访问的时间,并且使用相同的资源访问例程,则审核是最具权威性的。
以下做法可以提高 Web 应用程序的安全性:
• | 审核并记录跨应用层的访问。 |
• | 考虑标识流。 |
• |