【问题标题】:No Certificate in OnAuthorization(HttpActionContext actionContext)OnAuthorization 中没有证书(HttpActionContext actionContext)
【发布时间】:2019-03-01 16:30:27
【问题描述】:

我从这个例子中创建了 CertificateTestController 和 ValuesController How to use a client certificate to authenticate and authorize in a Web API。如果您从用户 Ogglas 向下滚动到“更新”。我以他为例,让“CertificateTestController”工作,我可以从我的商店获取证书并将其添加到“处理程序”中。当我调用“ValuesController”时,没有证书被

初始化
X509Certificate2 cert = actionContext.Request.GetClientCertificate();

这是我拥有的完整代码

值控制器

{
    [RequireSpecificCert]
    public class ValuesController : ApiController
    {
        // GET api/values
        public IHttpActionResult Get()
        {
            return Ok("It works!");
        }

        public class RequireSpecificCertAttribute : AuthorizationFilterAttribute
        {
            public override void OnAuthorization(HttpActionContext actionContext)
            {

                if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
                {
                    actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                    {
                        ReasonPhrase = "HTTPS Required"
                    };
                }
                else
                {
                    X509Certificate2 cert = actionContext.Request.GetClientCertificate();
                    X509Certificate2 cert2 = actionContext.RequestContext.ClientCertificate;

                    if (cert == null)
                    {
                        actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                        {
                            ReasonPhrase = "Client Certificate Required"
                        };
                    }
                    else
                    {
                        X509Chain chain = new X509Chain();

                        //Needed because the error "The revocation function was unable to check revocation for the certificate" happened to me otherwise
                        chain.ChainPolicy = new X509ChainPolicy()
                        {
                            RevocationMode = X509RevocationMode.NoCheck,
                        };
                        try
                        {
                            var chainBuilt = chain.Build(cert);
                            Debug.WriteLine(string.Format("Chain building status: {0}", chainBuilt));

                            var validCert = CheckCertificate(chain, cert);

                            if (chainBuilt == false || validCert == false)
                            {
                                actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                                {
                                    ReasonPhrase = "Client Certificate not valid"
                                };
                                foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                                {
                                    Debug.WriteLine(string.Format("Chain error: {0} {1}", chainStatus.Status, chainStatus.StatusInformation));
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine(ex.ToString());
                        }
                    }

                    base.OnAuthorization(actionContext);
                }
            }

            private bool CheckCertificate(X509Chain chain, X509Certificate2 cert)
            {
                var rootThumbprint = WebConfigurationManager.AppSettings["rootThumbprint"].ToUpper().Replace(" ", string.Empty);

                var clientThumbprint = WebConfigurationManager.AppSettings["clientThumbprint"].ToUpper().Replace(" ", string.Empty);

                //Check that the certificate have been issued by a specific Root Certificate
                var validRoot = chain.ChainElements.Cast<X509ChainElement>().Any(x => x.Certificate.Thumbprint.Equals(rootThumbprint, StringComparison.InvariantCultureIgnoreCase));

                //Check that the certificate thumbprint matches our expected thumbprint
                var validCert = cert.Thumbprint.Equals(clientThumbprint, StringComparison.InvariantCultureIgnoreCase);

                return validRoot && validCert;
            }
        }

用下面的 CertificateTestController 调用上面的 ValuesController

{
    [RoutePrefix("api/certificatetest")]
    public class CertificateTestController : ApiController
    {
        public IHttpActionResult Get()
        {
            var handler = new WebRequestHandler();
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.ClientCertificates.Add(GetClientCert());
            handler.UseProxy = false;
            var client = new HttpClient(handler);
            var result = client.GetAsync("https://localhost:44301//values").GetAwaiter().GetResult();
            var resultString = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
            return Ok(resultString);
        }

        private static X509Certificate GetClientCert()
        {
            X509Store store = null;
            try
            {
                store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);

                var certificateSerialNumber = "2bc034466b6960d2fee84d86e6c2532a".ToUpper().Replace(" ", string.Empty);

                var cert = store.Certificates.Cast<X509Certificate>().FirstOrDefault(x => x.GetSerialNumberString().Equals(certificateSerialNumber, StringComparison.InvariantCultureIgnoreCase));
                return cert;
            }
            finally
            {
                store.Close();
            }
        }
    }
}

请帮忙!

【问题讨论】:

  • 您是否打开证书并验证序列号是您在代码中使用的序列号?
  • 对不起,如果我之前不清楚。这不是关于在这一点上验证证书。它是关于,我什至无法从 actionContext 中提取证书。
  • 我的意思是手动:IE:工具:Internet 选项:内容:证书:选择任何一个:查看详细信息。查看受信任的根证书颁发机构上的证书。
  • 是的,但这不是问题所在。问题是当我调用 valuescontroller --> var result = client.GetAsync("localhost:44301//values").GetAwaiter().GetResult();。我在 ValuesController 的 actionContext 中看不到证书。@Ogglas ...你会碰巧知道什么吗?
  • 谁拥有证书?谁在运行应用程序?什么是证书的完整路径?

标签: c# security asp.net-web-api ssl-certificate client-certificates


【解决方案1】:

这是我在尝试解决此问题时回答的问题/问题。

第一季度。

为什么我的证书没有到达客户端(代码)?

A1.

VS 会在 OnAuthorization(HttpActionContext actionContext) 被命中之前进行初始 SSL 协商。此时,服务器在证书存储中搜索安装了私钥以进行验证的客户端证书。如果没有私钥,则失败。我通过打开详细信息找到了问题。请看下文。

以下是需要更改才能使其正常工作的配置。

1。 Web Config 文件更改

• SSL 协商

以下配置告诉 Visual Studio,“api/values”URL 需要进行 ssl 协商。这有助于我们限制预期证书协商的时间和地点。位置路径属性

<location path="api/values">
  <system.webServer>
     <security>
        <access sslFlags="SslNegotiateCert" />
        <authentication>
          <iisClientCertificateMappingAuthentication enabled="true">
          </iisClientCertificateMappingAuthentication>
        </authentication>
      </security>
    </system.webServer>
  </location>

• 证书详细

以下诊断可帮助我们进行故障排除,并找出证书验证可能导致的任何问题。

<system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.Net">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.HttpListener">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.Sockets">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
      <source name="System.Net.Cache">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="System.Net"
       type="System.Diagnostics.TextWriterTraceListener"
       initializeData="System.Net.trace.log"
       traceOutputOptions = "ProcessId, DateTime"/>
    </sharedListeners>
    <switches>
      <add name="System.Net" value="Verbose" />
      <add name="System.Net.Sockets" value="Verbose" />
      <add name="System.Net.Cache" value="Verbose" />
      <add name="System.Net.HttpListener" value="Verbose" />
    </switches>
  </system.diagnostics>

• 应用设置

将 rootThumbprint 值更改为任何服务器证书的指纹,clientThumprint 将是任何客户端证书指纹。 certificateSerialNumber 应该是传出证书序列号。

<appSettings>
            <add key="webpages:Version" value="3.0.0.0" />
            <add key="webpages:Enabled" value="false" />
            <add key="ClientValidationEnabled" value="true" />
            <add key="UnobtrusiveJavaScriptEnabled" value="true" />
            <add key="rootThumbprint" value="change"/>
            <add key="clientThumbprint" value="change"/>
<add key="certificateSerialNumber" value="change"/>
</appSettings>

2。本地 Visual Studio 和 IIS express

1) Applicationhost.config

 路径 早于 2015 年但在 2008 年之后的 Visual Studio 位置 --> c:\Users\e#\Documents\IISExpress\Config 视觉工作室 2015 和 2017 {项目名称}.vs\config\config.host.config
 变化 确保以下属性设置为“允许”

2) 启用 SSL

在 Visual Studio 属性窗口中启用 SSL。这很重要,因为 URL 从 http 变为 https。

3) WebApiConfig.cs

