我试图更新我的应用程序的TcpClient
,使其与SslStream
一起使用TLS,而不是普通的Stream
,我为此使用的代码似乎在Unity2019.1.8(2018年和2017年也进行了测试)项目中集成时失败了。
要建立一个连接并打开一个新的SslStream
,我使用以下代码:
public static void InitClient(string hostName, int port, string certificateName)
{
client = new TcpClient(hostName, port);
if (client.Client.Connected)
{
Debug.LogFormat("Client connected succesfully");
}
else
{
Debug.LogErrorFormat("Client couldn't connect");
return;
}
stream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
stream.AuthenticateAsClient(certificateName);
}
catch (AuthenticationException e)
{
Debug.LogErrorFormat("Error authenticating: {0}", e);
if (e.InnerException != null)
{
Debug.LogErrorFormat("Inner exception: {0}", e);
}
Debug.LogErrorFormat("Authentication failed - closing connection");
stream.Close();
client.Close();
}
}
和验证证书
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Debug.LogErrorFormat("Certificate error: {0}", sslPolicyErrors);
return false;
}
在Unity2019.1.8中,客户端连接并尝试验证远程证书,该证书在错误的TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED.
中失败
使ValidateServerCertificate
始终返回true
,让我的客户端能够毫无问题地连接。
我尝试使用完全相同的代码在独立的C#控制台应用程序中复制这个问题,目标是.net框架4.7.1。在此应用程序中启动客户端将从true
检查中从ValidateServerCertificate
返回sslPolicyErrors == SslPolicyErrors.None
。
我知道证书是一个有效的证书,由一个受信任的CA颁发(这是通过控制台应用程序接受证书,并且它在浏览器中有一个挂锁的事实来验证的)。
为什么统一中的验证失败了,而在其他地方却是如此?
发布于 2020-01-28 09:25:07
统一为什么不能验证选项1:
尽管证书是有效和正确的(例如,它在web浏览器中使用它时工作),但它不包括到根CA的中间证书链。其结果是无法形成信任链(Unity /检索中间层),从而设置UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
标志。
为了解决这个问题,我需要将证书链附加到我的叶证书中,以便Unity可以验证整个链直到根CA。要查找证书的证书链,可以使用"TLS证书链编写器“。
根据您使用的软件,您可能需要将链包含在证书中,或者将其保存在单独的文件中。来自何物链 (我根本不附属于这个网站,只是使用它):
注意:有些软件要求您将站点的证书(例如example.com.crt)和链证书(例如example.com.chain.crt)放在单独的文件中,而其他软件则要求您在站点证书之后将链证书放在同一个文件中。
统一为什么不能验证选项2:
当服务器的SSL证书过期时,统一将抛出完全相同的UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
错误,而不提供证书已过期的附加信息,因此请确保“有效到”日期是未来的(这也会导致在web浏览器中使用时拒绝证书)。
为什么浏览器/控制台应用程序可以验证:
软件在处理不完全链的方式上可以有不同的实现。它可以抛出一个错误,说明链被破坏,因此不能被信任(就像团结一样),或者缓存并保存中间层,以便以后使用/从以前的会话中检索它(就像浏览器和微软的.net(核心)一样)。
正如在这个答案 (强调地雷)中所解释的那样
通常,SSL/TLS客户端将尝试验证从服务器接收到的服务器证书链。如果客户端不满意该链,则客户端的行为取决于实现:一些客户端干脆放弃;其他客户端(特别是Windows/Internet )将尝试使用本地已知的中间CA构建另一个链,并从其他证书(“权威信息访问”扩展)中下载证书。
在没有提供链的情况下,不信任证书是团结公司出于跨平台可压缩性而作出的故意决定,如对1115214问题的答复中所述:
我们可以通过系统特定的TLS进行验证来解决这个问题,而不是像今天这样使用OpenSSL/MbedTLS对根证书进行验证,但是这个解决方案将不能跨平台工作。因此,我们今天不想实现它,因为它会在某些平台(但不是所有平台)上向用户隐藏配置错误的服务器。
当我问这个问题的时候,我发现这是一个解决我的特殊情况的方法,所以我决定自己回答它,作为将来的参考。然而,UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
可以有各种原因,这只是其中之一。
发布于 2020-11-11 20:28:12
对于那些偶然发现使用让我们加密和UnityWebRequest
的人来说
在关于团结的问题跟踪器有一个已知的问题中,您会发现它只在某些版本中得到了修复:
更改现有项目的统一版本并不是一项简单的任务,因此我们选择购买合法的SSL证书,这虽然不便宜,但是最简单的解决方案。
发布于 2020-12-10 22:57:05
我的解决办法是:
> Public class ForceAcceptAll : CertificateHandler {
> protected override bool ValidateCertificate(byte[] certificateData)
> {
> return true;
> } }
//?
var cert = new ForceAcceptAll();
// www is a UnityWebRequest
www.certificateHandler = cert;
Nota:如果使用不当(并且被Google发现,您的构建可能会被拒绝)。
所以要小心使用它。
更多信息,这里。
https://stackoverflow.com/questions/59945581
复制相似问题