网站开发

asp.net
随笔 - 30, 文章 - 0, 评论 - 9, 引用 - 0
数据加载中……

构建安全的数据访问

本页内容http://www.microsoft.com/china/technet/security/guidance/secmod87.mspx
本模块内容 本模块内容
目标 目标
适用范围 适用范围
如何使用本模块 如何使用本模块
威胁与对策 威胁与对策
设计注意事项 设计注意事项
输入验证 输入验证
SQL 注入 SQL 注入
身份验证 身份验证
授权 授权
配置管理 配置管理
敏感数据 敏感数据
异常管理 异常管理
构建安全的数据访问组件 构建安全的数据访问组件
代码访问安全性注意事项 代码访问安全性注意事项
部署注意事项 部署注意事项
小结 小结
其他资源 其他资源

本模块内容

数据访问是使用几个可用的 ADO.NET 数据提供程序之一从 ASP.NET Web 应用程序访问数据库的过程。

此数据库是应用程序级攻击的主要目标。应用程序级攻击用于利用数据访问代码中的漏洞并获取对数据库未授权的访问。如果所有其他攻击方法都已失效,应用程序的前门(即端口 8)将变成攻击者窃取、操纵和破坏数据的可选路径。

本模块说明如何构建安全的数据访问代码,以及如何避免常见的漏洞和缺陷。本模块提供了一系列对策和防御技术,您可以在自己的数据访问代码中使用它们来减少与数据访问有关的主要威胁。

目标

使用本模块可以实现:

设计、构建和部署安全的数据访问代码。

使用代码访问安全性和基于角色的安全性可以限制未经授权的调用方或代码的访问。

安全地验证用户的身份。

防止 SQL 注入攻击。

确保数据库连接字符串的安全。

使用加密机制来保护存储在数据库中的数据。

确保通过网络发送到数据库以及从数据库发送的数据的安全。

使用带有salt 的哈希值将密码安全地存储在数据库中。

实现安全的异常处理。

了解如何使用代码访问安全性,允许中等信任 Web 应用程序使用 OLE DB、Oracle 和 ODBC 数据提供程序(这些提供程序需要完全信任)。

了解应使用哪些对策来解决常见的数据访问威胁,包括 SQL 注入、配置数据泄露、敏感的应用程序数据泄露、数据库架构和连接详细信息的泄露、未授权的访问和网络窃听。

适用范围

本模块适用于下列产品和技术:

Microsoft® Windows® 2000 Server 和 Microsoft Windows Server™ 2003

Microsoft .NET Framework 1.1 和 ASP.NET 1.1

Microsoft SQL Server™

如何使用本模块

为了充分理解本模块内容,请先阅读下列模块或与本模块结合起来阅读:

阅读模块 2 威胁与对策这将使您更广泛深入地了解 Web 应用程序所面临的潜在威胁及其对策。

阅读模块 4 Web 应用程序安全设计指南在本模块中,您将了解构建安全解决方案时所面临的体系结构和设计挑战,以及构建准则。

阅读模块 18 保证数据库服务器的安全阅读模块 18 可了解如何确保数据库服务器的安全。

阅读模块 7 构建安全的程序集模块 7 中构建安全程序集和开发安全托管代码的准则和建议同样应该适用于数据访问代码

使用评估模块。要在产品周期的不同阶段检查数据访问的安全性,请参见下列模块中的“Web 服务”部分:模块 5 安全性体系结构和设计审查、模块 21 代码审查以及模块 22 部署审查。

使用检查表。本指南“检查表”部分中的检查表:保护数据访问包括一个便于参考的检查表。可以将此基于任务的检查表用作本模块中各个建议的摘要。

请注意,在当前版本的 .NET Framework (1.1) 中,只有 ADO.NET SQL Server 数据访问提供程序才支持部分信任调用方,并且可以安全地用在部分信任 Web 应用程序中。OLE DB、Oracle 和 ODBC ADO.NET 数据提供程序需要完全信任。

威胁与对策

要构建安全的数据访问代码,需要了解数据访问代码中的威胁是什么、常见漏洞是如何产生的以及如何使用适当的对策来降低风险。

数据访问代码面临的主要威胁包括:

SQL 注入

配置数据的泄漏

敏感应用程序数据的泄漏

数据库架构和连接详细信息的泄露

未授权的访问

网络窃听

图 14.1 阐明了这些主要威胁。

数据访问代码面临的威胁和攻击

图 14.1
数据访问代码面临的威胁和攻击

SQL 注入

SQL 注入攻击利用易受攻击的数据访问代码,并允许攻击者在数据库中执行任意命令。如果应用程序使用数据库中不受限制的帐户,由于攻击者可以更自由地执行查询和命令,因此受到的威胁会更大。

漏洞

使数据访问代码容易受到 SQL 注入攻击的常见漏洞包括:

弱输入验证

在不使用类型安全的参数时动态构造 SQL 语句

使用特权过高的数据库登录

对策

要应对 SQL 注入攻击,请务必:

限制和净化输入数据。

使用类型安全的 SQL 参数进行数据访问。这些参数可以与存储过程一起使用,也可以是动态构造的 SQL 命令字符串。参数执行类型和长度检查,并同时确保注入数据库中的代码被视为文本数据(而非可执行语句)。

使用在数据库中具有有限权限的帐户。理想情况下,只应向数据库中的选定存储过程授予执行权限,且不提供直接的表格访问权限。

配置数据泄露

数据访问代码所使用的最敏感的配置数据是数据库连接字符串。如果泄漏的连接字符串包括用户名和密码,后果将不堪设想。

漏洞

下列漏洞会增加与泄漏的配置数据相关的安全风险:

使用 SQL 身份验证,这要求在连接字符串中指定凭据

代码中嵌入的连接字符串

配置文件中的明文连接字符串

无法加密连接字符串

对策

要防止配置数据的泄漏:

使用 Windows 身份验证,以便连接字符串中不包含凭据。

加密连接字符串,并限制对已加密数据的访问。

敏感应用程序数据的泄漏

许多应用程序都存储敏感的数据(如客户的信用卡号),一定要保护此类数据的私密性和完整性。

漏洞

下列编码做法可能会导致泄漏敏感的应用程序数据:

存储没有加密的数据

弱授权

弱加密

对策

要防止泄漏敏感的应用程序数据:

使用强加密机制来确保数据的安全。

在执行数据访问之前先为每个调用方授权,以便用户只能看到其各自的数据。

数据库架构和连接详细信息的泄露

如果您的代码向客户端返回异常详细信息,恶意用户可能会使用这些信息来攻击服务器。数据访问代码中的异常可能会透露敏感信息,如数据库架构详细信息、数据存储的特性以及 SQL 代码片断。

漏洞

下列漏洞可能会导致信息泄漏:

不充分的异常处理

薄弱的 ASP.NET 配置(允许未经处理的异常详细信息返回到客户端)

对策

要防止这种泄漏:

捕获、记录和处理数据访问代码中的数据访问异常。

向调用方返回一般的错误消息。这要求对 Web.config 或 Machine.config 配置文件中的 <customErrors> 元素进行适当的配置。

未授权的访问

在授权不足的情况下,用户也许能够看到另一个用户的数据,并且能够访问其他受限制的数据。

漏洞

下列做法可能会允许未授权的访问:

数据访问代码中缺乏授权,从而提供了不受限制的访问

数据库帐户的特权过高

对策

要防止未授权的访问:

按照主体权限需求为调用用户授权。

按照代码访问安全权限需求为调用代码授权。

使用受限制的权限来限制应用程序登录到数据库,并防止直接访问表格。

网络窃听

大多数应用程序的部署体系结构中都包括数据访问代码与数据库服务器之间的物理隔离。因此,必须防止窃听者通过网络窃听敏感数据(如应用程序特定的数据或数据库登录凭据)。

漏洞

下列做法会增加网络窃听的漏洞:

在 SQL 身份验证过程中通过网络传递的明文凭据

进出数据库服务器的未加密敏感应用程序数据

对策

要限制网络窃听的漏洞:

使用 Windows 身份验证来避免通过网络发送凭据。

在数据库服务器上安装一个服务器证书。这会导致自动加密网络上的 SQL 凭据。

在 Web 服务器和数据库服务器之间使用 SSL 连接来保护敏感的应用程序数据。这需要一个数据库服务器证书。

在 Web 和数据库服务器之间使用 IPSec 加密通道。

设计注意事项

在开始编写代码之前,需要在设计时考虑许多重要的问题。主要的注意事项包括:

使用 Windows 身份验证。

使用最小特权帐户。

使用存储过程。

保护所存储的敏感数据。

使用单独的数据访问程序集。

使用 Windows 身份验证

理想情况下,在设计中应该使用 Windows 身份验证,以增加安全性好处。使用 Windows 身份验证,您不必存储具有嵌入凭据的数据库连接字符串,凭据不通过网络传递,而且您可以受益于安全帐户和密码管理策略。但是,您需要认真考虑在使用 Windows 身份验证时,将使用哪个帐户连接到 SQL Server。

有关详细信息,请参阅本模块后面的身份验证

使用最小特权帐户

您的应用程序应该使用在数据库中具有有限权限的最小特权帐户。请确保对应用程序的数据库登录进行了适当的授权和限制。有关详细信息,请参阅本模块后面的授权

使用最小特权帐户可以降低风险,并在您的帐户发生泄漏或者注入了恶意代码时限制潜在的损害。对于 SQL 注入,该命令将在由应用程序登录定义的安全上下文中执行,并遵守该登录在数据库中拥有的相关权限。如果您使用特权过高的帐户(例如,作为 SQL Server sysadmin 角色的成员)进行连接,攻击者能够在服务器上的任何数据库中执行任意操作。这包括插入、更新和删除数据;删除表;执行操作系统命令。

要点 不要使用 sa 帐户或者 SQL Server sysadmin db_owner 角色的任何成员帐户连接到 SQL Server。

使用存储过程

存储过程提供性能、维护和安全性好处。应尽可能使用参数化存储过程进行数据访问。安全性好处包括:

可以限制应用程序数据库登录,以便它只具有执行指定存储过程的权限。没有必要授予直接的表格访问权限。这有助于降低由 SQL 注入攻击造成的风险。

针对传递到存储过程的所有输入数据执行长度和类型检查。同样,不能将参数视为可执行代码。这也会降低 SQL 注入风险。

如果由于某种原因,您无法使用参数化存储过程,但是您需要动态构造 SQL 语句,请使用类型化参数和参数占位符来构造这样的语句,以确保检查输入数据的长度和类型。

保护所存储的敏感数据

标识需要保证私密性和完整性的存储数据。如果您只是为了验证而将密码存储到数据库中,请考虑使用单向哈希。如果密码表发生泄漏,则不能使用哈希来获取明文密码。

如果您存储用户提供的敏感数据(如信用卡号),请使用强对称加密算法(如三重 DES (3DES))来加密数据。使用 Win32 数据保护 API (DPAPI) 加密 3DES 密钥,然后将已加密的密钥存储在具有受限 ACL 的注册表项中,只有管理员和应用程序进程帐户才能使用该注册表项。

为什么不使用 DPAPI?

尽管建议使用 DPAPI 来加密连接字符串和其他可在计算机出现故障时手动恢复和重新构造的机密(如帐户凭据),但仍不太适合存储信用卡号之类的数据。这是由于可恢复性问题(如果密钥丢失,则无法恢复加密数据)和 Web 场问题。相反,应该使用对称加密算法(如 3DES)并使用 DPAPI 加密密钥。

下面概述了造成 DPAPI 不太适合在数据库中存储敏感数据的主要问题:

如果 DPAPI 与计算机密钥一起使用,而且您将 CRYPTPROTECT_LOCAL_MACHINE 传递到 CryptProtectData CryptUnprotectData 函数,则计算机帐户会生成加密密钥。这意味着 Web 场中的每台服务器都有一个不同的密钥,这会禁止一台服务器访问由另一台服务器加密的数据。同样,如果该 Web 服务器计算机被破坏,则密钥会丢失,而且加密的数据无法从数据库进行恢复。

如果使用计算机密钥方法,则该计算机上的任何用户都可以对数据进行解密(除非您使用其他加密机制)。

