首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 透過 NTLM 取得 Windows 登入使用者名稱實作代碼

     編輯:PHP 綜合知識

適用場景

企業內部系統、單一登入(SSO)前置作業、無需使用者輸入帳號密碼即可識別身分。僅適用於 Windows 域環境 + IE/Edge/Chrome(支援 NTLM)。

完整實作代碼

<?php
/************************************************************************
 * PHP NTLM GET LOGIN
 * Version 0.2.1
 * Copyright (c) 2004 Nicolas GOLLET
 ************************************************************************/
session_start();

$headers = apache_request_headers(); // 取得請求標頭

// 檢查 Proxy:NTLM 無法穿透 Proxy
if (@$_SERVER['HTTP_VIA'] != NULL) {
    die("Proxy bypass! NTLM authentication cannot work through proxy.");
}

// 第一階段:客戶端未提供 Authorization,發送 401 挑戰
if ($headers['Authorization'] == NULL) {
    header("HTTP/1.0 401 Unauthorized");
    header("WWW-Authenticate: NTLM");
    exit;
}

// 第二階段:解析 Type 1 訊息
if (isset($headers['Authorization'])) {
    if (substr($headers['Authorization'], 0, 5) == 'NTLM ') {
        $chaine = substr($headers['Authorization'], 5);
        $chained64 = base64_decode($chaine);
        
        // 檢查訊息類型(位元組 8)
        if (ord($chained64[8]) == 1) {
            // Type 1 訊息:回應 Type 2 挑戰
            // 檢查 NTLM 旗標(位元組 13 = 0xB2 = 178)
            if (ord($chained64[13]) != 178) {
                die("NTLM Flag error!");
            }
            
            // 建構 Type 2 訊息
            $retAuth = "NTLMSSP\0\0\0\0\0\0\0\0";
            $retAuth .= "\0\0\0\0\0\1\200\0\0";
            $retAuth .= "\0\0\0\0\0\0\0\0\0";
            $retAuth .= "\0\0\0\0\0\0\0\0\0";
            
            $retAuth64 = base64_encode($retAuth);
            
            header("HTTP/1.0 401 Unauthorized");
            header("WWW-Authenticate: NTLM $retAuth64");
            exit;
        }
        
        // 第三階段:解析 Type 3 訊息(包含認證資訊)
        else if (ord($chained64[8]) == 3) {
            // 解析 Domain
            $lenght_domain = ord($chained64[31]) * 256 + ord($chained64[30]);
            $offset_domain = ord($chained64[33]) * 256 + ord($chained64[32]);
            $domain = str_replace("\0", "", substr($chained64, $offset_domain, $lenght_domain));
            
            // 解析 Username
            $lenght_login = ord($chained64[39]) * 256 + ord($chained64[38]);
            $offset_login = ord($chained64[41]) * 256 + ord($chained64[40]);
            $login = str_replace("\0", "", substr($chained64, $offset_login, $lenght_login));
            
            if ($login != NULL) {
                $_SESSION['Login'] = $login;
                $_SESSION['Domain'] = $domain;
                header("Location: main.php"); // 導向主系統
                exit;
            } else {
                die("NT Login empty!");
            }
        }
    }
}

NTLM 交互流程圖解

Client                    Server
  |                         |
  |--- GET / --->          |
  |                         | (無 Authorization)
  |<-- 401 WWW-Auth: NTLM -|
  |                         |
  |--- GET / (Type1) --->  |
  |                         | 解析 Type1
  |<-- 401 WWW-Auth: NTLM -| (Type2 挑戰)
  |          (Type2)       |
  |                         |
  |--- GET / (Type3) --->  |
  |    (含 Domain/User)    | 解析 Type3 取得身分
  |                         |
  |<-- 302 Location: ... --| 登入成功

部署需求與限制

需求說明
Apache + mod_auth_ntlm_winbind或 IIS 整合 Windows 驗證
PHP 以模組模式運行apache_request_headers() 需支援
客戶端瀏覽器支援 NTLMIE/Edge/Chrome/Firefox(需設定)
同一網域/信任網域跨網域需信任關係
無 Proxy 中繼NTLM 連線導向無法穿透 Proxy

現代替代方案

  • Kerberos/SPNEGO:更安全、支援委派、雙向驗證
  • SAML/OIDC SSO:ADFS、Azure AD、Keycloak、Auth0
  • Windows Auth + PHP LDAP:ldap_bind() 驗證、查詢 AD 屬性

安全性警示

此代碼為教學用途,生產環境強烈建議使用成熟 SSO 方案。NTLM 存在已知弱點(中繼攻擊、哈希傳遞),且 Microsoft 已建議淘汰。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved