65.9K
CodeProject 正在变化。 阅读更多。
Home

SSL 与自托管 WCF 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (48投票s)

2008年3月1日

CPOL

6分钟阅读

viewsIcon

419717

一篇关于证书和 WCF 的有时晦涩难懂的文章

引言

要在客户端和服务器之间执行任何类型的 SSL 加密,必须有证书。对于初学者来说,证书可能有点晦涩难懂,尤其是当它们与一些奇怪的 WCF 配置设置混在一起时,但别担心,一切尽在这里。

我写这篇文章(我的第一篇)的原因是,我非常努力地才让它奏效,而我需要的信息散落在各个地方。我还在运行时遇到了很多错误,而这些错误实际上是由过程中更早的设置问题引起的。非常非常令人恼火。希望这能为某人省去一些麻烦!

我假设您熟悉 WCF 的基础知识,并且熟悉配置文件等。我没有包含任何源代码,因为服务本身实际上并不重要,SSL 的关键在于设置。

证书

本示例假设您(和我一样)没有权限访问漂亮闪亮的证书颁发机构 (CA),并且需要使用 makecert 工具。(稀疏的信息可以在 这里 找到。)

注意: 我最近发现了 这个 很棒的网站,一个免费的 CA,谁能想到呢。

您需要一个证书 (cert) 来充当您的根颁发机构,还有一个证书来充当实际用于 SSL 的证书,该证书需要由您的根颁发机构签名。如果您不设置根颁发机构,您的单个证书将不被信任,您将在事后很长一段时间通过一系列极其令人恼火的 WCF 异常来发现这一点。
以下命令(在 Visual Studio 命令提示符下运行)将创建您的根证书,不,这不是我自己想出来的,您可以在各处找到一些很好的示例,例如 这里)。

makecert -sv SignRoot.pvk -cy authority -r signroot.cer -a
    sha1 -n "CN=Dev Certification Authority" -ss my -sr localmachine

请查看上面的链接,了解这些参数的含义,这并不非常重要,但知道一下也很好。

运行此命令并成功后,您需要将此证书设为受信任的颁发机构。您可以通过 MMC 管理单元控制台来完成此操作。转到运行窗口并输入“mmc”,然后按 Enter。然后在打开的窗口(称为“Microsoft 管理控制台”,如果你关心的话)中执行以下操作。

文件 -> 添加/删除管理单元 -> 添加… -> 双击证书 -> 选择计算机帐户并单击下一步 -> 完成 -> 关闭 -> 确定

然后选择“证书(本地计算机)” ->“个人” ->“证书”节点。

Personal Certificates

您应该会看到一个名为“Dev Certificate Authority”(或您决定的任何其他名称)的证书。将此证书从当前节点移动到“证书(本地计算机)” ->“受信任的根证书颁发机构” ->“证书”节点,拖放即可轻松完成。

Trusted Certificates

现在您拥有的**不是**您需要的证书 :)
不过,您已经能够创建受信任的证书了,这很好。
现在您必须创建另一个证书,也就是您实际上要使用的证书。
再次运行 makecert,但按如下方式运行...

makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n
    CN="localhost" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr
    localmachine -sky exchange -sp
"Microsoft RSA SChannel Cryptographic Provider" -sy 12

请注意,您正在使用第一个证书作为最新证书的颁发者。这很重要…在我写 localhost 的地方,您需要填写您机器的 DNS 名称。换句话说,如果您部署服务的方式是其终结点读取 http://bob:10010/Service,那么该名称就是 bob。此外,您还需要为需要运行的每个主机执行此操作(是的,一个用于 bob,另一个用于 localhost)。

通过双击证书(选择“证书(本地计算机)”‘“个人”‘“证书”)来获取证书的签名,打开详细信息选项卡,然后滚动到“指纹”选项。

Thumbprint with carefully sprayed values

选择指纹并复制。将其粘贴到记事本或其他文本编辑器中,并删除空格。保留它。(更多关于如何执行此操作的信息可以在 这里 查看,尽管此链接有点不必要。)
您的证书已设置完毕。

配置带 SSL 证书的端口

现在您可以使用另一个有趣的工具 httpcfg。(有关更多信息,请参阅 这里。)首先运行以下命令,以检查您想要的端口上没有任何正在运行的服务。

httpcfg query ssl
Mine looks like this

请注意,有两个端口,一个将用于 chrise 的请求,一个将用于 localhost,请跟踪哪个是哪个。

如果您是第一次执行此操作,它应该只返回一个换行符。如果确切的 IP 地址已经设置了 SSL(或者以后您需要删除任何错误),您可以使用以下命令,其中 IP 地址和端口显示为上一个查询的结果。

httpcfg delete ssl -i 0.0.0.0:8888

在完成对以上两个命令的修改后,运行以下命令,将给定的证书(从而允许非对称加密)与给定的端口关联起来。
请注意,IP 地址 0.0.0.0 是一个特殊的地址,表示此 PC 上的所有 IP 地址。

httpcfg set ssl -i 0.0.0.0:8012 -h abababababababababababababab

其中最后一个部分 (ab^n) 是您之前保留的指纹(您保留了吗?)。好了,您现在拥有一个启用了 SSL 的端口。

WCF服务

终于!
WCF 服务中用于 SSL 的大部分工作都在配置中。我个人更喜欢配置文件,但这也可以在代码中完成。

服务配置需要如下所示

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NewBehavior">
          <serviceMetadata httpsGetEnabled="true"/>
         </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding name="Binding">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
         </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="NewBehavior" 
            name="TestWCF.ServiceImplementation.TestWCFService">
        <endpoint
          address="https://chrise:10081/TestWCFService"
          binding="basicHttpBinding"
          bindingConfiguration="Binding"
          name="TestWCFService.Http"
          contract="TestWCF.ServiceContracts.ITestWCFService" />
        <host>
          <baseAddresses>
            <add baseAddress="https://chrise:10081/TestWCFService" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
 </configuration>

请注意,httpsGetEnabled 设置为 true。这意味着即使是您的 mex 也是加密的,很酷!另请注意,chrise(在这种情况下为主机名)**必须**有相应的证书,否则无效。
我使用的是 basic HTTP 绑定。您也可以使用 wsHTTP,但如果整个传输都已加密,那么对消息进行加密有什么意义呢?
请注意,clientCredentialType 设置为 none,这只是为了简化整个解决方案,否则我们将进入另一篇文章。

客户端如下所示

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="TestWCFService.Http">
                <security mode="Transport">
                    <transport clientCredentialType="None" 
                        proxyCredentialType="None"
                        realm="" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address=https://chrise:10081/TestWCFService 
                binding="basicHttpBinding"
            bindingConfiguration="TestWCFService.Http" 
                contract="TestWCF.Client.TestWCFService.ITestWCFService"
            name="TestWCFService.WSHttp" />
    </client>
</system.serviceModel>

这样应该就可以工作了!

我遇到的一些异常

首先,这只能在您的本地计算机上工作。为什么?因为世界上没有其他计算机愚蠢到会信任您的个人证书。为了让您的客户端在另一台 PC 上正常工作,您需要导出您的颁发机构证书和 SSL 证书,然后将它们导入到客户端的 PC 上。这就是为什么 makecert **不适合生产环境**。各位,请使用真正的 CA。

其次,当服务运行时,您应该能够浏览到终结点。如果您这样做时,出现一个提示您有关证书可信度的弹出窗口,那么您的证书不被信任,客户端将无法与服务器通信。

© . All rights reserved.