连接字符串和配置文件

在应用程序代码中嵌入连接字符串可能导致安全漏洞和维护问题。 使用 Ildasm.exe(IL 反汇编程序)工具可以查看编译到应用程序源代码中的未加密连接字符串。 此外,如果连接字符串发生更改,则必须重新编译应用程序。 因此,我们建议您将连接字符串存储在应用程序配置文件中。

重要

Microsoft 建议使用最安全的可用身份验证流。 如果要连接到 Azure SQL,建议使用 Azure 资源的托管标识这种身份验证方法。

应用程序配置文件

应用程序配置文件包含特定应用程序特有的设置。 例如,ASP.NET 应用程序能包含一个或多个 web.config 文件,Windows 应用程序可能包含一个可选 app.config 文件。 虽然配置文件的名称和位置会因应用程序宿主的不同而有所不同,但配置文件可以有相同的元素。

connectionStrings 部分

连接字符串可作为键/值对存储在应用程序配置文件 configuration 元素的 connectionStrings 节中。 子元素包括 add、clear 和 remove

下面的配置文件片段演示用于存储连接字符串的架构和语法。 name 属性是你提供用来唯一标识连接字符串的名称,以便在运行时可以检索到该字符串。 providerName 是 .NET Framework 数据提供程序的固定名称,此名称登入 machine.config 文件中

<?xml version='1.0' encoding='utf-8'?>
  <configuration>
    <connectionStrings>
      <clear />
      <add name="Name"
       providerName="System.Data.ProviderName"
       connectionString="Valid Connection String;" />
    </connectionStrings>
  </configuration>

备注

您可以将连接字符串的一部分保存在配置文件中,并使用 DbConnectionStringBuilder 类在运行时将该字符串补充完整。 如果你预先不知道连接字符串的元素,或者不希望将敏感信息保存到配置文件中,这一方法会很有用。 有关详细信息,请参阅连接字符串生成器

使用外部配置文件

外部配置文件是单独的文件,此类文件包含由一部分组成的配置文件的片段。 外部配置文件由主配置文件引用。 如果在部署完应用程序后连接字符串可能会被编辑,那么将 connectionStrings 节存储在物理上独立的文件中会很有用。 例如,标准 ASP.NET 行为是在修改配置文件后重新启动应用程序域,这将导致状态信息丢失。 然而,修改外部配置文件不会导致重新启动应用程序。 外部配置文件并不局限于由 ASP.NET 使用,Windows 应用程序也可以使用。 此外,文件访问安全性和权限也可以用于限制对外部配置文件的访问。 运行时使用外部配置文件是透明的,且不需要特殊编码。

若要将连接字符串存储在外部配置文件中,请创建一个只包含 connectionStrings 节的单独的文件。 不要包含任何其他的元素、节或属性。 此示例演示外部配置文件的语法。

<connectionStrings>
  <add name="Name"
   providerName="System.Data.ProviderName"
   connectionString="Valid Connection String;" />
</connectionStrings>

在主应用程序配置文件中,可以使用 configSource 属性指定外部文件的完全限定名和位置。 此示例引用名为 connections.config 的外部配置文件。

<?xml version='1.0' encoding='utf-8'?>
<configuration>
    <connectionStrings configSource="connections.config"/>
</configuration>

运行时检索连接字符串

.NET Framework 2.0 在 System.Configuration 命名空间中引入了新类,以简化在运行时从配置文件检索连接字符串的操作。 您可以以编程方式按名称或提供程序名称检索连接字符串。

备注

machine.config 文件还包含 connectionStrings 节,此节包含 Visual Studio 使用的连接字符串。 当按提供程序名称从 Windows 应用程序中的 app.config 文件检索连接字符串时,首先加载 machine.config 中的连接字符串,然后加载 app.config 中的项。在 connectionStrings 元素删除所有继承自内存中数据结构的引用后将立即添加 clear,以便只考虑在本地 app.config 文件中指定的连接字符串。

使用配置类

从 .NET Framework 2.0 开始,当使用本地计算机上的配置文件时,将使用 ConfigurationManager,从而替换已不推荐使用的 ConfigurationSettings 类。 WebConfigurationManager 与 ASP.NET 配置文件一起使用。 该管理器可以使用 Web 服务器上的配置文件,并允许以编程方式访问配置文件节(如 system.web)

备注