创建一个类过滤器文件夹。适当地命名它。在运行任何其他代码之前,证书验证需要成为第一个检查。这就是 WebApiConfig.cs 派上用场的地方。例如,我调用了我的类 RequireHttpsAttribute。为了运行检查,只需将以下行放入 WebApiConfig.cs config.Filters.Add(new RequireHttpsAttribute());

4) CertificateTestController.cs

这个类充当客户端。此类用于将证书附加到请求中并将其发送出去。这堂课有一个变化。这仅在计算机上进行了本地测试。 var 结果 = client.GetAsync("https://localhost:44300//api//values").GetAwaiter().GetResult(); 更改网址。 我们根据下面的序列号附上证书。还可以根据指纹、主题、过期/撤销、链验证等附加证书。

var certificateSerialNumber = WebConfigurationManager.AppSettings["certificateSerialNumber"].ToUpper().Replace(" ", string.Empty);

5) ValueController.cs

此类充当服务器。这是证书验证发生的地方。引用 webApiConfig.cs 的“CheckCertificate”方法/函数有两个变化。如果您按照上面 WebApiConfig.cs 下的应用设置更改,那么您就可以开始了。

3。文件

1) CertificateTestController.cs

2) ValuesController.cs

【讨论】:

    猜你喜欢
    • 2012-04-12
    • 1970-01-01
    • 2017-06-14
    • 2013-12-09
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    相关资源
    最近更新 更多