对如何进行证书固定感到困惑。我们如何通过xmarin表单在n android或ios设备中安装证书。如果应用程序在安装期间完成吗?有一些关于如何使用固定来验证https请求但没有安装公共证书的导师?
另一种方法是在叶子的证书公钥上执行固定,在this simple demo class中,我们可以通过自定义ServicePointManager来查看如何使用HttpClient:
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace ApproovSDK
{
/**
* Service point configuration.
*
* Adds simple pinning scheme to service point manager.
*
* FOR DEMONSTRATION PURPOSES ONLY
*/
public static class ServicePointConfiguration
{
private static string PinnedPublicKey = null;
public static void SetUp(string key = null)
{
PinnedPublicKey = key;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate;
}
private static bool ValidateServerCertficate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
if (PinnedPublicKey == null || PinnedPublicKey.Length <= 0) return true;
//Console.WriteLine("Expected: " + PinnedPublicKey);
//Console.WriteLine("Found : " + certificate?.GetPublicKeyString());
return String.Equals(PinnedPublicKey, certificate?.GetPublicKeyString(),
StringComparison.OrdinalIgnoreCase);
}
}
}
上面的示例是为了演示目的而编写的,更好的实现应该为每个被调用的域关联多个键。
虽然您可以使用证书本身来执行验证,从而固定证书,但还有其他选项。
根据OWASP documentation here,您可以实现以下3种方法中的任何一种:
证书
证书最容易固定。您可以从网站上获取带外证书,让IT人员通过电子邮件向您发送公司证书,使用openssl s_client检索证书等。证书过期后,您将更新您的申请。假设您的应用程序没有错误或安全缺陷,应用程序将每年或每两年更新一次。在运行时,您将在回调中检索网站或服务器的证书。在回调中,您将检索到的证书与程序中嵌入的证书进行比较。如果比较失败,则方法或功能失败。
钉住证书有一个缺点。如果站点定期轮换其证书,则需要定期更新您的应用程序。例如,Google会轮换其证书,因此您需要每月更新一次应用程序(如果它依赖于Google服务)。即使Google轮换其证书,底层公钥(在证书中)仍然是静态的。
公钥
由于从证书中提取公钥所需的额外步骤,公钥锁定更灵活,但有点棘手。与证书一样,程序使用其公钥的嵌入副本检查提取的公钥。两个公钥固定有两个缺点。首先,由于您通常必须从证书中提取密钥,因此更难使用密钥(而不是证书)。在Java和.Net中,提取是一个小小的不便,但它在Cocoa / CocoaTouch和OpenSSL中很不舒服。其次,密钥是静态的,可能违反密钥轮换策略。
哈希
虽然上面的三个选择使用DER编码,但也可以使用信息的散列(或其他变换)。事实上,原始的示例程序是使用消化的证书和公钥编写的。更改样本以允许程序员使用dumpasn1和其他ASN.1解码器等工具检查对象。
哈希还提供了三个额外的好处。首先,哈希允许您匿名化证书或公钥。如果您的应用程序担心在反编译和重新设计期间泄漏信息,这可能很重要。
其次,消化的证书指纹通常可用作许多库的本机API,因此使用起来非常方便。
最后,组织可能希望在主要身份被泄露的情况下提供保留(或备份)身份。散列可确保您的对手在使用之前不会看到保留的证书或公钥。实际上,谷歌的IETF草案websec-key-pinning使用了这种技术。
我强烈建议使用Hashing方法,这意味着当您验证进入的证书时,您只需要检查来自服务器的证书的哈希是否是您期望的那个。类似于以下内容:
private bool ValidateServerCertificate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Make sure we have a certificate to check.
if (certificate == null)
{
return false;
}
if (sslPolicyErrors != SslPolicyErrors.None)
{
return false;
}
return this.KnownKeys.Contains(certificate.GetCertHashString(),
StringComparer.Ordinal);
}
其中KnownKeys
是已知证书哈希的简单编译时定义数组:
private readonly string[] KnownKeys = new[]
{
"INSERT HASH",
"AND A SECOND IF REQUIRED"
};