企業內部系統、單一登入(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!");
}
}
}
}
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() 需支援 |
| 客戶端瀏覽器支援 NTLM | IE/Edge/Chrome/Firefox(需設定) |
| 同一網域/信任網域 | 跨網域需信任關係 |
| 無 Proxy 中繼 | NTLM 連線導向無法穿透 Proxy |
ldap_bind() 驗證、查詢 AD 屬性此代碼為教學用途,生產環境強烈建議使用成熟 SSO 方案。NTLM 存在已知弱點(中繼攻擊、哈希傳遞),且 Microsoft 已建議淘汰。