2013-05-03 104 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