C#.NET-固定证书颁发机构-我做得正确吗? [英] C# .NET - Pinning Certificates Authorities - I am doing it correctly?

查看:80
本文介绍了C#.NET-固定证书颁发机构-我做得正确吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的软件使用HTTPS连接连接到Dropbox,以便检索一些敏感数据.

My software connects to Dropbox using an HTTPS connection in order to retrieve some sensitive data.

我想固定证书颁发机构,以防止中间人攻击.

I would like to pin the Certificates Authorities in order to prevent a man-in-the-middle attack.

到目前为止,我有以下代码:

So far I have the following code:

static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
        try
        {
            var currentCaPublicKey = chain.ChainElements.Cast<X509ChainElement>().Last().Certificate.GetPublicKeyString();

            var caPublicKeys = new List<string>(){"00ad0e15cee443805cb187f3b760f97112a5aedc269488aaf4cef520392858600cf880daa9159532613cb5b128848a8adc9f0a0c83177a8f90ac8ae779535c31842af60f98323676ccdedd3ca8a2ef6afb21f25261df9f20d71fe2b1d9fe1864d2125b5ff9581835bc47cda136f96b7fd4b0383ec11bc38c33d9d82f18fe280fb3a783d6c36e44c061359616fe599c8b766dd7f1a24b0d2bff0b72da9e60d08e9035c678558720a1cfe56d0ac8497c3198336c22e987d0325aa2ba138211ed39179d993a72a1e6faa4d9d5173175ae857d22ae3f014686f62879c8b1dae45717c47e1c0eb0b492a656b3bdb297edaaa7f0b7c5a83f9516d0ffa196eb085f18774f"};

            return caPublicKeys.Any(s => currentCaPublicKey.Equals(s));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            return false;
        }
}

它工作正常,但我不知道我是否检查了正确的事情.来自一些加密专家的任何建议将不胜感激.

It works fine but I don't know if I am checking the right things. Any advice from some crypto experts would be greatly appreciated.

推荐答案

您的代码对于固定到根CA公钥而言看起来是正确的.

Your code looks correct for pinning to the Root CA public key.

HPKP要求您至少提供一个备用引脚,但是,我建议您遵循该指南.假设您要固定到根CA,则最好提供另一个根CA的公钥作为备份,以减轻第一个CA发生故障(例如停业)时发生DoS的风险.

HPKP requires that you provide at least one backup pin, however, and I would recommend that you follow that guidance. Given that you are pinning to a Root CA it would be appropriate to provide the public key of another Root CA as the backup to mitigate the risk of DoS should something happen to the first CA, e.g., out of business.

当然,您的代码可以容纳多个公共密钥,因此只需将附加密钥添加到字符串列表即可.

Of course, your code accommodates multiple public keys to pin against, so it would merely be a matter of adding the additional key to your list of strings.

欢呼

编辑2017.10.23

EDIT 2017.10.23

这里是我认为合理的根CA公钥固定和证书验证应该是什么样的示例.这个快速样本是在WebApi项目中完成的,因此是样板值控制器.

Here is a sample of what I think reasonable Root CA Public Key pinning and Cert Validation should look like. This quick sample was done in a WebApi project, thus the boiler plate values controller.

请注意,我的示例中仅使用了一(1)个根CA公钥,并且如上所述,应提供一个备用引脚(至少2个数组元素).

Please note that only one (1) Root CA public key is used in my sample, and as mentioned above, a backup pin should be provided (minimum 2 array elements).

这是一个样本,不应用作生产代码-我建议对以下内容进行同行/安全性审查:

This is a sample and not intended to be taken as production code - I suggest that the following be subjected to peer / security review:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Web.Http;

namespace CertPinPocClient.Controllers
{
    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            ServicePointManager.ServerCertificateValidationCallback = new PinnedRootCaCertificate(new[]
            {
                "MIICCgKCAgEAzHYh7u+V5haaRSoGSVGm/gC4EYvZHkBR3/c/kQvTJeh1L9Bn/b7U1s7onw85SjvpZ28ohoT7p4vJRoNUBemR6hf3TM1mZmSE0tqnLGzBV9H4Nfrxx1+cubxYyYaOJ8iJfp1XslGGyZqQmUFFjWOUuU9cvOAbz4DqBIUn344JhG0xEHCf5IOF0gfuWE8yQC9vIjlveUQQ7dq/rDNZcQjqDhEb6DcF7za+1ZxjZdmtKewoYgDBPqzf66Gwi85BZsEcYFQTbjzvAhYaq4xPhJF6iPS4ihf+zjnMPxmy2oH1bm8n2fVuyxqV5JgIDU0ualx728UhfJUjcoBl57OLVsiJIdHFHpcDhN8Fn5QUGkNPgQqX27R1aw/+t2HfYTEsg6urH3aam8e7qRKUEXJs8qMKnXZ15aY0zlO7DLtfnK5tq2Cnu+HBBo4FlDhRO4kTBZOisFkvkEWI/Nj6jioOyMWsTsUvOdDK5KUpWZazpc3rwCvQy3KwBz6EyPU7ihrTm+nqqK5wiI9YwRcMjsPRBZfAur1cB0hNi+g98+2zzj+hwyR49KkOzFowp5MvXEWhnYDrY4cHSJ7zSdgMdO9HWPMke1HuKOUuUUUIpQMvPmFDAh4WQpAKqGvI/cOZeubnSwVMQra13QviYdlUeT56tFDTjgdbUNyBy0gxcFPVgTjzTj8CAwEAAQ==",
            }).Valid;

            var httpClient = new HttpClient
            {
                BaseAddress = new Uri("https://local.monitor.iontech.org")
            };

            var httpResponseMessage = httpClient.GetAsync(new Uri("https://local.monitor.iontech.org/api/status/")).Result;
            var result = httpResponseMessage.Content.ReadAsStringAsync().Result;
            return new[] {result};
        }
    }

    public class PinnedRootCaCertificate
    {
        private readonly string[] _rootCaPublicKeys;

        public PinnedRootCaCertificate(string[] rootCaPublicKeys)
        {
            _rootCaPublicKeys = rootCaPublicKeys;
        }

        public bool Valid(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
        {
            if (sslpolicyerrors != SslPolicyErrors.None) return false;

            var rootCertificate = SelfSignedCertificate(chain);
            var publicKey = Convert.ToBase64String(rootCertificate.PublicKey.EncodedKeyValue.RawData);
            return rootCertificate.Verify() && _rootCaPublicKeys.Contains(publicKey);
        }

        private X509Certificate2 SelfSignedCertificate(X509Chain chain)
        {
            foreach (var x509ChainElement in chain.ChainElements)
            {
                if (x509ChainElement.Certificate.SubjectName.Name != x509ChainElement.Certificate.IssuerName.Name) continue;
                return x509ChainElement.Certificate;
            }
            throw new Exception("Self-signed certificate not found.");
        }
    }
}

这篇关于C#.NET-固定证书颁发机构-我做得正确吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