如果您将 DPAPI 与用户密钥一起使用,而且您使用的是本地用户帐户,就会为每台 Web 服务器上的每个本地帐户生成一个不同的安全标识符 (SID) 和一个不同的密钥,这会禁止一台服务器访问由另一台服务器加密的数据。

如果您将 DPAPI 与用户密钥一起使用,而且您在 Web 场中的计算机之间使用漫游用户配置文件,则所有数据都将共享相同的加密/解密密钥。但是,如果负责漫游用户配置文件帐户的域控制器被损害或被破坏,则无法重新创建具有相同 SID 的用户帐户,而且不能从数据库中恢复加密的数据。

另外,对于漫游用户配置文件,如果某人设法检索该数据,则只要攻击者能够在特定的用户帐户下运行代码,就可以在网络中的任何计算机上解密该数据。这会增加潜在攻击的范围,因此不建议这样做。

使用单独的数据访问程序集

如果您可以进行选择,请避免将数据访问逻辑直接放在 ASP.NET 页或代码隐藏文件中。如果将数据访问逻辑放在一个单独的程序集中,并实现一个与应用程序的业务和表示逻辑分开的逻辑数据访问层,就会带来安全性、重复使用和维护好处。

从安全的角度看,您可以:

对程序集使用强名称以提供可防篡改功能。

使用沙盒技术来隔离数据访问代码,如果您的代码需要支持部分信任调用方(例如,部分信任 Web 应用程序),这一点十分重要。

使用那些按照代码标识权限需求向调用代码授权的数据访问方法和类。

对于深层防御,请按照业务组件中的主体权限需求来执行基于主体的授权,并按照代码标识权限需求来为调用数据访问逻辑的代码授权,如图 14.2 所示。

分开表示层、业务层和数据访问层

图 14.2
表示层、业务层和数据访问层的分离

有关数据访问代码授权的详细信息,请参阅本模块后面的授权部分。

输入验证

除了业务层需要确保数据库保持数据的有效性和一致性之外,还必须在将数据提交到数据库之前验证数据,以防 SQL 注入。如果数据访问代码从当前信任边界内部的其他组件接收其输入内容,而且您知道数据已经过验证(例如,由 ASP.NET 网页或业务组件验证),则数据访问代码会忽略广泛的数据验证。但是,请确保在数据访问代码中使用 SQL 参数,这些参数验证输入参数的类型和长度。下一部分将讨论 SQL 参数的用法。

SQL 注入

当应用程序使用输入内容来构造动态 SQL 语句以访问数据库时,会发生 SQL 注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生 SQL 注入攻击。SQL 注入可能导致攻击者能够使用应用程序登录在数据库中执行命令。如果应用程序使用特权过高的帐户连接到数据库,这种问题会变得很严重。

注意 传统的安全措施(如使用 SSL 和 IPSec)不能防止 SQL 注入攻击。

防止 SQL 注入

使用下列对策来防止 SQL 注入攻击:

限制输入。

使用类型安全的 SQL 参数。

限制输入

验证输入内容的类型、长度、格式和范围。如果您不希望获得数值,则不要接受它们。应该考虑输入内容来自何处。如果它来自受信任源,而且您知道已针对该来源执行过彻底的输入验证,则可以选择在数据访问代码中忽略数据验证。如果数据来自不受信任源或者用于深层防御,则数据访问方法和组件应该验证输入。

使用类型安全的 SQL 参数

SQL 中的 Parameters 集合提供类型检查和长度验证。如果您使用 Parameters 集合,则输入内容将被视为文本值,SQL 不会将其视为可执行代码。使用 Parameters 集合还有一个好处,那就是可以强制进行类型和长度检查。超出范围的值会触发异常。这是深层防御的一个有力示例。

要点 SSL 不能防止 SQL 注入。对于任何应用程序来说,如果它在没有正确的输入验证和适当的数据访问技术的情况下访问数据库,都很容易受到 SQL 注入攻击。

尽可能使用存储过程,并使用 Parameters 集合来调用它们。

结合使用 Parameters 集合和存储过程

下面的代码片断阐释了 Parameters 集合的用法:

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add(
"@au_id", SqlDbType.VarChar, 11);
parm.Value = Login.Text;

在本例中,@au_id 参数被视为文本值,而非可执行代码。另外,还针对参数进行了类型和长度检查。在上例中,输入值不能长于 11 个字符。如果数据不遵循由参数定义的类型或长度,就会生成异常。

请注意,使用存储过程不一定会防止 SQL 注入。重要的是结合使用参数和存储过程。如果不使用参数,则在存储过程使用未筛选的输入内容时,它们很容易受到 SQL 注入攻击。例如,下面的代码片断很容易受到攻击:

SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure '" + 
Login.Text + "'", conn);

要点 如果使用存储过程,请确保同时使用参数。

结合使用 Parameters 集合和动态 SQL

如果您不能使用存储过程,仍可以使用参数,如下面的代码片断所示:

SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id", 
SqlDbType.VarChar, 11);
parm.Value = Login.Text;

使用参数批处理

通常会产生如下误解:如果将几个 SQL 语句连接在一起,以便在单个往返中向服务器发送一批语句,则不能使用参数。但是,如果您能确保参数名不重复,则可以使用这种技术。通过在 SQL 文本连接过程中,向每个参数名中添加一个数字或其他某个唯一值,可以方便地执行此操作。

使用筛选例程

用来防止 SQL 注入攻击的另一种方法是开发筛选例程,以便向具有特殊 SQL 含义的字符添加转义符,如单撇号字符。下面的代码片断阐释了一个用来添加转义符的筛选例程:

private string SafeSqlLiteral(string inputSQL)
{
return inputSQL.Replace("'", "''");
}

这种例程存在着一定的问题,而且您不应完全依赖它们,因为攻击者可以使用 ASCII 十六进制字符来回避检查。但是应该筛选输入内容,并将其作为深层防御策略的一部分。

注意 不要依赖筛选输入。

使用 LIKE 子句

请注意,如果您使用 LIKE 子句,通配符仍需要转义符。下面的代码片断阐释了这种技术:

s = s.Replace("[", "[[]");
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");

身份验证

