C#:以安全的方式正确发送电子邮件

发布于 2024-09-04 14:47:13 字数 2956 浏览 8 评论 0原文

尝试使用 C# 发送安全电子邮件,想知道我是否理解正确。我目前有以下程序:

using System;
using System.Net.Mail;
using System.Net;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Net.Security;

namespace Geekality.SecureEmail
{
    class Program
    {
        static bool OurCertificateValidation(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            var actualCertificate = X509Certificate.CreateFromCertFile("example.com.cert");

            return certificate.Equals(actualCertificate);
        }

        static void Main(string[] args)
        {
            // Register our own certificate validation
            ServicePointManager.ServerCertificateValidationCallback = OurCertificateValidation;

            // Message
            var from = new MailAddress("[email protected]", "Me");
            var to = new MailAddress("[email protected]", "Myself");

            var message = new MailMessage(from, to)
            {
                Subject = "Greetings!",
                Body = "How are you doing today?",
            };

            // Create client
            var client = new SmtpClient("smtp.example.com")
            {
                EnableSsl = true,
                Credentials = new NetworkCredential
                {
                    UserName = "[email protected]",
                    Password = "password",
                },
            };

            // Try to send
            using (client)
            {
                try
                {
                    client.Send(message);
                    Console.WriteLine("Message sent!");
                }
                catch (AuthenticationException e)
                {
                    Console.WriteLine("Authentication failed:");
                    Console.WriteLine(e.Message);
                }
                catch (SmtpException e)
                {
                    Console.WriteLine("SMTP error:");
                    Console.WriteLine(e.Message);
                }
            }

            Console.ReadKey(true);
        }
    }
}

数据当然已更改为示例值。无论如何,从我所看到的来看,这似乎工作得很好。对我所做的事情有什么评论吗?特别是关于我如何进行证书验证的问题。这是一个好方法吗?或者我是否错过了一些如此糟糕的事情,以至于我最好不使用 SSL 发送电子邮件?

我自己进行验证的原因是默认验证失败,因为它是自行颁发的证书,并且我使用的邮件域与所使用的证书中的邮件域不同。我使用的是 mail.mydomain.com,而证书中的域类似于 mywebhost.com。因此,我所做的就是使用 Opera 的邮件客户端从 Opera 获取证书文件并将其存储起来,以便我可以将其与尝试发送电子邮件时获得的证书文件进行比较。这是进行此验证的安全且良好的方法吗?我还知道实际证书的哈希值,并尝试将其与发送电子邮件时收到的哈希值进行比较。这也有效并且更容易做到,尽管在代码行中它几乎是相同的。只是与字符串而不是文件进行比较。这些方法中的任何一种比另一种更好吗?

Experimented sending secure emails using C# and was wondering if I have understood things correctly. I currently have the following program:

using System;
using System.Net.Mail;
using System.Net;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Net.Security;

namespace Geekality.SecureEmail
{
    class Program
    {
        static bool OurCertificateValidation(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            var actualCertificate = X509Certificate.CreateFromCertFile("example.com.cert");

            return certificate.Equals(actualCertificate);
        }

        static void Main(string[] args)
        {
            // Register our own certificate validation
            ServicePointManager.ServerCertificateValidationCallback = OurCertificateValidation;

            // Message
            var from = new MailAddress("[email protected]", "Me");
            var to = new MailAddress("[email protected]", "Myself");

            var message = new MailMessage(from, to)
            {
                Subject = "Greetings!",
                Body = "How are you doing today?",
            };

            // Create client
            var client = new SmtpClient("smtp.example.com")
            {
                EnableSsl = true,
                Credentials = new NetworkCredential
                {
                    UserName = "[email protected]",
                    Password = "password",
                },
            };

            // Try to send
            using (client)
            {
                try
                {
                    client.Send(message);
                    Console.WriteLine("Message sent!");
                }
                catch (AuthenticationException e)
                {
                    Console.WriteLine("Authentication failed:");
                    Console.WriteLine(e.Message);
                }
                catch (SmtpException e)
                {
                    Console.WriteLine("SMTP error:");
                    Console.WriteLine(e.Message);
                }
            }

            Console.ReadKey(true);
        }
    }
}

The data has of course been changed to example values though. Anyways, this seems to work nicely from what I can see. Any comments on what I have done? Especially on the matter of how I do the certificate validation. Is it a good way of doing it? Or have I missed something so bad here that I might as well send the email not using SSL?

The reason for me doing the validation myself is that the default validation failed because it is a self-issued certificate and the mail domain I'm using is not the same as is in the certificate used. I'm using mail.mydomain.com while the domain in the certificate is something like mywebhost.com. So what I did was to get the certificate file from Opera using it's mail client and store it so I can compare it to the one I get when trying to send the email. Is this a secure and good way to do this validation? I also know the hash of the actual certificate and tried to use that to compare with the one I get when sending the email. This also works and was sort of easier to do, although in lines of code it's pretty much the same. Just comparing with a string instead of a file. Is any of these ways better than the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

朕就是辣么酷 2024-09-11 14:47:13

您没有检查证书的有效期,也没有检查它是否未被服务器吊销。一般来说,正确的证书验证是非常重要的事情。

有效期检查很简单 - 只需检查证书的 ValidFrom 和 ValidTo 属性即可。验证时刻必须介于两者之间。至于吊销检查,如果您有自签名证书,那么服务器维护人员很可能会费心管理 CRL 或安装 OCSP 服务器进行在线验证。因此,您可以在您的特定情况下跳过此步骤。

最后,如果服务器将证书更改为另一个合法证书怎么办?您需要更改代码(或带有证书的文件),不是吗?

You aren't checking certificate validity period and aren't checking if it has not been revoked by the server. In general, proper certificate validation is very non-trivial thing.

Validity period check is trivial - just check ValidFrom and ValidTo properties of the certificate. Moment of validation must fit in between. As for revocation checking, -- if you have a self-signed certificate anyway, there's a little chance that server maintainers will bother managing CRLs or install OCSP server for online validation. So you can skip this step in your particular case.

Finally, what if the server changes the certificate to another legitimate one? You will need to change your code (or file with certificate), won't you?

弱骨蛰伏 2024-09-11 14:47:13

只是您代码的一个附带问题 - 为什么要将参数 object sX509Chain chainSslPolicyErrors sslPolicyErrors 传递到您的 OurCertificateValidation< /代码>方法?他们没有被引用。

Just a side question to your code - Why do you pass the parameters object s, X509Chain chain and SslPolicyErrors sslPolicyErrors into your OurCertificateValidation method? They aren't getting referenced.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文