在运行时访问配置文件需要对调用方授予权限,根据应用程序类型、配置文件和位置确定所需的权限。 有关详细信息,请参阅 ASP.NET 应用程序的 WebConfigurationManager 和 Windows 应用程序的 ConfigurationManager

您可以使用 ConnectionStringSettingsCollection 从应用程序配置文件中检索连接字符串。 它包含 ConnectionStringSettings 对象的集合,每个对象表示 connectionStrings 节中的一项。 它的属性 (Property) 映射为连接字符串属性 (Attribute),从而允许您通过指定名称或提供程序名称来检索连接字符串。

属性 描述
Name 连接字符串的名称。 映射到 name 属性
ProviderName 完全限定提供程序名。 映射到 providerName 属性
ConnectionString 连接字符串。 映射到 connectionString 属性

示例:列出所有连接字符串

此示例循环访问 ConnectionStringSettingsCollection,并在控制台窗口中显示 ConnectionStringSettings.NameConnectionStringSettings.ProviderNameConnectionStringSettings.ConnectionString 属性。

注意

System.Configuration.dll 并不包含在所有项目类型中,你可能需要对其设置引用才能使用配置类。 特定应用程序配置文件的名称和位置因应用程序类型和宿主进程的不同而有所不同。

using System.Configuration;

static class Program
{
    static void Main()
    {
        GetConnectionStrings();
        Console.ReadLine();
    }

    static void GetConnectionStrings()
    {
        ConnectionStringSettingsCollection settings =
            ConfigurationManager.ConnectionStrings;

        foreach (ConnectionStringSettings cs in settings)
        {
            Console.WriteLine(cs.Name);
            Console.WriteLine(cs.ProviderName);
            Console.WriteLine(cs.ConnectionString);
        }
    }
}
Imports System.Configuration

Class Program
    Shared Sub Main()
        GetConnectionStrings()
        Console.ReadLine()
    End Sub

    Private Shared Sub GetConnectionStrings()

        Dim settings As ConnectionStringSettingsCollection = _
            ConfigurationManager.ConnectionStrings

        If Not settings Is Nothing Then
            For Each cs As ConnectionStringSettings In settings
                Console.WriteLine(cs.Name)
                Console.WriteLine(cs.ProviderName)
                Console.WriteLine(cs.ConnectionString)
            Next
        End If
    End Sub
End Class

示例:按名称检索连接字符串

此示例演示如何通过指定连接字符串名称从配置文件中检索连接字符串。 此代码创建一个 ConnectionStringSettings 对象,以将提供的输入参数与 ConnectionStrings 名称相匹配。 如果未找到匹配名称,则该函数返回 null(在 Visual Basic 中返回 Nothing)。

// Retrieves a connection string by name.
// Returns null if the name is not found.
static string? GetConnectionStringByName(string name)
{
    // Look for the name in the connectionStrings section.
    ConnectionStringSettings? settings =
        ConfigurationManager.ConnectionStrings[name];

    // If found, return the connection string (otherwise return null)
    return settings?.ConnectionString;
}
' Retrieves a connection string by name.
' Returns Nothing if the name is not found.
Private Shared Function GetConnectionStringByName( _
    ByVal name As String) As String

    ' Assume failure
    Dim returnValue As String = Nothing

    ' Look for the name in the connectionStrings section.
    Dim settings As ConnectionStringSettings = _
       ConfigurationManager.ConnectionStrings(name)

    ' If found, return the connection string.
    If Not settings Is Nothing Then
        returnValue = settings.ConnectionString
    End If

    Return returnValue
End Function

示例:按提供程序名称检索连接字符串

此示例演示如何通过指定 System.Data.ProviderName 格式的提供程序固定名称来检索连接字符串。 此代码循环访问 ConnectionStringSettingsCollection,并返回找到的第一个 ProviderName 的连接字符串。 如果未找到提供程序名称,则该函数返回 null(在 Visual Basic 中返回 Nothing)。