当应用程序连接到 SQL Server 数据库时,可以在 Windows 身份验证或 SQL 身份验证之间进行选择。Windows 身份验证更安全。如果必须使用 SQL 身份验证(可能由于必须使用许多不同的帐户连接到数据库,并且希望避免调用 LogonUser),请执行其他几个步骤,以尽可能降低额外的风险。

注意 如果使用 LogonUser 创建模拟令牌,需要在 Microsoft Windows 2000 上具有功能强大的“作为操作系统的一部分工作”特权,因此应避免使用此方法。

考虑下面的建议:

使用 Windows 身份验证。

保护 SQL 身份验证的凭据。

使用最小特权帐户进行连接。

使用 Windows 身份验证

Windows 身份验证不通过网络发送凭据。如果对 Web 应用程序使用 Windows 身份验证,请尽可能使用服务帐户或进程帐户(如 ASPNET 帐户)连接到数据库。Windows 和 SQL Server 都必须能够识别您在数据库服务器上使用的帐户。该帐户必须被授予 SQL Server 登录权限,而且需要具有与访问数据库相关的登录权限。

在使用 Windows 身份验证时,必须使用受信任连接。下面的代码片断显示了几个使用 Windows 身份验证的典型的连接字符串。

下例使用面向 SQL Server 的 ADO.NET 数据提供程序:

SqlConnection pubsConn = new SqlConnection(
"server=dbserver; database=pubs; Integrated Security=SSPI;");

下例使用面向 OLE DB 数据源的 ADO.NET 数据提供程序:

OleDbConnection pubsConn = new OleDbConnection(
"Provider=SQLOLEDB; Data Source=dbserver; Integrated Security=SSPI;" +
"Initial Catalog=northwind");

保护 SQL 身份验证的凭据

如果必须使用 SQL 身份验证,请确保凭据不以明文形式通过网络发送,并确保加密包含凭据的数据库连接字符串。

要使 SQL Server 能够自动加密通过网络发送的凭据,请在数据库服务器上安装服务器证书。也可以在 Web 服务器和数据库服务器之间使用 IPSec 加密通道,来确保进出数据库服务器的所有通信的安全。要确保连接字符串的安全,请使用 DPAPI。有关详细信息,请参阅本模块后面配置管理部分中的“确保连接字符串的安全”。

使用最小特权帐户进行连接

应用程序应该通过使用最小特权帐户连接到数据库。如果您使用 Windows 身份验证进行连接,则从操作系统的角度看,Windows 帐户应该是最小特权帐户,而且该帐户应该具有有限的特权和对 Windows 资源的有限的访问能力。另外,无论您使用 Windows 身份验证还是 SQL 身份验证,相应的 SQL Server 登录都应该受到数据库中的权限的限制。

有关如何创建最小特权数据库帐户以及使用 Windows 身份验证将 ASP.NET Web 应用程序连接到远程数据库的选项的详细信息,请参阅模块 19 确保 ASP.NET 应用程序和 Web 服务的安全中的“数据访问”。

授权

如果用户能够检索和操纵特定的数据,就会建立授权过程。有两种方法:数据访问代码可以使用授权来确定是否执行请求的操作,数据库可以通过执行授权来限制应用程序所使用的 SQL 登录的功能。

在授权不足的情况下,用户也许能够看到另一个用户的数据,未授权的用户也许能够访问受限制的数据。要去除这些威胁:

限制未授权的调用方。

限制未授权的代码。

限制数据库中的应用程序。

图 14.3 概述了应该使用的授权点和技术。

数据访问授权、程序集和数据库

图 14.3
数据访问授权、程序集和数据库

注意数据访问代码如何按照权限需求为调用用户或调用代码授权。代码标识需求是 .NET 代码访问安全性的一个特性。

要为数据库中的应用程序授权,请使用只具有执行选定存储过程权限的最小特权 SQL 服务器登录。除非有特殊理由,否则不应为应用程序授予如下权限:直接针对任何表执行创建、检索、更新、破坏/删除 (CRUD) 操作。

注意 存储过程在数据库系统的安全上下文中运行。尽管您可以通过为应用程序分配对特定存储过程的权限来限制它的逻辑操作,但不能限制存储过程所执行的操作的结果。存储过程是受信任代码。必须使用数据库权限来确保存储过程的接口安全。

限制未授权的调用方

您的代码在连接到数据库之前必须基于角色或标识为用户授权。角色检查通常用在应用程序的业务逻辑中,但是,如果您不能清楚地区分业务逻辑和数据访问逻辑,请对数据库访问方法使用主体权限需求。

以下属性确保只有作为 Manager 角色成员的用户才能调用 DisplayCustomerInfo 方法:

[PrincipalPermissionAttribute(SecurityAction.Demand, Role="Manager")]
public void DisplayCustomerInfo(int CustId)
{
}

如果需要其他授权粒度,并且需要在数据访问方法内部执行基于角色的逻辑,请使用命令性主体权限需求或显式的角色检查,如下面的代码片断所示:

using System.Security;
using System.Security.Permissions;

public void DisplayCustomerInfo(int CustId)
{
try
  {
// 用来验证调用方是 manager 的命令性主体权限
// 角色检查
PrincipalPermission principalPerm = new PrincipalPermission(
null, "Manager");
// 仅在调用方是“Manager”角色的成员时才执行
// 随后的代码
  }
catch( SecurityException ex )
  {
   . . .
  }
}

下面的代码片断使用显式的程序设计角色检查来确保调用方是 Manager 角色的成员:

public void DisplayCustomerInfo(int CustId)
{
if(!Thread.CurrentPrincipal.IsInRole("Manager"))
  {
    . . .
  }
}

限制未授权的代码

通过使用 .NET Framework 代码访问安全性(特别是代码标识需求),可以限制能够访问数据访问类和方法的程序集。

例如,如果您只希望由公司或特定开发组织编写的代码能够使用您的数据访问组件,请使用 StrongNameIdentityPermission ,并要求调用程序集具有一个带有指定公钥的强名称,如下面的代码片断所示:

using System.Security.Permissions;
. . .
[StrongNameIdentityPermission(SecurityAction.LinkDemand, 
PublicKey="002...4c6")]
public void GetCustomerInfo(int CustId)
{
}

要提取给定程序集的公钥的文本表示形式,请使用下面的命令:

sn -Tp assembly.dll

注意 –Tp 开关中使用大写的“T”。

因为 Web 应用程序的程序集是动态编译的,所以对于这些程序集不能使用强名称。这使得很难将数据访问程序集的使用限制在特定的 Web 应用程序上。最佳方法是开发一个自定义权限,并要求该权限来自数据访问组件。完全信任 Web 应用程序(或任何完全受信任代码)可以调用您的组件。但是,部分信任代码只有在被授予了自定义权限之后,才能调用您的数据访问组件。

有关自定义权限的示例实现,请参阅本指南“如何”部分中的如何:创建自定义加密权限。

限制数据库中的应用程序

首选方法是为应用程序用来连接到数据库的 Windows 帐户创建一个 SQL Server 登录权限,然后将 SQL Server 登录映射到数据库中的某个数据库用户。将该数据库用户放在用户定义的数据库角色中,并授予该角色相应的权限。理想情况下,应该只为该角色授予对应用程序所使用的存储过程的执行访问权限。

有关如何配置此方法的详细信息,请参阅模块 19 确保 ASP.NET 应用程序和 Web 服务的安全中的“为 ASP.NET 应用程序配置数据访问权限”。

配置管理

数据库连接字符串是针对数据访问代码主要考虑的配置管理问题。应认真考虑这些字符串的存储位置以及如何保护它们(特别是当它们包括凭据时)。要提高加密管理安全性:

使用 Windows 身份验证。

确保连接字符串的安全。

使用受限制的 ACL 确保 UDL 文件的安全。

使用 Window 身份验证

使用 Windows 身份验证时,系统会为您管理凭据,而且凭据不会通过网络传输。还可以避免将用户名和密码嵌入到连接字符串中。

确保连接字符串的安全

如果您需要使用 SQL 身份验证,连接字符串中将包含用户名和密码。如果攻击者利用 Web 服务器上的源代码泄漏这一漏洞或设法登录到该服务器,则攻击者可以检索连接字符串。同样,能够合法登录到该服务器的任何用户都可以查看它们。使用加密机制确保连接字符串的安全。

加密连接字符串

使用 DPAPI 加密连接字符串。使用 DPAPI 加密时,由于加密密钥由平台进行管理,并且绑定到特定的计算机或 Windows 用户帐户,因此可避免出现加密密钥管理问题。要使用 DPAPI,必须通过 P/Invoke 调用 Win32 DPAPI 函数。

有关如何构建托管包装类的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其网址为:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

安全地存储加密的连接字符串

加密的连接字符串可以放在注册表中,也可以放在 Web.config 或 Machine.config 文件中。如果您使用 HKEY_LOCAL_MACHINE 下的注册表项,请将下面的 ACL 应用于该项:

管理员:完全控制
进程帐户:读取

注意 该进程帐户由运行数据访问程序集的进程来确定。这通常是 ASP.NET 进程,或者当您的解决方案使用企业服务中间层时,该进程是企业服务服务器进程。

还可以考虑使用 HKEY_CURRENT_USER,该注册表项提供受限制的访问。有关详细信息,请参阅模块 7 构建安全的程序集中的“注册表”部分。

注意 如果您使用 Microsoft Visual Studio® .NET 数据库连接向导,连接字符串将以明文属性值形式存储在 Web 应用程序代码隐藏文件或 Web.config 文件中。这两种方法都应该避免使用。

为了更容易部署,您可能希望将加密的字符串存储在 Web.config 中,尽管这可能不如使用受限制的注册表项安全。在本例中,将使用如下所示的自定义 <appSettings> 名称-值对:

<configuration>
<appSettings>  
<add key="connectionString" value="AQA..bIE=" />
</appSettings>
<system.web>
   ...
</system.web>
</configuration>

要从 <appSettings> 元素访问密码文本,请使用如下所示的 ConfigurationSettings 类:

using System.Configuration;
private static string GetConnectionString()
{
return ConfigurationSettings.AppSettings["connectionString"];
}

不要将 Persist Security Info 设置为“True”或“Yes”

如果在连接字符串中包括 Persist Security Info 属性,将导致 ConnectionString 属性在密码返回给用户之前,将密码从连接字符串中去除。在建立与数据库的连接之后,默认设置 false(等同于忽略 Persist Security Info 属性)会丢弃该信息。

使用受限制的 ACL 确保 UDL 文件的安全

如果您的应用程序结合使用外部通用数据链接 (UDL) 文件和面向 OLE DB 的 ADO.NET 托管数据提供程序,请使用 NTFS 权限来限制访问。使用以下受限制的 ACL:

管理员:完全控制
进程帐户:读取

注意 UDL 文件未进行加密。一个更安全的方法是,使用 DPAPI 加密连接字符串,并将其存储在受限制的注册表项中。

敏感数据

许多 Web 应用程序都在数据库中以某种形式存储敏感数据。如果攻击者设法针对您的数据库执行查询,则务必要适当地加密所有敏感数据项(如信用卡号)。

加密需要存储的敏感数据。

确保网络上敏感数据的安全。

使用带有salt 的哈希值存储密码。

加密需要存储的敏感数据

尽可能避免存储敏感数据。如果必须存储敏感数据,请对其进行加密。

使用 3DES 加密

要将敏感数据(如信用卡号)存储在数据库中,请使用强对称加密算法,如 3DES。

在开发过程中,要启用 3DES 加密

1.

使用 RNGCryptoServiceProvider 类来生成强(192 位,24 字节)加密密钥。

2.

备份加密密钥,并将备份副本存储在物理安全的位置。

3.

使用 DPAPI 对密钥进行加密,并将其存储在注册表项中。使用下面的 ACL 来确保注册表项的安全:

管理员:完全控制
进程帐户(例如,ASPNET):读取

在运行时,要将加密数据存储在数据库中

1.

获取要加密的数据。

2.

从注册表中检索经过加密的加密密钥。

3.

使用 DPAPI 对加密密钥进行解密。

4.

结合使用 TripleDESCryptoServiceProvider 类和加密密钥来加密数据。

5.

将加密数据存储在数据库中。

在运行时,要对加密的机密进行解密

1.

从数据库中检索加密数据。

2.

从注册表中检索经过加密的加密密钥。

