【问题标题】:WCF Service over HTTPS without IIS, with SSL Certificate from CERT and KEY strings or files没有 IIS 的 HTTPS 上的 WCF 服务,带有来自 CERT 和密钥字符串或文件的 SSL 证书
【发布时间】:2019-02-17 14:33:34
【问题描述】:

我以前使用过 WCF - 但由于它仅供内部使用,根本无法从 Internet 访问,我只是使用 net.tcp,不太关心安全性。

但是,我现在正在为一个项目进行前期制作,该项目将通过 Internet 提供给客户,因此必须计划好安全性。

我一直在对此事进行一些研究,根据我收集到的信息(如果我在这里错了,请纠正我),HTTPS 是我最好的选择,因为 HTTP 根本不安全(默认情况下)和 net. tcp 可以发现某些防火墙的问题。

不过,如果客户不愿意,我不想强​​迫客户必须在他们的服务器中安装 IIS,因此计划是使用自托管的 Windows 服务。但是,我似乎找不到任何关于如何设置服务器以在没有 IIS 的情况下使用 HTTPS 的信息。

  1. 我找到了有关使用 makecerthttpcfg set ssl 向商店添加新证书然后将其设置为端口的信息 - 可以进行测试,但我在客户的服务器中看不到这可行- 更不用说这意味着我将使用自签名证书 - 再次可以用于测试,而不是在生产中那么多

  2. 我还找到了有关使用类似的信息 (ServiceCredentials MSDN page)

    sh.Credentials.ServiceCertificate.SetCertificate(
        StoreLocation.LocalMachine, StoreName.My,
        X509FindType.FindByThumbprint, 
        "af1f50b20cd413ed9cd00c315bbb6dc1c08da5e6");
    

设置一个已经在服务器证书存储中的证书 - 这几乎可以 - 它仍然需要客户知道如何管理存储中的证书,虽然不完美但没问题。但是我无法让它工作 - 我在启动 servisse 时没有收到任何错误,但如果我尝试在浏览器中访问服务地址,我会收到关于 TLS 已过期的错误 - Q1:知道什么可能是这里的问题?

Q2:是否有可能在某个地方进行配置,客户可以在其中输入购买证书时获得的证书和密钥文件的拥有或至少位置,并使用它来保护服务?

【问题讨论】:

标签: c# wcf


【解决方案1】:

Q1:如错误中所述,您的证书可能存在问题。确保证书有效(自签名证书不能过期)。
Q2:据我所知,我们可以将证书保存为文件(pfx,cert)或将证书安装在证书存储(certlm.msc,certmgr.msc)中以便管理。
您想在 Windows 服务项目中通过 https 托管 WCF 服务吗?我做了一个demo,希望对你有用。
Service1.cs

public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
            }
            Uri uri = new Uri("https://localhost:1017");
            ServiceHost sh = null;
            protected override void OnStart(string[] args)
            {
                BasicHttpBinding binding = new BasicHttpBinding();
                binding.Security.Mode = BasicHttpSecurityMode.Transport;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                try
                {
                    ServiceHost sh = new ServiceHost(typeof(MyService), uri);
                    sh.AddServiceEndpoint(typeof(IService), binding, "");
                    ServiceMetadataBehavior smb;
                    smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (smb == null)
                    {
                        smb = new ServiceMetadataBehavior()
                        {
                            HttpsGetEnabled=true,
                        };
                        sh.Description.Behaviors.Add(smb);
                    }
                    Binding mexbinding = MetadataExchangeBindings.CreateMexHttpsBinding();
                    sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
                    sh.Open();
                    WriteLog($"Service is ready at {DateTime.Now.ToString("hh-mm-ss")}");
                }
                catch (Exception e)
                {
                    WriteLog(e.ToString());
                    throw;
                }
            }

            protected override void OnStop()
            {
                if (sh!=null&&sh.State==CommunicationState.Opened)
                {
                    sh.Close();
                    WriteLog($"Service is closed at {DateTime.Now.ToString("hh-mm-ss")}");
                }
            }

            public static void WriteLog(string text)
            {
                using (StreamWriter sw = File.AppendText(@"C:\Mylog.txt"))
                {
                    sw.WriteLine(text);
                    sw.Flush();
                }
            }
        }
        [ServiceContract(Namespace = "mydomain")]
        public interface IService
        {
            [OperationContract]
            string SayHello();
        }
        public class MyService : IService
        {
            public string SayHello()
            {
                Service1.WriteLog(string.Format("Wow, I have been called at {0}", DateTime.Now.ToString("hh-mm-ss")));
                return "Hello stranger";
            }
    }

ProjectInstaller.cs


安装windows服务(管理员权限CMD)

将证书绑定到应用端口。

https://docs.microsoft.com/en-us/windows/desktop/http/add-sslcert
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
Certhash 参数指定证书的指纹。 appid 参数是一个 GUID,可用于识别所属应用程序(打开 project.csproj 文件)

<ProjectGuid>{56FDE5B9-3821-49DB-82D3-9DCE376D950A}</ProjectGuid>

启动windows服务。

测试(服务器IP为10.157.13.70):

客户端调用(默认有验证服务器证书的步骤)

static void Main(string[] args)
    {
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
        ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
        try
        {
            var result = client.SayHello();
            Console.WriteLine(result);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

结果

如果有什么我可以帮忙的,请随时告诉我。

【讨论】:

  • 关于第一季度 - 如果我使用 IIS 设置该证书,然后将我的服务附加到它工作的域 - 所以我很确定证书没问题 - 我只是不想依赖 IIS
  • 稍后我会测试您的 Q2 答案并让您知道它是否有效
  • 尝试配置通信中使用的 TLS 版本。 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;并请参考我将证书绑定到应用程序端口的方式。
  • 好的 - 这就是我在 1. 在我的问题中提到的。除了我提到httpcfg 而你提到netshnetsh 是您在 Windows Vista 及更高版本中使用的,httpcfg 是您在 Windows Server 2003 及更高版本中使用的。这对于测试/调试来说是可以的,但是对于生产来说——我不知道客户是否有 Windows Server?
  • 是的,你是对的。这是我所知道的将证书绑定到端口的唯一可行方法。我在下面看到证书未绑定到端口。 Netsh http show sslcert|findstr 端口号
猜你喜欢
  • 2012-12-11
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
相关资源
最近更新 更多