// Retrieve a connection string by specifying the providerName.
// Assumes one connection string per provider in the config file.
static string? GetConnectionStringByProvider(string providerName)
{
    // Get the collection of connection strings.
    ConnectionStringSettingsCollection? settings =
        ConfigurationManager.ConnectionStrings;

    // Walk through the collection and return the first
    // connection string matching the providerName.
    if (settings != null)
    {
        foreach (ConnectionStringSettings cs in settings)
        {
            if (cs.ProviderName == providerName)
            {
                return cs.ConnectionString;
            }
        }
    }
    return null;
}
' Retrieve a connection string by specifying the providerName.
' Assumes one connection string per provider in the config file.
Private Shared Function GetConnectionStringByProvider( _
    ByVal providerName As String) As String

    'Return Nothing on failure.
    Dim returnValue As String = Nothing

    ' Get the collection of connection strings.
    Dim settings As ConnectionStringSettingsCollection = _
        ConfigurationManager.ConnectionStrings

    ' Walk through the collection and return the first 
    ' connection string matching the providerName.
    If Not settings Is Nothing Then
        For Each cs As ConnectionStringSettings In settings
            If cs.ProviderName = providerName Then
                returnValue = cs.ConnectionString
                Exit For
            End If
        Next
    End If

    Return returnValue
End Function

使用受保护的配置加密配置文件节。

ASP.NET 2.0 引入了一个称为“受保护配置”的新功能,可以通过此功能来加密配置文件中的敏感信息。 虽然受保护配置主要是为 ASP.NET 应用程序设计的,但它也可以用于加密 Windows 应用程序中的配置文件节。

下面的配置文件片段演示加密后的 connectionStrings 节。 configProtectionProvider 可指定用于加密和解密连接字符串的受保护配置提供程序。 EncryptedData 节包含密文

<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAH2... </CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

在运行时检索加密连接字符串时,.NET Framework 会使用指定的提供程序来解密 CipherValue 并将其提供给应用程序。 你无需额外编写任何代码来管理解密过程。

受保护配置提供程序

受保护配置提供程序是在本地计算机的 machine.config 文件的 configProtectedData 节中注册的(如下面的片段所示),此片段演示 .NET Framework 附带的两个受保护配置提供程序。 此处显示的值已被截断,以便于阅读。

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
  <providers>
    <add name="RsaProtectedConfigurationProvider"
      type="System.Configuration.RsaProtectedConfigurationProvider" />
    <add name="DataProtectionConfigurationProvider"
      type="System.Configuration.DpapiProtectedConfigurationProvider" />
  </providers>
</configProtectedData>

可以配置其他受保护配置提供程序,方法是将它们添加到 machine.config 文件中。 还可以通过从 ProtectedConfigurationProvider 抽象基类继承来创建自己的受保护配置提供程序。 下表描述了 .NET Framework 附带的两个配置文件。

提供程序 描述
RsaProtectedConfigurationProvider 使用 RSA 加密算法来加密和解密数据。 RSA 算法既可用于公钥加密,也可用于数字签名。 它还称为“公共密钥”或非对称加密,因为它使用两个不同的密钥。 可以使用 ASP.NET IIS 注册工具 (Aspnet_regiis.exe) 来加密 Web.config 文件中的节和管理加密密钥。 ASP.NET 在处理配置文件时解密该文件。 ASP.NET 应用程序的标识必须对用于加密和解密各加密节的加密密钥具有读取权限。
DpapiProtectedConfigurationProvider 使用 Windows Data Protection API (DPAPI) 来加密配置节。 它使用 Windows 内置加密服务,并可为计算机特定或用户帐户特定保护进行配置。 对于同一服务器上需要共享信息的多个应用程序来说,计算机特定保护非常有用。 用户帐户特定保护可与以特定用户标识运行的服务(如共享宿主环境)一起使用。 每个应用程序以单独的标识运行,这样就限制了对文件和数据库等资源的访问。

这两种提供程序都可以对数据进行强加密。 但是,如果计划在多台服务器(如网络场)上使用相同的加密配置文件,则只有通过 RsaProtectedConfigurationProvider 才能导出用于加密数据的加密密钥,并将其导入其他服务器。 有关详细信息,请参阅导入和导出受保护配置的 RSA 密钥容器

使用配置类

System.Configuration 命名空间提供以编程方式使用配置设置的类。 ConfigurationManager 类可提供对计算机、应用程序和用户配置文件的访问。 如果要创建 ASP.NET 应用程序,可以使用 WebConfigurationManager 类,它可提供相同的功能,同时还允许访问 ASP.NET 应用程序特有的设置(如 <system.web> 中的设置)。

备注

System.Security.Cryptography 命名空间包含提供用于加密和解密数据的其他选项的类。 如果需要采用在使用受保护配置时不可用的加密服务,请使用这些类。 一些类是非托管 Microsoft CryptoAPI 的包装类,而其他类则是纯托管实现。

App.config 示例