3.

使用 DPAPI 对加密密钥进行解密。

4.

使用 TripleDESCryptoServiceProvider 类对加密数据进行解密。

在此过程中,如果用来对加密密钥进行加密的 DPAPI 帐户被损坏,则可以从备份位置检索 3DES 密钥的备份,并在新帐户下使用 DPAPI 对该备份进行加密。新的加密密钥可以存储在注册表中,数据库中的数据仍可以进行解密。

有关创建托管 DPAPI 库的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”中“How To”部分中的“How To: Create a DPAPI Library”,其网址为:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

保护网络上敏感数据的安全

通过网络传入和传出数据库服务器的敏感数据可能包括应用程序特定的数据或数据库登录凭据。为了确保网络上的数据的私密性和完整性,可以使用平台级解决方案(如由安全数据中心提供的解决方案,在这种解决方案中,在服务器之间使用 IPSec 加密的通信通道),也可以对您的应用程序进行配置,以便与数据库建立 SSL 连接。后一种方法需要在数据库服务器上安装服务器证书。

有关使用 SSL 和 IPSec 的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use IPSec to Provide Secure Communication Between Two Servers”和“How To:Use SSL to Secure Communication to SQL Server 2000”,其网址为:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)

使用带有salt 的哈希值存储密码

如果您需要实现一个包含用户名和密码的用户存储,请不要以明文或加密格式来存储密码。存储增加了 salt 的不可逆哈希值(而不是存储密码)可以降低词典攻击的风险。

注意 salt 值是密码形式的强随机数字。

创建 Salt 值

下面的代码显示了如何通过使用随机数字生成功能(此功能由 System.Security.Cryptography 命名空间中的 RNGCryptoServiceProvider 类提供)来生成 salt 值。

public static string CreateSalt(int size)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}

创建 Hash 值(带有 Salt)

下面的代码片断显示了如何从所提供的密码和 salt 值生成哈希值。

public static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = string.Concat(pwd, salt);
string hashedPwd = 
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "SHA1");
return hashedPwd;
}

详细信息

有关实现用户存储(使用带有salt 的哈希值存储密码)的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use Forms Authentication with SQL Server 2000”,其网址为:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

异常管理

异常条件可能会由配置错误、代码中的错误或恶意输入引起。如果没有正确的异常管理,这些条件可能会透露有关数据源位置和特性的敏感信息,以及有价值的连接详细信息。下面的建议适用于数据访问代码:

捕获和记录 ADO.NET 异常。

确保数据库连接总是处于断开状态。

在 ASP.NET 应用程序中使用一般错误页面。

捕获和记录 ADO.NET 异常

将数据访问代码放在 try/catch 块中并处理异常。在编写 ADO.NET 数据访问代码时,由 ADO.NET 生成的异常类型取决于数据提供程序。例如:

SQL Server .NET Framework 数据提供程序生成 SqlException

OLE DB .NET Framework 数据提供程序生成 OleDbException

ODBC .NET Framework 数据提供程序生成 OdbcException

捕获异常

下面的代码使用 SQL Server .NET Framework 数据提供程序,并显示应该如何捕获类型为 SqlException 的异常。

try
{
// 数据访问代码
}
catch (SqlException sqlex) // 比较具体
{
}
catch (Exception ex) // 比较一般
{
}

记录异常

还应该记录来自 SqlException 类的详细信息。此类公开那些包含异常条件详细信息的属性。这些属性包括 Message 属性(用来描述错误)、Number 属性(用来唯一标识错误类型)以及 State 属性(其中包含其他信息)。State 属性通常用来指示特定错误条件出现的具体位置。例如,如果某个存储过程从多个行中生成同一错误,则 State 属性可以指出错误出现的具体位置。最后,Errors 集合中包含 SqlError 对象,这些对象提供详细的 SQL 服务器错误信息。

下面的代码片断显示了如何通过使用 SQL Server .NET Framework 数据提供程序来处理 SQL Server 错误条件:

using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;

// 由数据访问层 (DAL) 组件公开的方法
public string GetProductName( int ProductID )
{
SqlConnection conn = new SqlConnection(
"server=(local);Integrated Security=SSPI;database=products");
// 将所有的数据访问代码包含在 try 块中
try
  {
conn.Open();
SqlCommand cmd = new SqlCommand("LookupProductName", conn );
cmd.CommandType = CommandType.StoredProcedure;

cmd.Parameters.Add("@ProductID", ProductID );
SqlParameter paramPN = 
cmd.Parameters.Add("@ProductName", SqlDbType.VarChar, 40 );
paramPN.Direction = ParameterDirection.Output;

cmd.ExecuteNonQuery();
// 在该方法返回之前先执行 finally 代码
return paramPN.Value.ToString();  
  }
catch (SqlException sqlex)
  {
// 处理数据访问异常条件
// 记录具体的异常详细信息
LogException(sqlex);
// 将当前异常包装在一个相关性更强的
// 外部异常中,并重新引发新异常
throw new Exception(
"Failed to retrieve product details for product ID: " + 
ProductID.ToString(), sqlex );
  }
finally
  {
conn.Close(); // 确保连接处于断开状态
  }
}

// Helper 例程,该例程将 SqlException 详细信息记录到
// 应用程序事件日志中
private void LogException( SqlException sqlex )
{
EventLog el = new EventLog();
el.Source = "CustomAppLog";
string strMessage;
strMessage = "Exception Number :" + sqlex.Number + 
"(" + sqlex.Message + ") has occurred";
el.WriteEntry( strMessage );

foreach (SqlError sqle in sqlex.Errors)
  {
strMessage = "Message:" + sqle.Message +
" Number:" + sqle.Number +
" Procedure:" + sqle.Procedure +
" Server:" + sqle.Server +
" Source:" + sqle.Source +
" State:" + sqle.State +
" Severity:" + sqle.Class +
" LineNumber:" + sqle.LineNumber;
el.WriteEntry( strMessage );
  }
}

确保数据库连接总是处于断开状态

如果发生异常,一定要断开数据库连接,并释放其他所有受限制的资源。使用 finally 块或 C# using 语句,可以确保无论是否发生了异常条件,都会断开数据库连接。上面的代码阐释了 finally 块的用法。还可以按如下方式使用 C# using 语句:

