C# 用于WCF身份验证的SSL证书

C# 用于WCF身份验证的SSL证书,c#,wcf,ssl,ssl-certificate,wcf-security,C#,Wcf,Ssl,Ssl Certificate,Wcf Security,我开发了一个应用程序,它启动了几个WCF服务,这些服务使用SecurityMode.Message来加密通信 它正在工作,但是非常复杂,因为我们必须生成一个SSL证书并将其放在服务器和客户端的特定存储中 问题在于将使用该程序的客户: 不在域中事实上,服务器肯定在域中,但不是客户端 不想买证书 那我最好的机会是什么呢?我只需要加密数据,不需要确保连接到正确的主机 我知道我不是在最好的情况下,但该应用程序将由一些特定的用户使用 下面是我的代码的一部分,用于建立连接: 服务器端: 客户端: 请注意,我

我开发了一个应用程序,它启动了几个WCF服务,这些服务使用SecurityMode.Message来加密通信

它正在工作,但是非常复杂,因为我们必须生成一个SSL证书并将其放在服务器和客户端的特定存储中

问题在于将使用该程序的客户:

不在域中事实上,服务器肯定在域中,但不是客户端 不想买证书 那我最好的机会是什么呢?我只需要加密数据,不需要确保连接到正确的主机

我知道我不是在最好的情况下,但该应用程序将由一些特定的用户使用

下面是我的代码的一部分,用于建立连接:

服务器端:

客户端:


请注意,我删除了有关我的自定义身份验证的部分,以获得更干净的代码

您的客户需要windows域之外的安全性=您的客户需要证书。没有证书=没有安全性。这就是你必须向客户解释的

您只需要在服务器上拥有带有私钥的证书,客户端必须信任该证书。如果它信任发布者,则不必安装该证书。这是什么意思?您有三种选择:

您的客户必须从受信任的发布者处购买证书,您的客户只需工作即可 您的客户必须安装自己的证书颁发机构,该机构将生成证书,并且客户必须在其受信任的根颁发机构存储中拥有该机构的证书。每个较大的公司都有自己的证书颁发机构。 您将在生产中使用自签名证书。这不太安全,不推荐使用。较不安全意味着您的客户端必须信任自签名证书,并且它无法验证证书链=它无法验证该证书是由受信任的颁发机构颁发的,并且它无法验证该证书颁发机构吊销的证书。在这种情况下,您必须在每个客户机上安装服务证书-这是信任自签名证书的唯一方法安装本身实际上就是信任。
这就是安全工作的方式。您可以构建自己的-您将在这方面付出巨大的努力,但最终您仍然需要具有非对称加密的PKI私钥基础设施,以使其真正安全。证书主要涉及包装、存储和传输公钥和私钥

您的客户需要windows域之外的安全性=您的客户需要证书。没有证书=没有安全性。这就是你必须向客户解释的

您只需要在服务器上拥有带有私钥的证书,客户端必须信任该证书。如果它信任发布者,则不必安装该证书。这是什么意思?您有三种选择:

您的客户必须从受信任的发布者处购买证书,您的客户只需工作即可 您的客户必须安装自己的证书颁发机构,该机构将生成证书,并且客户必须在其受信任的根颁发机构存储中拥有该机构的证书。每个较大的公司都有自己的证书颁发机构。 您将在生产中使用自签名证书。这不太安全,不推荐使用。较不安全意味着您的客户端必须信任自签名证书,并且它无法验证证书链=它无法验证该证书是由受信任的颁发机构颁发的,并且它无法验证该证书颁发机构吊销的证书。在这种情况下,您必须在每个客户机上安装服务证书-这是信任自签名证书的唯一方法安装本身实际上就是信任。
这就是安全工作的方式。您可以构建自己的-您将在这方面付出巨大的努力,但最终您仍然需要具有非对称加密的PKI私钥基础设施,以使其真正安全。证书主要涉及包装、存储和传输公钥和私钥

好吧,我就是这么想的。如果客户不喜欢加密,也不需要安装/支付证书,我应该做什么更改?这不是我向他推荐的解决方案,但我需要知道:如果他们购买了证书,我必须在这里检查什么?我假设某些证书只适用于http,而不适用于SSL服务器证书。如果您想制作自己的定制解决方案,这取决于您自己。您必须在传递消息内容之前对其进行加密,在接收到消息内容之后对其进行解密-可能由自定义消息检查器或自定义通道/编码器来完成。您必须找到一种方法来安全地存储加密密钥这正是证书的作用。谢谢,另一个问题是:如果服务器只能通过客户网络访问怎么办?我是说,为了值得信赖的出版商?我们可以为内部网络名称或专用ip获得合法的SSL证书吗?在这种情况下,需要内部客户认证
这就是我的想法。如果客户不喜欢加密,也不需要安装/支付证书,我应该做什么更改?这不是我向他推荐的解决方案,但我需要知道:如果他们购买了证书,我必须在这里检查什么?我假设某些证书只适用于http,而不适用于SSL服务器证书。如果您想制作自己的定制解决方案,这取决于您自己。您必须在传递消息内容之前对其进行加密,在接收到消息内容之后对其进行解密-可能由自定义消息检查器或自定义通道/编码器来完成。您必须找到一种方法来安全地存储加密密钥这正是证书的作用。谢谢,另一个问题是:如果服务器只能通过客户网络访问怎么办?我是说,为了值得信赖的出版商?我们能否为内部网络名称或专用ip获得合法SSL证书?在这种情况下,这是内部客户证书颁发机构的情况。
ServiceHost host = new ServiceHost(typeof(MyServiceType))
WSHttpBinding binding = new WSHttpBinding
{
    ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue,     MaxDepth = int.MaxValue, MaxBytesPerRead = int.MaxValue, MaxNameTableCharCount = int.MaxValue },
    MaxReceivedMessageSize = int.MaxValue
};
TimeSpan timeoutSpan = TimeSpan.FromMilliseconds(timeout);
binding.CloseTimeout = timeoutSpan;
binding.OpenTimeout = timeoutSpan;
binding.ReceiveTimeout = timeoutSpan;
binding.SendTimeout = timeoutSpan;
binding.ReliableSession.InactivityTimeout = timeoutSpan;

binding.MaxBufferPoolSize = int.MaxValue;
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings["Hostname"]);
host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
host
.AddServiceEndpoint(services[port], binding, String.Format("http://localhost:{0}", port));
string remoteAddress = String.Format("{0}://{1}:{2}", Tools.GetDescription(accessInfo.ServiceHost.Protocol), accessInfo.ServiceHost.HostName, accessInfo.PortNumber);


// avoid seralization/deserialization problems with large XML's
WSHttpBinding binding = new WSHttpBinding();
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
binding.ReaderQuotas.MaxDepth = int.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
TimeSpan timeoutSpan = DateTime.Now.AddMinutes(30) - DateTime.Now;
binding.CloseTimeout = timeoutSpan;
binding.OpenTimeout = timeoutSpan;
binding.ReceiveTimeout = timeoutSpan;
binding.SendTimeout = timeoutSpan;
binding.ReliableSession.InactivityTimeout = timeoutSpan;
binding.MaxBufferPoolSize = int.MaxValue;

//we set the security type
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;


ChannelFactory<TService> channelFactory = new ChannelFactory<TService>(binding, remoteAddress);

_service = channelFactory.CreateChannel();