Mono https web 请求失败,“身份验证或解密失败”

我正在创建一个简单的 REST 客户机,以便在我的 C # 应用程序中使用。进去。它可以很好地与 http://和 https://连接连接。在 Ubuntu 10.10上的 mono 2.6.7(也用2.8进行了测试,得到了相同的结果)只有 http://works。Https://connect 在请求时抛出此异常。GetResponse ()方法:

Unhandled Exception: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in <filename unknown>:0
at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
at System.Net.HttpWebRequest.GetResponse () [0x00000] in <filename unknown>:0

我还没找到解决的办法。有人知道为什么会发生这种事,以及如何解决吗?

同样,这只是在 Mono 中失败了,.Net 在建立连接方面似乎没有任何问题。

这是通话代码:

public JToken DoRequest(string path, params string[] parameters) {
if(!path.StartsWith("/")) {
path = "/" + path;
}
string fullUrl = url + path + ToQueryString(parameters);


if(DebugUrls) Console.WriteLine("Requesting: {0}", fullUrl);


WebRequest request = HttpWebRequest.CreateDefault(new Uri(fullUrl));
using(WebResponse response = request.GetResponse())
using(Stream responseStream = response.GetResponseStream()) {
return ReadResponse(responseStream);
}
}
69316 次浏览

那个。NET Framework 在 Windows 上使用 Windows 证书存储(mmc、添加/删除管理单元、证书)来确定是否接受来自远程站点的 SSL 证书。Windows 附带了许多根证书颁发机构和中级证书颁发机构(CA) ,它们通过 WindowsUpdate 定期更新。因此,你的。NET 代码通常会信任由 CA 或证书存储中 CA 的后代颁发的证书(包括大多数信誉良好的商业 CA)。

在 Mono 中,没有 Windows 证书存储。Mono 有自己的店。默认情况下,它是空的(没有受信任的默认 CA)。您需要自己管理这些条目。

看看这里:

Exe 点将导致 mono 安装在默认安装后信任 Firefox 信任的所有内容。

在请求 http 请求之前写这一行。这应该是工作。

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });




private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
//Return true if the server certificate is ok
if (sslPolicyErrors == SslPolicyErrors.None)
return true;


bool acceptCertificate = true;
string msg = "The server could not be validated for the following reason(s):\r\n";


//The server did not present a certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
{
msg = msg + "\r\n    -The server did not present a certificate.\r\n";
acceptCertificate = false;
}
else
{
//The certificate does not match the server name
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
msg = msg + "\r\n    -The certificate name does not match the authenticated name.\r\n";
acceptCertificate = false;
}


//There is some other problem with the certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
foreach (X509ChainStatus item in chain.ChainStatus)
{
if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
item.Status != X509ChainStatusFlags.OfflineRevocation)
break;


if (item.Status != X509ChainStatusFlags.NoError)
{
msg = msg + "\r\n    -" + item.StatusInformation;
acceptCertificate = false;
}
}
}
}


//If Validation failed, present message box
if (acceptCertificate == false)
{
msg = msg + "\r\nDo you wish to override the security check?";
//          if (MessageBox.Show(msg, "Security Alert: Server could not be validated",
//                       MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
acceptCertificate = true;
}


return acceptCertificate;
}

我也遇到了这个错误。

我尝试了 ServicePointManager.ServerCertificateValidationCallbackServicePointManager.CertificatePolicy,但仍然没有工作。

我生气。建立一个 cURL 包装。它的工作为我的玩具项目罚款。

/// <summary>
/// For MONO ssl decryption failed
/// </summary>
public static string PostString(string url, string data)
{
Process p = null;
try
{
var psi = new ProcessStartInfo
{
FileName = "curl",
Arguments = string.Format("-k {0} --data \"{1}\"", url, data),
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = false,
};


p = Process.Start(psi);


return p.StandardOutput.ReadToEnd();
}
finally
{
if (p != null && p.HasExited == false)
p.Kill();
}
}

我也有同样的问题。 当 http 响应抛出这个异常时,我会:

System.Diagnostics.Process.Start("mozroots","--import --quiet");

这会导入丢失的证书,并且异常不会再次发生。

第一个答案已经说明了这一点: 除了 Windows 以外,Mono 在其他任何操作系统上都没有附带任何东西,所以最初它不信任任何证书。那怎么办?

这里有一篇很好的文章,从开发者的角度介绍了处理这个问题的不同方法: Http://www.mono-project.com/archived/usingtrustedrootsrespectfully/

简短摘要: 你可以选择:

  • 忽视安全问题
  • 忽略这个问题
  • 让用户知道并终止
  • 让使用者知道,并让他/她选择继续承担风险

上面的链接提供了针对每种情况的代码示例。

我有同样的问题与统一(也使用单声道)和 这篇文章帮助我解决它。

在提出要求之前,只需添加以下一行:

ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;

这种方法:

public bool MyRemoteCertificateValidationCallback(System.Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
bool isOk = true;
// If there are errors in the certificate chain,
// look at each error to determine the cause.
if (sslPolicyErrors != SslPolicyErrors.None) {
for (int i=0; i<chain.ChainStatus.Length; i++) {
if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown) {
continue;
}
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build ((X509Certificate2)certificate);
if (!chainIsValid) {
isOk = false;
break;
}
}
}
return isOk;
}

Unity 的另一个解决方案是初始化 ServicePointManager 一次,以便始终接受证书。这种方法可行,但显然并不安全。

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true; // **** Always accept
};

你可以在 iOS Build 中设置 Mono TLS 的实现,一切都会像这里描述的那样工作得很好: http://massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown(尽管 Mono TLS 不支持 TLS 的新版本,但是我还没有碰到这个问题)。

Mono 默认情况下不信任任何证书,要导入 Mozilla 受信任的根权限,可以在 mozroots.exe 所在的 Mono 安装文件夹中运行 mozroots --import --quiet

在按照接受的答案导入证书之后,我仍然有这个问题。

我发现 Mono4.8.0中增加了对 TLS 1.2的支持使用的是谷歌的 无聊的 SSL,而我使用的是比这个旧版本的 Mono。我更新到 Mono 5.10,现在可以连接,而不会收到这个异常。