using ((SqlConnection conn = new SqlConnection(connString)))
{
conn.Open();
// 在以下情况下将断开连接:生成异常或者控制流
// 通常会离开 using 语句的使用范围
}

在 ASP.NET 应用程序中使用一般错误页面

如果您的数据访问代码由 ASP.NET Web 应用程序或 Web 服务调用,则应该对 <customErrors> 元素进行配置,以防异常详细信息传播回到最终用户。还可以通过使用该元素来指定一般错误页面,如下所示。

<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />

对于生产服务器设置 mode="On"。只有在发布之前开发和测试软件时才使用 mode="Off"。如果不这样做,将导致向最终用户返回大量错误信息(如图 14.4 中显示的信息)。这些信息可能包含数据库服务器的名称、数据库名称和连接凭据。

详细的异常信息会透露敏感数据

图 14.4
详细的异常信息会透露敏感数据

图 14.4 还显示了数据访问代码中接近导致异常的行的大量漏洞。特别是:

连接字符串是硬编码的。

特权极高的 sa 帐户用于连接到数据库。

sa 帐户有一个弱密码。

SQL 命令的构造容易受到 SQL 注入攻击;输入内容未进行验证,代码不使用参数化存储过程。

构建安全的数据访问组件

下面的代码显示了 CheckProductStockLevel 方法(用来在产品数据库中查询库存量)的示例实现,该代码阐释了本模块前面介绍的数据访问代码的许多重要安全功能。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using Microsoft.Win32;
using DataProtection;

public static int CheckProductStockLevel(string productCode)
{
int quantity = 0;
// (1) 由 try/catch 块保护的代码
try
  {
// (2) 使用正则表达式验证的输入内容
//     应该从资源程序集中检索错误消息,以帮助实现
//     本地化。为简短起见,省略了 Localization(本地化)代码。
if (Regex.IsMatch(productCode, "^[A-Za-z0-9]{12}$") == false)
throw new ArgumentException("Invalid product code" );
//(3) using 语句确保连接被断开
using (SqlConnection conn = new SqlConnection(GetConnectionString()))
    {
// (4) 使用参数化存储过程可以应对
//     SQL 注入攻击
SqlCommand cmd = new SqlCommand("spCheckProduct", conn);
cmd.CommandType = CommandType.StoredProcedure;

// 对参数的类型进行检查
SqlParameter parm = 
cmd.Parameters.Add("@ProductCode", 
SqlDbType.VarChar,12);
parm.Value = productCode;
// 定义输出参数
SqlParameter retparm = cmd.Parameters.Add("@quantity", SqlDbType.Int);
retparm.Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
quantity = (int)retparm.Value;
    }
  }
catch (SqlException sqlex)
  {
// (5) 记录完整的异常详细信息。一般(安全的)错误消息
//     基于 SQL 错误代码返回调用方
//     为清楚起见,省略了日志和错误标识代码
throw new Exception("Error Processing Request");
  }
catch (Exception ex)
  {
// 记录完整的异常详细信息
throw new Exception("Error Processing Request");
  }
return quantity;
}

// (6) 将加密的数据库连接字符串存保留在注册表中
private static string GetConnectionString()
{
// 从注册表中检索密码文本;进程帐户必须
// 由注册表项的 ACL 授予“读取”访问权限
string encryptedString = (string)Registry.LocalMachine.OpenSubKey(
@"Software\OrderProcessing\")
.GetValue("ConnectionString");
// 使用托管的 DPAPI helper 库对该字符串进行解密
DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE);
byte[] dataToDecrypt = Convert.FromBase64String(encryptedString);
return Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null));
}

上面的代码显示出下列安全特征(由注释行中的数字进行标识)。

1.

数据访问代码放在 try/catch 块中。这是防止在出现异常时将系统级信息返回到调用方所必需的。调用 ASP.NET Web 应用程序或 Web 服务会处理异常,并向客户端返回适当的一般错误消息,但是数据访问代码不依赖这些消息。

2.

使用正则表达式验证输入。检查所提供的产品 ID,以便验证它只包含 A–Z 和 0–9 范围内的字符,而且不超过 12 个字符。这是旨在防止 SQL 注入攻击的一组对策中的第一个。

3.

SqlConnection 对象是在 Microsoft Visual C#® using 语句的内部创建的。这可确保无论是否发生了异常,都断开方法内部的连接。这会降低拒绝服务攻击的威胁,该威胁尝试使用到数据库的所有可用连接。通过使用 finally 块可以实现类似的功能。

4.

参数化存储过程用于数据访问。这是防止 SQL 注入的另一个对策。

5.

不向客户端返回详细的错误信息。记录异常详细信息,以便帮助诊断问题。

6.

加密的数据库连接字符串存储在注册表中。存储数据库连接字符串最安全的方法之一是,使用 DPAPI 加密该字符串,并将加密的密码文本存储在具有受限 ACL 的受保护的注册表项中。(例如,使用“管理员:完全控制”和“ASP.NET 或企业服务进程帐户:读取”,具体情况取决于由哪个进程托管该组件。)

注意 该代码显示了如何从注册表检索连接字符串,然后使用托管的 DPAPI helper 库对其进行解密。此库在“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的 How To: Create a DPAPI Library (英文)中提供。

代码访问安全性注意事项

所有的数据访问都遵循代码访问安全权限需求。您所选择的 ADO.NET 托管数据提供程序可以确定精确的要求。下表显示了对于每个 ADO.NET 数据提供程序必须授予数据访问程序集的权限。

表 14.1:ADO.NET 数据提供程序所需的代码访问安全权限

ADO.NET 数据提供程序 所需的代码访问安全权限

SQL Server

SqlClient
PermissionSupports 部分信任调用方(包括中等信任 Web 应用程序)。

OLE DB

OleDbPermission*

Oracle

OraclePermission*

ODBC

OdbcPermission*

*撰写本文时,在 1.0 和 1.1 版本的 .NET Framework上,OLE DB、Oracle 和 ODBC 提供程序只支持完全信任调用方。要从部分信任 Web 应用程序中使用这些提供程序,必须将您的数据访问代码放在沙盒中,这需要一个专门的数据访问程序集。有关显示如何将数据访问代码放在沙盒中以及如何从中等信任 Web 应用程序中使用 OLE DB 数据提供程序的示例,请参阅模块 9 ASP.NET 代码访问安全性。

如果您使用 ADO.NET SQL Server 数据提供程序,您的代码就必须由代码访问安全策略授予 SqlClientPermission。完全和中等信任 Web 应用程序具有此权限。

代码能否连接到 SQL Server 由代码是否被授予了 SqlClientPermission 来确定。还可以使用权限对数据库连接字符串的使用进行限制。例如,可以强制应用程序使用集成安全性,或者可以确保在使用 SQL Server 安全性时不接受空白密码。如果违反通过 SqlClientPermission 指定的规则,将会导致运行时安全异常。

有关如何使用 SqlClientPermission 来限制数据访问的详细信息,请参阅模块 8 代码访问安全的实践中的“数据访问”。

部署注意事项

以安全方式设计和开发的数据访问组件如果不以安全的方式进行部署,仍然容易受到攻击。常见的部署做法是使数据访问代码和数据库驻留在单独的服务器上。这些服务器通常由内部防火墙隔开,这就引进了额外的部署注意事项。开发人员和管理员应该了解下列问题:

防火墙限制

连接字符串管理

登录帐户配置

登录审核

网络上的数据私密性和完整性

防火墙限制

如果您通过防火墙连接到 SQL Server,请配置防火墙、客户端和服务器。可通过使用 SQL Server 客户端网络实用程序来配置客户端,并使用服务器网络实用程序配置数据库服务器。在默认情况下,SQL Server 侦听 TCP 端口 1433,但您可以更改此设置。必须在防火墙上打开所选端口。

根据您所选择的 SQL Server 身份验证模式以及应用程序对分布式事务的使用方式,您可能需要在防火墙上打开几个其他端口:

如果应用程序使用 Windows 身份验证连接到 SQL Server,则必须打开支持 Kerberos 或 NTLM 身份验证所必需的端口。

对于不使用 Active Directory 的网络,TCP 端口 139 通常是 Windows 身份验证所必需的。有关端口要求的详细信息,请参阅 TechNet 文章“TCP and UDP Port Assignments”和“Security Considerations for Administrative Authority”,前者的网址为:http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/tcpip/part4/tcpappc.asp(英文),后者的网址为:http://www.microsoft.com/technet/security/bestprac/bpent/sec2/seconaa.asp(英文)

如果您的应用程序使用分布式事务(例如,自动化 COM+ 事务),您可能还需要对防火墙进行配置,以便允许 DTC 通信在单独的 DTC 实例之间以及 DTC 和资源管理器(如 SQL Server)之间流动。

有关完整配置的详细信息,请参阅模块 18 保证数据库服务器的安全中的“端口”部分。

连接字符串管理

许多应用程序都将连接字符串存储在代码中,这主要是为了提高性能。但是,性能优势是可以忽略的,而且使用文件系统缓存有助于确保外部文件中的连接字符串能够提供相当的性能。使用外部文件存储连接字符串对于系统管理极其有益。

为了增加安全性,建议使用 DPAPI 来加密连接字符串。如果您的连接字符串包含用户名和密码,这一点尤为重要。然后,确定在何处存储加密的字符串。注册表是安全的存储位置,特别是在您使用 HKEY_CURRENT_USER 时,因为只有在相关用户帐户下运行的进程才能进行访问。为了使部署更加容易,还可以将加密的字符串存储在 Web.config 文件中。这两种方法已在本模块前面的配置管理部分讨论过。

登录帐户配置

一定要让您的应用程序使用最小特权帐户来连接到数据库,这是降低 SQL 注入攻击威胁的主要方法之一。

作为开发人员,您必须与数据库管理员进行协商,以确定应用程序登录需要访问的确切的存储过程和(可能的)表。在理想情况下,您应该只允许应用程序登录对随应用程序一起部署的一组有限的存储过程具有执行权限。

应该对 SQL 或 Windows 帐户、或应用程序连接到数据库所使用的帐户使用强密码。

有关针对数据库中的应用程序帐户的建议授权策略,请参阅本模块前面的授权部分。

登录审核

应该将 SQL Server 配置为记录失败的登录尝试和可能成功的登录尝试。审核失败的登录尝试有助于检测到尝试发现帐户密码的攻击者。

有关如何配置 SQL Server 审核的详细信息,请参阅模块 18 保证数据库服务器的安全。

网络上的数据私密性和完整性

如果您使用 SQL 身份验证连接到 SQL Server,请确保不通过网络暴露登录凭据。可以在数据库服务器上安装一个证书(这会导致 SQL Server 加密凭据),或者使用数据库的 IPSec 加密通道。

建议使用数据库的 IPSec 或 SSL 通道来保护传入和传出数据库的敏感的应用程序级数据。有关详细信息,请参阅模块 18 保证数据库服务器的安全。

小结

本模块显示了数据访问代码的几种主要威胁,并重点介绍了常见的漏洞。SQL 注入是应该注意的主要威胁之一。除非您使用本模块中讨论的正确对策,否则攻击者会利用您的数据访问代码在数据库中运行任意命令。传统的安全措施(如防火墙和 SSL)对 SQL 注入攻击不提供任何防御功能。您应该彻底验证自己的输入内容,并将参数化存储过程用作最基本的防御措施。

其他资源

有关详细信息,请参阅下列资源:

有关可打印的检查表,请参阅本指南“检查表”部分中的检查表:保护数据访问。

有关保护开发人员工作站的详细信息,请参阅本指南“如何”部分中的如何:保护开发人员工作站。

有关结合使用 SSL 和 SQL Server 的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use SSL to Secure Communication with SQL Server 2000”,其网址为:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT19.asp(英文)。

有关使用 IPSec 的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use IPSec to Provide Secure Communication Between Two Servers”,其网址为:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT18.asp(英文)。

有关使用 DPAPI 的详细信息,请参阅“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其网址为:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT07.asp(英文)。


posted on 2006-11-17 15:08 风雨兼程 阅读(423) 评论(0)  编辑  收藏 所属分类: Asp.net


只有注册用户登录后才能发表评论。


网站导航: