可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm getting this error:
The remote certificate is invalid according to the validation procedure.
whenever I try to send e-mail using Gmail's SMTP server in my C# code.
Can someone point me to the right direction for a solution to this problem?
The following is the stack trace...
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.TlsStream.CallProcessAuthentication(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Mail.SmtpConnection.Flush()
at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at BulkEmail.frmemail.mailsending(String toaddress, String fromaddress, String fromname, String subject, String pwd, String attachements, String mailmessage, String htmlmessage, Int32 i, Int32 j, String replytoaddress)
回答1:
Warning: Do not use this in production code!
As a workaround, you can switch off certificate validation. Only ever do this to obtain confirmation that the error is being throw because of a bad certificate.
Call this method before you call smtpclient.Send()
:
[Obsolete("Do not use this in Production code!!!",true)]
static void NEVER_EAT_POISON_Disable_CertificateValidation()
{
// Disabling certificate validation can expose you to a man-in-the-middle attack
// which may allow your encrypted message to be read by an attacker
// https://stackoverflow.com/a/14907718/740639
ServicePointManager.ServerCertificateValidationCallback =
delegate (
object s,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
) {
return true;
};
}
回答2:
The link here solved my problem.
http://brainof-dave.blogspot.com.au/2008/08/remote-certificate-is-invalid-according.html
I went to url of the web service (on the server that had the issue), clicked on the little security icon in IE, which brought up the certificate. I then clicked on the Details tab, clicked the Copy To File button, which allowed me to export the certifcate as a .cer file. Once I had the certificate locally, I was able to import it into the certificate store on the server using the below instructions.
Start a new MMC.
File --> Add/Remove Snap-In...
Click Add...
Choose Certificates and click Add.
Check the "Computer Account" radio button. Click Next.
Choose the client computer in the next screen. Click Finish.
Click Close.
Click OK.
NOW install the certificate into the Trusted Root Certification Authorities certificate store. This will allow all users to trust the certificate.
回答3:
You can improve the code to ask user that the certificate is not valid. Do you want to continue? As below:
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(ValidateServerCertificate);
And add a method like this:
public static bool ValidateServerCertificate(object sender,X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
else
{
if (System.Windows.Forms.MessageBox.Show("The server certificate is not valid.\nAccept?", "Certificate Validation", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
return true;
else
return false;
}
}
回答4:
A little late to the party, but if you are looking for a solution like Yury's the following code will help you identify if the issue is related to a self-sign certificate and, if so ignore the self-sign error. You could obviously check for other SSL errors if you so desired.
The code we use (courtesy of Microsoft - http://msdn.microsoft.com/en-us/library/office/dd633677(v=exchg.80).aspx) is as follows:
private static bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
// If the certificate is a valid, signed certificate, return true.
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
// Self-signed certificates with an untrusted root are valid.
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain, the certificate is invalid,
// so the method returns false.
return false;
}
}
}
}
// When processing reaches this line, the only errors in the certificate chain are
// untrusted root errors for self-signed certificates. These certificates are valid
// for default Exchange server installations, so return true.
return true;
}
else
{
// In all other cases, return false.
return false;
}
}
回答5:
I had the exact same problem and figured out that by default the Mail Shield from Avast antivirus had the "Scan SSL connection" activated. Make sure to turn that off.
From my knowledge, Avast will "open" the mail, scan it for any viruses and then sign it using it's own certificate so the mail won't be signed by the gmail's certificate anymore which produces that error.
Solution 1:
- Turn off the SSL scans from your antivirus (or the entire mail shield).
Solution 2 (Should be the best security speaking):
- Get somehow the certificate used by the antivirus (Avast has an option to export it)
- Import it in your imap/pop/smtp client before connecting to gmail server.
回答6:
Are you sure you are using correct SMTP server address?
Both smtp.google.com and smtp.gmail.com work, but SSL certificate is issued to the second one.
回答7:
Get the same error while sending from outlook because of ssl. Tried setting EnableSSL = false resolved the issue.
example:
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("xxx@gmail.com", "xxxxx")
};
回答8:
I had the same error when i tried to send email using SmtpClient
via proxy server (Usergate).
Verifies the certificate contained the address of the server, which is not equal to the address of the proxy server, hence the error.
My solution: when an error occurs while checking the certificate, receive the certificate, export it and check.
public static bool RemoteServerCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
// if got an cert auth error
if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateNameMismatch) return false;
const string sertFileName = "smpthost.cer";
// check if cert file exists
if (File.Exists(sertFileName))
{
var actualCertificate = X509Certificate.CreateFromCertFile(sertFileName);
return certificate.Equals(actualCertificate);
}
// export and check if cert not exists
using (var file = File.Create(sertFileName))
{
var cert = certificate.Export(X509ContentType.Cert);
file.Write(cert, 0, cert.Length);
}
var createdCertificate = X509Certificate.CreateFromCertFile(sertFileName);
return certificate.Equals(createdCertificate);
}
Full code of my email sender class:
public class EmailSender
{
private readonly SmtpClient _smtpServer;
private readonly MailAddress _fromAddress;
public EmailSender()
{
ServicePointManager.ServerCertificateValidationCallback = RemoteServerCertificateValidationCallback;
_smtpServer = new SmtpClient();
}
public EmailSender(string smtpHost, int smtpPort, bool enableSsl, string userName, string password, string fromEmail, string fromName) : this()
{
_smtpServer.Host = smtpHost;
_smtpServer.Port = smtpPort;
_smtpServer.UseDefaultCredentials = false;
_smtpServer.EnableSsl = enableSsl;
_smtpServer.Credentials = new NetworkCredential(userName, password);
_fromAddress = new MailAddress(fromEmail, fromName);
}
public bool Send(string address, string mailSubject, string htmlMessageBody,
string fileName = null)
{
return Send(new List<MailAddress> { new MailAddress(address) }, mailSubject, htmlMessageBody, fileName);
}
public bool Send(List<MailAddress> addressList, string mailSubject, string htmlMessageBody,
string fileName = null)
{
var mailMessage = new MailMessage();
try
{
if (_fromAddress != null)
mailMessage.From = _fromAddress;
foreach (var addr in addressList)
mailMessage.To.Add(addr);
mailMessage.SubjectEncoding = Encoding.UTF8;
mailMessage.Subject = mailSubject;
mailMessage.Body = htmlMessageBody;
mailMessage.BodyEncoding = Encoding.UTF8;
mailMessage.IsBodyHtml = true;
if ((fileName != null) && (System.IO.File.Exists(fileName)))
{
var attach = new Attachment(fileName, MediaTypeNames.Application.Octet);
attach.ContentDisposition.CreationDate = System.IO.File.GetCreationTime(fileName);
attach.ContentDisposition.ModificationDate = System.IO.File.GetLastWriteTime(fileName);
attach.ContentDisposition.ReadDate = System.IO.File.GetLastAccessTime(fileName);
mailMessage.Attachments.Add(attach);
}
_smtpServer.Send(mailMessage);
}
catch (Exception e)
{
// TODO lor error
return false;
}
return true;
}
public static bool RemoteServerCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
// if got an cert auth error
if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateNameMismatch) return false;
const string sertFileName = "smpthost.cer";
// check if cert file exists
if (File.Exists(sertFileName))
{
var actualCertificate = X509Certificate.CreateFromCertFile(sertFileName);
return certificate.Equals(actualCertificate);
}
// export and check if cert not exists
using (var file = File.Create(sertFileName))
{
var cert = certificate.Export(X509ContentType.Cert);
file.Write(cert, 0, cert.Length);
}
var createdCertificate = X509Certificate.CreateFromCertFile(sertFileName);
return certificate.Equals(createdCertificate);
}
}
回答9:
My issue was on Windows 2003 Server, when calling AuthenticateAsClient. The solutions above (e.g. circumventing ServicePointManager.ServerCertificateValidationCallback
) did not work.
Turns out this is a bug in Windows 2003, and there is a hotfix:
"Applications that use the Cryptography API cannot validate an X.509 certificate in Windows Server 2003"
https://support.microsoft.com/en-us/kb/938397
Installing this hotfix resolved my issue.
回答10:
Your website folder needs network service security. Especially the web.config. It uses this account to access your registry for the certificates. This will stop the need to add a hack to your code.
回答11:
Check your computer's Date and Time. If it is wrong, update it to the current time or set it automatically to get the time from the Internet.
Because certificates are tied to a fixed time period, if your clock is wrong, you are likely to get errors like this. In that scenario, by fixing the time, the problem will be fixed.
回答12:
My issue was not that I was referencing the server by the IP address instead of the URL. I had purchased a signed certificate from a CA for use inside a private network. The URL specified on the certificate does matter when referencing the server. Once I referenced the server by the URL in the certificate everything started to work.
回答13:
I know I am pretty late in this game, but I haven't seen an answer here pointing to the system.diagnostics logs for the TLS Stream.
Before you do any changes to your code, make sure you understand what the problem is about. The AuthenticationException
is one of that very generic exception which does not tell much. To learn what's going under the hood edit the app.config file for your application (or create a new one) and make sure you have System.Net trace source enabled in the system.diagnostics
section, for example:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sharedListeners>
<add name="file" initializeData="c:\network.log" type="System.Diagnostics.TextWriterTraceListener" />
</sharedListeners>
<sources>
<source name="System.Net" switchValue="Verbose">
<listeners>
<add name="file" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
Rerun your application and check the c:\network.log file. You should see there detailed information about your TLS (SSL) connection, for example:
System.Net Information: 0 : [12764] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = f44368:535f958, targetName = localhost, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [12764] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=OK).
System.Net Information: 0 : [12764] Remote certificate: [Version]
V3
[Subject]
CN=test
Simple Name: test
DNS Name: example.com
[Issuer]
CN=Root CA
Simple Name: Root CA
DNS Name: Root CA
...
[Signature Algorithm]
sha256RSA(1.2.840.113549.1.1.11)
[Public Key]
Algorithm: RSA
Length: 2048
Key Blob: ....
System.Net Information: 0 : [12764] SecureChannel#38496415 - Remote certificate has errors:
System.Net Information: 0 : [12764] SecureChannel#38496415 - Certificate name mismatch.
System.Net Information: 0 : [12764] SecureChannel#38496415 - Remote certificate was verified as invalid by the user.
System.Net Error: 0 : [12764] Exception in AppDomain#10923418::UnhandledExceptionHandler - The remote certificate is invalid according to the validation procedure..
Knowing what causes the problem, you should be able to resolve it or at least narrow your Google searches.
回答14:
For those encountering this same error when connecting to a local site with a self-signed certificate, the following blog post helped me out.
http://brainof-dave.blogspot.com.au/2008/08/remote-certificate-is-invalid-according.html
回答15:
In our case problem was caused by IIS server certificate. The certificate's subject was set to DNS name and users were trying to access web site by IP adress, so .NET certification validation failed.
Problem disappeared when users started to use DNS name.
So you have to change your Provider URL to https://CertificateSubject/xxx/xxx.application
回答16:
There is an MSDN blog article on investigating this type of issues:
Troubleshooting ASP.NET – The remote certificate is invalid according to the validation procedure:
http://blogs.msdn.com/b/jpsanders/archive/2009/09/16/troubleshooting-asp-net-the-remote-certificate-is-invalid-according-to-the-validation-procedure.aspx
回答17:
Adding this line worked for me.
System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(RemoteServerCertificateValidationCallback);
Full code is
private void sendAMail(String toAddress, String messageBody)
{
String msg = "Sending mail to : " + toAddress;
MailMessage mail = new MailMessage();
mail.To.Add(toAddress);
mail.From = new MailAddress("from@mydomain.com");
mail.Subject = "Subject: Test Mail";
mail.Body = messageBody;
mail.IsBodyHtml = true;
//Added this line here
System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(RemoteServerCertificateValidationCallback);
SmtpClient smtp = new SmtpClient();
smtp.Host = "myhostname.com";
smtp.Credentials = new System.Net.NetworkCredential("sender@sample.com", "");
smtp.EnableSsl = true;
smtp.Port = 587;
smtp.Send(mail);
}
private bool RemoteServerCertificateValidationCallback(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
//Console.WriteLine(certificate);
return true;
}
回答18:
It solved my issue
smtpClient.Credentials = new NetworkCredential(sendMail.UserName, sendMail.Password);
smtpClient.EnableSsl = false;//sendMail.EnableSSL;
// With Reference to // Problem comes only Use above line to set false SSl to solve error when username and password is entered in SMTP settings.
回答19:
here is the solution that I decided to use.
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
string name = certificate.Subject;
DateTime expirationDate = DateTime.Parse(certificate.GetExpirationDateString());
if (sslPolicyErrors == SslPolicyErrors.None || (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch && name.EndsWith(".acceptabledomain.com") && expirationDate > DateTime.Now))
{
return true;
}
return false;
};