在ASP.NET中通过X509证书进行客户端认证

28

我有一个asp.net应用程序,需要使用X509证书对用户进行身份验证。也就是说,用户必须安装由我发布的证书才能浏览我的网站,并且我可以通过此证书识别用户。

我已经在IIS上配置了SSL,但这不是我现在要寻找的内容,而且我不知道从哪里开始。

如何在asp.net c#中实现这一目标?

2个回答

25
为创建一个安全的身份验证机制,您需要同时使用客户端证书和用户名/密码。原因是证书可以被盗窃(复制),但密码只有用户本人知道。另一种选择是在智能卡上保护PIN的证书。
要在ASP.NET应用程序中使用客户端证书,您需要执行以下操作:
步骤1: 在IIS管理器中打开您的应用程序或网站,选择SSL设置,并选择需要SSL和需要客户端证书。
现在当用户打开您的网站时,浏览器将提示他选择将在通信中使用的客户端证书。
重要提示: 此时您必须确保证书由您信任的人颁发(因为任何人都可以创建自签名证书)。
步骤2: 添加一个配置项(web.config、数据库等)。在此列表中,您将添加客户端证书的整个CA(证书颁发机构)链的指纹。
<add key="ClientCertificateIssuerThumbprints" value="4901f5b87d736cd88792bd5ef7caee91bf7d1a2b,0113e31aa85d7fb02740a1257f8bfa534fb8549e,c9321de6b5a82666cf6971a18a56f2d3a8675602"/>

步骤三:创建一个经典的用户名/密码登录页面。验证用户名和密码。
步骤四:将以下代码添加到您的登录页面:
var x509 = new X509Certificate2(this.Request.ClientCertificate.Certificate);
var chain = new X509Chain(true);
chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
chain.Build(x509);

var validThumbprints = new HashSet<string>(
    System.Configuration.ConfigurationManager.AppSettings["ClientCertificateIssuerThumbprints"]
        .Replace(" ", "").Split(',', ';'),
    StringComparer.OrdinalIgnoreCase);

// if the certificate is self-signed, verify itself.
for (int i = chain.ChainElements.Count > 1 ? 1 : 0; i < chain.ChainElements.Count; i++)
{
    if (!validThumbprints.Contains(chain.ChainElements[i].Certificate.Thumbprint))
        throw new UnauthorizedAccessException("The client certificate selected is not authorized for this system. Please restart the browser and pick the certificate issued by XXXXX");
}

// certificate Subject would contain some identifier of the user (an ID number, SIN number or anything else unique). here it is assumed that it contains the login name and nothing else
if (!string.Equals("CN=" + login, x509.Subject, StringComparison.OrdinalIgnoreCase))
    throw new UnauthorizedAccessException("The client certificate selected is authorized for another user. Please restart the browser and pick another certificate.");

只有在验证了密码和证书之后,才应该允许用户进入系统。

如果客户端可以将证书导出并安装在任何地方,那么证书的意义是什么?用户名/密码可以确保用户的真实性,但我还需要确保机器的真实性。 - enb081
1
可以安装证书,以便私钥(用于身份验证)无法导出。一些笔记本电脑允许您将证书安装在硬件芯片中。另一种选择是将证书存储在智能卡中。 - Knaģis
1
如果您认为客户端证书足够,您可以将其用于身份验证:http://www.iis.net/configreference/system.webserver/security/authentication/iisclientcertificatemappingauthentication - flup
我同意,我也想对工作站进行身份验证。但我认为适合我的解决方案是使用一对多的客户端证书,并为每个客户端证书生成元数据以识别工作站(元数据需要加密以提高安全性)。 - TheLegendaryCopyCoder
能否使用证书对用户进行身份验证,而无需提供登录名和密码?用户只需使用带有证书的智能卡,系统将自动登录? - Eru

13
假设您拥有IIS 7.0或更高版本,则可以配置客户端证书映射身份验证。 使用Active Directory(非常简单,将映射工作留给AD服务器)。
<location path="Default Web Site">
   <system.webServer>
      <security>
         <access sslFlags="Ssl, SslNegotiateCert" />
          <authentication>
            <windowsAuthentication enabled="false" />
            <anonymousAuthentication enabled="false" />
            <digestAuthentication enabled="false" />
            <basicAuthentication enabled="false" />
            <clientCertificateMappingAuthentication enabled="true" />
         </authentication>
     </security>
   </system.webServer>
</location>

或者 使用 IIS(需要在 IIS 中进行更多配置,需要访问客户端证书,但是可以独立工作,无需往返 AD)。在这种情况下,您需要指定(一个或多个)用户凭据,并且
  • 将每个用户映射到证书的公钥,以及指定其凭据的用户,或者
  • 基于证书字段中的值将多个证书映射到用户

配置(多对一):

<location path="Default Web Site">
   <system.webServer>
      <security>
         <authentication>
            <windowsAuthentication enabled="false" />
            <anonymousAuthentication enabled="false" />
            <digestAuthentication enabled="false" />
            <basicAuthentication enabled="false" />
            <iisClientCertificateMappingAuthentication enabled="true"
                  manyToOneCertificateMappingsEnabled="true">
               <manyToOneMappings>
                  <add name="Contoso Employees"
                        enabled="true"
                        permissionMode="Allow"
                        userName="Username"
                        password="[enc:AesProvider:57686f6120447564652c2049495320526f636b73:enc]">
                     <rules>
                        <add certificateField="Subject"
                           certificateSubField="O"
                           matchCriteria="Contoso"
                           compareCaseSensitive="true" />
                     </rules>
                  </add>
               </manyToOneMappings>
            </iisClientCertificateMappingAuthentication>
         </authentication>
         <access sslFlags="Ssl, SslNegotiateCert" />
      </security>
   </system.webServer>
</location>

(示例配置有点抄袭iis.net文档页面上的样本,这些样本相当复杂。)

或者您可以将应用程序配置为使用基于声明的身份验证,使用安全令牌服务(STS)验证客户端基于客户端证书的身份。 ADFS 2.0可以担任此角色,如果不可用,则可以考虑Thinktecture Identity Server


AspNet Core 2.0 有什么新的更新吗? - Vikas Rana
我们如何在 .NET Core 2.x 中实现这个? - Ask

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接