为什么WCF中Kerberos默认切换到NTLM?

8

我有一个简单的WCF演示应用程序,其中包括两个控制台项目-主机和客户端。两者都在我的机器上运行(win 7框)。我正在使用netTcpBinding,它使用Windows身份验证。

问题在于身份验证从kerberos降级到NTLM,我无法弄清原因。

如果我使用

<clientCredentials>
   <windows allowNtlm="true" />
</clientCredentials>

在客户端,一切都很好。但是如果我将其更改为false,则会出现以下异常:

SecurityNegotiationException:远程服务器未满足相互身份验证要求。

这表明kerberos失败了,由于客户端不允许NTLM,所以调用结果会导致抛出异常。
这是项目的问题还是由于开发机器的配置而引起的外部问题?
解决方案:
显然,我必须在客户端配置中指定服务器的身份。在我的情况下,服务器正在我的身份下运行,因此我这样修改了客户端:
<client>
  <endpoint address="net.tcp://dev7.HurrDurr.com:12345/MyService" 
            binding="netTcpBinding" 
            bindingConfiguration="MyBindingConfigurationLol" 
            behaviorConfiguration="HurrDurrServiceEndpoint" 
            contract="ShaolinCore.ICommunicationService">
    <!-- start changes here -->
    <identity>
      <userPrincipalName value="myusername@mydomain"/>
    </identity>
    <!-- end changes here -->
  </endpoint>
</client>

我不确定为什么这样能解决问题。在客户端方面,我完全信任服务器(嘿,我认识那个家伙!)。但由于NTLM比Kerberos不太安全,为什么不反过来呢?如果我不完全信任服务器,我使用Kerberos,否则NTLM就可以。或者说,另一方面,如果我不完全信任服务器,为什么它还能正常工作呢?"SecurityException: Endpoint identity not set. WCF无法信任服务器的身份,也不会传输客户端的身份。"

这似乎是一个适合serverfault.com的问题。 - phkahler
重新列出的解决方案:正是因为这个原因,Kerberos更加安全——服务器是一个可信且已知的源,具有保证地址和运行在该地址上的进程的身份。作为不同用户运行的服务帐户将无法处理您的请求。 - Hogan
@hogan 我认为 kerb/ntlm 更多的是关于认证而不是授权。使用 kerb 让我能够与任何服务器进行身份验证;一旦我知道了服务是谁,我就可以决定是否想要与他们打交道。如果我通过 kerb 进行身份验证,我就有了由受信任的第三方(AD)提供的服务的身份。如果服务被欺骗,我可以通过该身份告诉它,并在不符合预期时抛出异常。在 WCF 中,似乎欺骗的服务器会失败于 kerb 然后通过 ntlm 成功。这对我来说似乎不安全。与任何人进行身份验证,如果他们不是我所期望的人,则抛出异常。 - user1228
听起来不错,但这并不是它的实现方式。 - Hogan
4个回答

9
当我在IIS4、5和6开发团队工作时,我们经常遇到这个问题!为了让Kerb正常工作,需要满足以下条件:
1)双方都支持Kerb(所有支持的Windows版本今天都支持Kerb)
2)机器通过Active Directory进行认证
3)为服务器端点注册服务主体名称(SPN)。在“好旧的日子里”,您必须使用SetSPN.exe手动执行此操作。SPN只是Kerb将连接到的端点;它需要这些数据来支持相互认证。大多数应用程序将调用适当的API来为您完成此工作(DsWriteAccountSpn)
如果上述步骤中的任何一步不正确,Windows通常会默认使用NTLM,这只提供客户端身份验证。
希望这有所帮助! - Michael

我读了一两本关于Windows安全的书,有时候还是很困惑。我也不太理解WCF如何处理相互认证,所以这让它变得更加困难。为什么我必须提供服务器UPN/SPN/DNS才能在客户端上启用Kerb?如果我不完全信任服务器,为什么NTLM比Kerb更好?或者客户端需要向第三方提供服务标识?为什么服务不能直接提供它?为什么我的头疼? - user1228
Kerb需要对客户端和服务器进行身份验证,我指的是计算机。当您的客户端代码(WCF)请求连接到服务时,它需要确切地知道它正在连接到什么,因此管理员需要将服务器应用程序的SPN添加到AD中 - 本质上,您要告诉Kerb“我需要连接到这个SPN”。在许多情况下,方程式的服务器端注册一个SPN,但只有在具备此能力的情况下才会这样做。NTLM不比Kerb更好,NTLM仅对客户端进行身份验证,因此服务器知道您是谁,但您不知道您正在连接到谁。 - Michael Howard-MSFT
另外,只有在通过 DNS 名称调用服务时才能使用 Kerberos。通过 IP 地址调用服务将导致使用 NTLM。 - bug

2

据MSDN消息: netTcpBinding:默认绑定使用传输安全和协商身份验证。这种协商尝试使用Kerberos,但如果不行,它将退而使用较老的NTLM协议。如果您在域环境中,则Kerberos是一个很好的选择;为了使用它,您需要使服务和客户端都在域帐户下运行。您还需要为您的服务配置服务主体名称(SPN)。


理论上来说,在阅读了您一开始没有阅读的评论之后,这种行为似乎是按设计来的。 - Ta01

1
服务器配置如何?您在配置文件中是否有<authentication mode="Windows"/><identity impersonate="true"/>
您可以通过配置文件中的authentication标签来设置身份验证模式:
<configuration>
  <system.web>
    <authentication mode="Windows" />
  </system.web>
</configuration>

我认为这些只适用于HTTP绑定。然而,我正在指定我的clientCredentialType为Windows。 - user1228
如果客户端允许NTLM,则它可以工作,否则会失败(这意味着我认为Kerberos不可用)。 - user1228
据我所知,它们不仅适用于 HTTP。 - Hogan
我在任何与tcp有关的内容中都没有看到authenticationMode。然而,我也没有看到identity,最终那就是解决方案。在tcp绑定中,在哪里设置身份验证模式(在xml中,而不是在代码中kthx)? - user1228
这是一个控制台应用程序;我不认为我如何登录网站与我正在体验的有多大关系... - user1228

1
也许MSDN上的这个页面 - 调试Windows身份验证错误 - 可以帮助你弄清楚正在发生什么 - 看起来很棘手,因为不知道何时使用NTLM与Kerberos。

k...域用户两端都有,检查通过。完全限定的URL已更新,没有差异。添加身份验证/ UPN…没有差异。正在为客户端配置SPN身份验证…成功! - user1228
@Will:很酷,我正想建议你检查服务器和客户端上的SPN。 - Hogan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接