此示例演示如何对 Windows 应用程序的 app.config 文件中的 connectionStrings 节的加密进行切换。 在此示例中,该过程将应用程序的名称(例如“MyApplication.exe”)作为一个参数。 然后,对 app.config 文件进行加密,并采用名称“MyApplication.exe.config”将其复制到包含可执行文件的文件夹中。

代码使用 OpenExeConfiguration 方法打开 app.config 文件以进行编辑,GetSection 方法返回 connectionStrings 节。 然后,代码检查 IsProtected 属性,调用 ProtectSection 以加密未加密的节。 调用 UnprotectSection 方法以加密该节。 (连接字符串只能在加密的计算机上解密。)该方法 Save 会完成此操作并保存更改。

必须在要运行代码的项目中添加对 System.Configuration.dll 的引用。

重要

Microsoft 建议使用最安全的可用身份验证流。 如果要连接到 Azure SQL,建议使用 Azure 资源的托管标识这种身份验证方法。

static void ToggleConfigEncryption(string exeFile)
{
    // Get the application path needed to obtain
    // the application configuration file.

    // Takes the executable file name without the
    // .config extension.
    var exePath = exeFile.Replace(".config", "");

    try
    {
        // Open the configuration file and retrieve
        // the connectionStrings section.
        Configuration config = ConfigurationManager.
            OpenExeConfiguration(exePath);

        var section =
            config.GetSection("connectionStrings")
            as ConnectionStringsSection;

        if (section != null)
        {
            if (section.SectionInformation.IsProtected)
            {
                // Remove encryption.
                section.SectionInformation.UnprotectSection();
            }
            else
            {
                // Encrypt the section.
                section.SectionInformation.ProtectSection(
                    "DataProtectionConfigurationProvider");
            }
        }
        // Save the current configuration.
        config.Save();

        Console.WriteLine("Protected={0}",
            section?.SectionInformation.IsProtected);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Shared Sub ToggleConfigEncryption(ByVal exeConfigName As String)
    ' Takes the executable file name without the
    ' .config extension.
    Try
        ' Open the configuration file and retrieve 
        ' the connectionStrings section.
        Dim config As Configuration = ConfigurationManager. _
            OpenExeConfiguration(exeConfigName)

        Dim section As ConnectionStringsSection = DirectCast( _
            config.GetSection("connectionStrings"), _
            ConnectionStringsSection)

        If section.SectionInformation.IsProtected Then
            ' Remove encryption.
            section.SectionInformation.UnprotectSection()
        Else
            ' Encrypt the section.
            section.SectionInformation.ProtectSection( _
              "DataProtectionConfigurationProvider")
        End If

        ' Save the current configuration.
        config.Save()

        Console.WriteLine("Protected={0}", _
        section.SectionInformation.IsProtected)

    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try
End Sub

Web.config 示例

此示例使用 OpenWebConfigurationWebConfigurationManager 方法。 在这种情况下,可以通过使用波形符来提供 Web.config 文件的相对路径。 代码需要对 System.Web.Configuration 类的引用。

static void ToggleWebEncrypt()
{
    // Open the Web.config file.
    Configuration config = WebConfigurationManager.
        OpenWebConfiguration("~");

    // Get the connectionStrings section.
    var section =
        config.GetSection("connectionStrings")
        as ConnectionStringsSection;

    // Toggle encryption.
    if (section.SectionInformation.IsProtected)
    {
        section.SectionInformation.UnprotectSection();
    }
    else
    {
        section.SectionInformation.ProtectSection(
            "DataProtectionConfigurationProvider");
    }

    // Save changes to the Web.config file.
    config.Save();
}
Shared Sub ToggleWebEncrypt()
    ' Open the Web.config file.
    Dim config As Configuration = WebConfigurationManager. _
      OpenWebConfiguration("~")

    ' Get the connectionStrings section.
    Dim section As ConnectionStringsSection = DirectCast( _
        config.GetSection("connectionStrings"), _
        ConnectionStringsSection)

    ' Toggle encryption.
    If section.SectionInformation.IsProtected Then
        section.SectionInformation.UnprotectSection()
    Else
        section.SectionInformation.ProtectSection( _
          "DataProtectionConfigurationProvider")
    End If

    ' Save changes to the Web.config file.
    config.Save()
End Sub

有关保护 ASP.NET 应用程序的详细信息,请参阅保护 ASP.NET 网站

另请参阅