【问题标题】:Why is Request.ClientCertificate empty for some certificates but not others?为什么某些证书的 Request.ClientCertificate 为空,而其他证书则为空?
【发布时间】:2019-04-06 01:23:05
【问题描述】:

我正在尝试构建一个 AuthorizeAttribute,它要求 HTTPRequest 包含指定的客户端证书。

我在这里找到了我认为是关于这些问题的一系列博客文章,作者是 Andras Nemes:

我有一个测试 Web API 项目在 VS2015 中运行,针对在我的本地 IIS 上运行的站点进行调试,而不是 IIS Express,配置了 https 并设置了 SSL 设置以允许客户端证书。

我很确定它设置正确,因为它适用于我创建的证书之一。

我的属性很简单:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class KtRequireClientCertAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        byte[] cert = HttpContext.Current.Request.ClientCertificate.Certificate;
        // if the ClientCertificate is empty, pass null
        X509Certificate2 suppliedCert = cert.Any() ? new X509Certificate2(cert) : null;

        if (suppliedCert != null && isExpectedCert(suppliedCert)
            return;

        base.OnAuthorization(actionContext);
    }
}

我的问题 - 这适用于我上周按照 Andras 的说明创建的证书之一。

ClientCertificate.Certificate 是一个包含 808 个元素的 byte[],X509Certificate2 构造正确,我的验证逻辑按预期工作。

但是对于我今天尝试创建的每个证书,HttpContext.Current.Request.ClientCertificate.Certificate 都是空的。

我正在制作证书:

MAKECERT.EXE -ic DevRootCertificate.cer -iv DevRootCertificate.pvk -pe -sv testclientcert.pvk -a sha1 -n "CN=testclientcert" -len 2048 -b 01/01/2015 -e 01/01/2030 -sky exchange testclientcert.cer -eku 1.3.6.1.5.5.7.3.2

我的测试客户端应用很简单:

using (var requestHandler = new WebRequestHandler())
{
    var certificate = new X509Certificate2(certificateFile);
    requestHandler.ClientCertificates.Add(certificate);

    var url = new Uri(baseUrl);
    using (var client = new HttpClient(requestHandler){BaseAddress = url})
    {
        var response = client.GetAsync(endPoint).Result;
        response.EnsureSuccessStatusCode();

        var content = response.Content.ReadAsStringAsync().Result;

        Console.Out.WriteLine(JToken.Parse(content).ToString(Formatting.Indented));
    }
}

问题是为什么一个证书被传递给属性而另一个没有?


附加信息:

我在同一个服务器上运行同一个客户端,在我本地机器上的 IIS 上运行。该网站被配置为接受但不要求客户端证书。

有效的测试运行和无效的测试运行之间的唯一区别是我从哪个 .cer 文件加载证书。

我不确定有效的证书是否有私钥,但有效的文件是 .cer,而不是 .pfx。

无效的文件也是 .cer。我知道它没有签名。所以我创建了一个签名证书并尝试使用 .pfx 文件构建 X509Certificate2() 。我什至没有访问服务器就收到 403 错误。

【问题讨论】:

  • 仔细检查您使用的是https:// 而不是http://
  • 我正在使用与失败证书相同的证书 URL。
  • 一个是 PFX 而另一个是 CER 吗?您需要私钥才能正确使用它; ClientCertificates 中 cert.HasPrivateKey 为 false 的任何证书都将被忽略。
  • 您是否连接到相同的服务器?并非所有 TLS (HTTPS) 服务器都需要通过证书进行客户端身份验证...

标签: c# ssl iis ssl-certificate


【解决方案1】:

第一个问题

  • 为什么我得到 403 错误,而没有真正进入我的控制器操作?

Web 服务器和客户端协商客户端将发送什么证书。服务器发送一个它将接受的签名授权列表,客户端发送可接受的证书。

如果您使用自签名证书,您要做的第一件事就是创建一个根证书并将其公钥作为“受信任的根证书颁发机构”导入您当前的用户证书存储。

然后您需要在运行 Web 服务器的机器的机器存储中执行相同的操作。客户端和服务器都需要将根证书视为受信任的权威,否则他们将永远不会就其签署的任何证书达成一致。

第二个问题

  • 为什么我几天前创建的客户端证书可以正常工作,而我之后创建的那些证书却不行?

有效的是 .cer 文件,那么为什么其他 .cer 文件无效时它有效?

当然是私钥。

但是,您说 .cer 文件没有私钥。没错,他们没有。但是为我工作的 .cer 文件是从用户存储中导出的。

也就是说,我创建了一个 .cer 和一个 .pvk 文件的证书,然后将两者合并到一个 .pfx 文件中。

我将 .pfx 文件导入到我的用户存储中,然后将其导出到 .cer 文件中。

当我的客户端加载exported.cer 文件时,它知道私钥是有效的,因为它在用户存储中,因此它在创建X509Certificate2 对象时不需要提供密码。

当我尝试对不在用户存储中的证书执行相同操作时,使用 .cer 文件不起作用。使用 .pfx 文件确实 - 如果我提供了密码。

var certificate = new X509Certificate2("testcert.pfx", "Password1");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-26
    • 2017-07-11
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    相关资源
    最近更新 更多