连接字符串和配置文件

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

重要

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

应用程序配置文件

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

connectionStrings 部分

连接字符串可以以键/值对的形式存储在应用程序配置文件的connectionStrings元素的configuration部分中。 子元素包括 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 中的条目。添加clear后紧接connectionStrings元素,这将删除内存中数据结构的所有继承引用,这样就只考虑在本地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 并使其可供应用程序使用。 你无需额外编写任何代码来管理解密过程。

受保护配置提供程序

受保护的配置提供程序在本地 configProtectedData 计算机上的 machine.config 文件的部分中注册,如以下片段所示,其中显示了 .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 应用程序的 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={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 网站

另请参阅