gro*_*boy 5 .net c# java ssl ssl-certificate
我们开发了一个通过 TCP 处理请求的 Java 应用程序。我们还为应用程序开发客户端库,其中每个库支持不同的语言/平台(Java、.NET 等)。
直到最近,TCP 流量还被限制在安全网络中。为了支持在不安全网络上的使用,我们使用java-plain-and-tls-socket-examples中的配方实现了 TLS 。这里有适用于服务器和客户端的配方,以及生成 X.509 证书的脚本。以下是我们用于仅服务器身份验证的 TLS 的配方摘要:
这看起来像是证书固定的设置,因为客户端在连接之前拥有服务器证书的副本。显然,在连接时,客户端将以某种方式使用此数据来验证服务器发送的证书。
我们现在假设这种方法对于保护 TCP 流量是有效的。由证书颁发机构签名似乎没有必要,因为我们同时控制服务器和客户端。
初步测试表明该实现在我们的 Java 服务器和 Java 客户端(均在本地运行)中正常运行:
我们使用SslStream来加密 TCP 流量。正如文档所示,我们没有指定 TLS 版本;相反,如果版本低于 1.2,我们会抛出异常。
我们对如何正确使用X509Chain.ChainPolicy.CustomTrustStore没有信心,因为文档忽略了此类型的用例以及 和 等选项类型的X509KeyStorageFlags信息X509VerificationFlags。
下面的代码旨在模仿上面概述的方法,即配置信任存储数据结构,供客户端在验证服务器证书时使用。这种方法似乎相当于将证书导入到操作系统的信任存储中。
// Import the trust store.
private X509Certificate2Collection GetCertificates(string storePath, string storePassword)
{
byte[] bytes = File.ReadAllBytes(storePath);
var result = new X509Certificate2Collection();
result.Import(bytes, storePassword, X509KeyStorageFlags.EphemeralKeySet);
return result;
}
// Callback function to validate a certificate received from the server.
// fCertificates stores the result of function GetCertificates.
private bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Do not allow this client to communicate with unauthenticated servers.
//
// With a self-signed certficate, sslPolicyErrors should be always equal to
// SslPolicyErrors.RemoteCertificateChainErrors.
var result = (SslPolicyErrors.RemoteCertificateChainErrors == sslPolicyErrors);
if (result)
{
// The values below are default values: set them to be explicit.
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.AddRange(fCertificates);
result = chain.Build((X509Certificate2)certificate);
}
return result;
}
// Initialize SslStream.
private SslStream GetStream(TcpClient tcpClient, string targetHost)
{
SslStream sslStream = new SslStream(
tcpClient.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
try
{
sslStream.AuthenticateAsClient(targetHost);
// require TLS 1.2 or higher
if (sslStream.SslProtocol < SslProtocols.Tls12)
{
throw new AuthenticationException($"The SSL protocol ({sslStream.SslProtocol}) must be {SslProtocols.Tls12} or higher.");
}
}
catch (AuthenticationException caught)
{
sslStream.Dispose();
throw caught;
}
return sslStream;
}
Run Code Online (Sandbox Code Playgroud)
初步测试产生的结果因操作系统而异:
sslPolicyErrors等于SslPolicyErrors.RemoteCertificateChainErrors(预期)。X509Chain.Build返回false且唯一的链状态项是“UntrustedRoot,自签名证书”。sslPolicyErrors包括以下值:
SslPolicyErrors.RemoteCertificateNameMismatch(意外)。SslPolicyErrors.RemoteCertificateChainErrors(预期的)。sslPolicyErrors则:
SslPolicyErrors.RemoteCertificateNameMismatch上文)后,我们的服务器证书似乎应该包含一个subjectAltName字段来指定允许的 DNS 名称。sslPolicyErrors当我们使用证书固定时,在验证服务器证书时忽略这一点是否必要,或者是否合理?我无法回答你的具体问题,但这里有一些想法:
您还没有提到服务器如何对客户端进行身份验证。因此,您可能会考虑实施诸如客户端证书之类的东西。如果您控制两者,您可能需要某种方法来确保随机攻击者无法连接。
您可以考虑创建威胁模型。在许多情况下,正是您没有考虑到的事情导致了问题。
| 归档时间: |
|
| 查看次数: |
333 次 |
| 最近记录: |