2013-05-03 80 views
2

我有一个SSO站点,它使用的是NTLM身份验证,它在XP和Win 7(32位)上运行良好,但最近我的公司决定使用win 7(64位)电脑也是如此。在这些PC上,握手在类型2消息之后结束,并且tomcat返回401.我不知道如何调查,也许这里有人可以给我一些提示。NTLM身份验证在类型2响应后失败

这是servlet的doPost方法:

 try { 
     // NTLM Handshake 
     // 1: Client --> Server | GET ... 
     // 2: Client <-- Server | 401 Unauthorized/WWW-Authenticate: NTLM 

     String auth = request.getHeader("Authorization"); 
     if (auth == null) { 
      response.setStatus(response.SC_UNAUTHORIZED); 
      response.setHeader("WWW-Authenticate", "NTLM"); 
      response.flushBuffer(); 
      return; 
     } 
     if (auth.startsWith("NTLM ")) { 
      byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth 
        .substring(5)); 
      int off = 0, length, offset; 

      // 3: Client --> Server | GET .../Authorization: NTLM 
      // <base64-encoded type-1-message> 
      if (msg[8] == 1) { 
       // 4: Client <-- Server | 401 Unauthorized/WWW-Authenticate: 
       // NTLM <base64-encoded type-2-message> 
       byte z = 0; 
       byte[] msg1 = { (byte) 'N', (byte) 'T', (byte) 'L', 
         (byte) 'M', (byte) 'S', (byte) 'S', (byte) 'P', z, 
         (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z, 
         (byte) 1, (byte) 130, z, z, z, (byte) 2, (byte) 2, 
         (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z }; 

       response.setHeader("WWW-Authenticate", "NTLM " 
         + new sun.misc.BASE64Encoder().encodeBuffer(msg1)); 
       //response.sendError(response.SC_UNAUTHORIZED); 
       response.setStatus(response.SC_UNAUTHORIZED); 
       response.flushBuffer(); 
       return; 
      } 
      // 5: Client --> Server | GET .../Authorization: NTLM 
      // <base64-encoded type-3-message> 
      else if (msg[8] == 3) { 
       off = 30; 

       length = msg[off + 17] * 256 + msg[off + 16]; 
       offset = msg[off + 19] * 256 + msg[off + 18]; 
       String remoteHost = new String(msg, offset, length); 

       length = msg[off + 1] * 256 + msg[off]; 
       offset = msg[off + 3] * 256 + msg[off + 2]; 
       String domain = new String(msg, offset, length); 

       for (int i = 0; i < domain.length(); i += 2) 
        loginDomain += domain.charAt(i); 

       length = msg[off + 9] * 256 + msg[off + 8]; 
       offset = msg[off + 11] * 256 + msg[off + 10]; 
       String username = new String(msg, offset, length); 

       for (int i = 0; i < username.length(); i += 2) 
        loginUser += username.charAt(i); 
      } 
     } 
    } catch (Exception se) { 
     log.error(loginUser + ", NTLM handshake exception:", se); 
    } 
+0

你说的验证启用NTLM扩展安全,但你不是真的在这里检查密码...!?!看起来你真的只想从NTLM消息中获取用户名? – 2013-05-03 14:12:42

+0

@EdwardThomson您不需要密码进行NTLM身份验证。 NTLM是一项挑战/响应协议。 – 2013-05-03 14:22:09

+0

@MatthiasHerlitzius是的,但客户端使用密码来形成挑战。所以服务器应该*实际上查看响应*来进行身份验证,而不是假设因为你有*某些*响应,它必须是有效的。这里没有认证。 – 2013-05-03 14:24:51

回答

2

这是在64位PC的一个政策问题,因为NTLMv2的被迫。解决方案是在安全策略中禁用这些设置。

•运行“secpol.msc”这应该弹出标题为“本地安全策略”窗口

•安全设置 - >本地策略>安全选项>“网络安全:基于NTLM SSP的最小会话安全......”

有两个类似的条目,像这样开始,打开并取消选中“需要NTLMv2会话安全性”。

至少原来我们使用的是NTLMv1。 :|

+0

这是否会增加任何安全漏洞? – 2016-07-07 11:09:11

+1

是的,有更多最新的解决方案(如kerberos)用于SSO,但是如果您有一个复杂的方法来更改使用NTLM1的Web应用程序,则可以执行风险分析,以确定是否值得启用NTLM1或将NTLM1努力发展。伪造NTLM握手并不是一件微不足道的事情,很多用户都不具备这种能力。因此,不要将其用于财务解决方案,但可以将其用于例如网站。网球场预订。 – 2016-07-20 12:54:19

0

大多数公司网络将迁移到NTLMv2。我们不久前遇到了这个问题,并从http://www.ioplex.com/收购了Jespa。只要你有一个Servlet堆栈,它工作得很好。如果您使用像Play这样的非Java EE堆栈,我不知道除了支持NTLMv1之外的解决方案。

+0

当我调查问题时,我已经检查过Jespa,但由于您必须购买它,因此不是一种选择,我的经理告诉我要找到一个免费的解决方案。 :)无论如何,大多数链接都会导致这种解决方案,所以我猜如果有人认真对待这个NTLM,最终会结束一次。 – 2013-09-03 08:45:34

1

如果您仍然想坚持使用JCIFS,请尝试使用这些链接来克服“无效的参数错误”和“无法与适当的域控制器进行协商”。 它适用于NTLM,但不能保证与NTLMv2更安全地协同工作。

“参数无效” https://www.sysaid.com/Sysforums/posts/list/9065.page

“无法与一个合适的域控制器进行谈判” https://lists.samba.org/archive/jcifs/2005-August/005312.html

+0

欢迎来到Stack Overflow!我只是改进了你的文章中的一些拼写。最好还包括一个网站的相关信息,以防万一它发生故障而不是发布链接。你能编辑你的答案以包含相关信息吗? – 2015-07-02 16:37:38

2

试试这个

使用下面的代码

byte[] msg1 = { 
    (byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', 
    (byte) 'S', (byte) 'S', (byte) 'P', 
    z, (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z, 
    (byte) 1, (byte) 130, **(byte) 8**, z, z, (byte) 2, (byte) 2, 
    (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z 
}; 
+0

谢谢!我曾经使用类似于海报问题的代码来在java webapp中提取用户名。它停止与运行窗口10的机器一起工作。您的更改(在(字节)130之后使用(字节)8)解决了问题。你能解释一下你是怎么找到这个解决方案的? – user467257 2017-04-06 12:39:10