加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

.net – Windows 10 Universal应用程序中的证书固定

发布时间:2020-12-13 22:25:50 所属栏目:Windows 来源:网络整理
导读:我需要一种在 Windows 10 Universal应用程序中实现证书或公钥锁定的好方法.所有代码都在C#中,并且所有连接都是HTTPS,因此 Windows.Web.Http.HttpClient 类的内容非常棒.是否有一个简单的类/库,或者至少是一个循序渐进的指南,如何实现这些可以由不知道X.509证
我需要一种在 Windows 10 Universal应用程序中实现证书或公钥锁定的好方法.所有代码都在C#中,并且所有连接都是HTTPS,因此 Windows.Web.Http.HttpClient类的内容非常棒.是否有一个简单的类/库,或者至少是一个循序渐进的指南,如何实现这些可以由不知道X.509证书的神秘细节的人安全地完成的东西?

我发现的一些事情谈论使用本机代码或OpenSSL等第三方库(非常复杂!).我发现的最好的东西是this question关于WP8.0中的固定,其中包括一个应该在WP8.1上工作的代码示例,希望也可以在Win10上运行,但它有点丑陋和令人困惑,我不知道如何要求在发送包含敏感信息的请求时,服务器的证书是固定证书之一.由于检查时间/使用时间(TOCTOU)攻击,事先检查似乎并不安全(除非HttpRequestMessage.TransportInformation功能打开连接然后保持打开状态,因此攻击者无法获得操作 – 新连接的中间位置).理想情况下,有一种方法可以过滤HttpClient,因此它只连接到带有固定证书的服务器,但是我能找到的最接近的东西恰好相反(忽略某些证书错误,如here所述),通过HttpBaseProtocolFilter.IgnorableServerCertificateErrors属性,似乎没有任何限制有效证书的选项.

这有人有一个很好的解决方案吗?如果HttpRequestMessage.TransportInformation方法(使用自定义证书验证代码)是唯一选项,那么在发送请求之前检查该属性是否可以安全地防止TOCTOU攻击?

解决方法

你有没有看过HttpBaseProtocolFilter的ServerCustomValidationRequested事件?对我来说棘手的部分是从证书对象中提取公共证书.为此,我必须引入System.Security.Cryptography.X509Certificates nuget包.我的代码看起来像这样:

private void DoIt()
{
    using (var filter = new HttpBaseProtocolFilter())
    {
        filter.ServerCustomValidationRequested += FilterOnServerCustomValidationRequested;
        var httpClient = new Windows.Web.Http.HttpClient(filter);
        var myString = await httpClient.GetStringAsync(new Uri("https://myserver.com"));
        // I guess we should be kind and unsubscribe?
        filter.ServerCustomValidationRequested -= FilterOnServerCustomValidationRequested;
    }
}

private void FilterOnServerCustomValidationRequested(HttpBaseProtocolFilter sender,HttpServerCustomValidationRequestedEventArgs args)
{
    if (!IsCertificateValid(args.RequestMessage,args.ServerCertificate,args.ServerCertificateErrors))
    {
        args.Reject();
    }
}

private bool IsCertificateValid(Windows.Web.Http.HttpRequestMessage httpRequestMessage,Certificate cert,IReadOnlyList<ChainValidationResult> sslPolicyErrors)
{
    // disallow self-signed certificates or certificates with errors
    if (sslPolicyErrors.Count > 0)
    {
        return false;
    }

    if (RequestRequiresCheck(httpRequestMessage.RequestUri))
    {
        var certificateSubject = cert?.Subject;
        bool subjectMatches = certificateSubject == CERTIFICATE_COMMON_NAME;

        var certArray = cert?.GetCertificateBlob().ToArray();
        var x509Certificate2 = new X509Certificate2(certArray);
        var certificatePublicKey = x509Certificate2.GetPublicKey();
        var certificatePublicKeyString = Convert.ToBase64String(certificatePublicKey);
        bool publicKeyMatches = certificatePublicKeyString == CERTIFICATE_PUBLIC_KEY;

        return subjectMatches && publicKeyMatches;
    }

    return true;
}

private bool RequestRequiresCheck(Uri uri)
{
    return uri.IsAbsoluteUri &&
            uri.AbsoluteUri.StartsWith("https://",StringComparison.CurrentCultureIgnoreCase) &&
            uri.AbsoluteUri.StartsWith(BASE_URL,StringComparison.CurrentCultureIgnoreCase);
}

附:如果您对更多细节感兴趣,我最终写了一个关于UWP中的证书的blog post

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读