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

PHP 與 JavaScript 獲取客戶端 MAC 地址的實現方案與侷限性分析

     編輯:PHP 相關知識

前言:MAC 地址獲取的現實邊界

MAC 地址屬於資料鏈路層 (Layer 2) 識別碼,無法跨越路由器 (Layer 3) 傳輸。因此:

  • 伺服器端 PHP:僅能獲取同一區域網路內客戶端的 MAC(透過 ARP 表或 NBTSTAT)。
  • 客戶端 JavaScript:受瀏覽器沙箱限制,標準 Web API 完全無法讀取 MAC,僅有 IE 透過 ActiveX (WMI) 實現,且需用戶授權。

本文提供程式碼參考,並強調適用場景與安全風險。

一、PHP 端:獲取區域網內客戶端 MAC

原理:伺服器收到請求後,從 $_SERVER['REMOTE_ADDR'] 取得客戶端 IP,執行系統指令查詢本機 ARP 快取或 NetBIOS 表。

核心類實現 (支援 Windows/Linux 雙平台)

<?php
class MacAddr {
    public $returnArray = [];
    public $macAddr = '';

    public function __construct($os_type = null) {
        if (is_null($os_type)) $os_type = PHP_OS;
        switch (strtolower($os_type)) {
            case 'linux': $this->forLinux(); break;
            case 'windows': default: $this->forWindows(); break;
        }
        $this->parseMac();
    }

    private function forWindows() {
        @exec("ipconfig /all", $this->returnArray);
        if (!$this->returnArray) {
            $ipconfig = $_SERVER["WINDIR"] . "\\system32\\ipconfig.exe";
            @exec($ipconfig . " /all", $this->returnArray);
        }
    }

    private function forLinux() {
        @exec("ifconfig -a", $this->returnArray);
    }

    private function parseMac() {
        $pattern = '/[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}/i';
        foreach ($this->returnArray as $line) {
            if (preg_match($pattern, $line, $m)) {
                $this->macAddr = $m[0];
                break;
            }
        }
    }
}

// 獲取伺服器自身網卡 MAC (示範)
$mac = new MacAddr(PHP_OS);
echo "Server MAC: " . $mac->macAddr . "<br/>";

// 獲取「同網段」客戶端 MAC
$ip = $_SERVER['REMOTE_ADDR'];
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $cmd = "nbtstat -a $ip";
} else {
    $cmd = "arp -a $ip";
}
echo "Command: $cmd <br/>";
$result = `$cmd`;
echo "<pre>" . htmlspecialchars($result) . "</pre>";
?>

關鍵限制與效能警示

  • 僅限同一廣播域:跨 VLAN、跨路由器、雲端部署均失效。
  • 權限需求:PHP 執行身分需具備執行 arp/nbtstat/ipconfig 權限 (Linux 需 root/sudo,Windows 需管理員)。
  • 執行緩慢:系統指令呼叫延遲高 (數百毫秒至秒級),嚴禁用於高併發請求路徑。
  • ARP 快取時效性:客戶端近期無通訊則無 ARP 記錄,需先 Ping 觸發。

二、JavaScript 端:IE 專屬 ActiveX 方案 (已棄用)

僅供歷史參考,現代瀏覽器 (Edge/Chrome/Firefox/Safari) 全部不支援。

<!-- 僅 IE 有效,且彈出安全警告 -->
<object id="locator" classid="CLSID:76A64158-CB41-11D1-8B02-00600806D9B6"></object>
<object id="foo" classid="CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223"></object>
<script language="JScript" event="OnObjectReady(objObject,objAsyncContext)" for="foo">
    if (objObject.IPEnabled && objObject.MACAddress) {
        MACAddr = objObject.MACAddress; // 格式如 "00:11:22:33:44:55"
    }
</script>
<script language="JScript" event="OnCompleted(hResult,pErrorObject, pAsyncContext)" for="foo">
    document.forms[0].lbMacAddr.value = unescape(MACAddr);
</script>
<script language="JScript">
    var service = locator.ConnectServer();
    service.Security_.ImpersonationLevel = 3;
    service.InstancesOfAsync(foo, 'Win32_NetworkAdapterConfiguration');
</script>
<form><input type="text" id="lbMacAddr" name="lbMacAddr" /></form>

為何此方案不可用於生產?

  1. 瀏覽器侷限:IE 11 之後微軟已停止更新,Edge/Chrome 無 ActiveX 支援。
  2. 安全阻擋:預設安全設定會阻擋「不安全的 ActiveX 控制項」,用戶需手動降低安全等級或加入信任站點。
  3. WMI 依賴:客戶端需啟用 WMI 服務且具備查詢權限。

三、現代替代方案:設備指紋

若需識別唯一設備,請放棄 MAC 地址,改用 瀏覽器指紋 技術:

  • Canvas 指紋、WebGL 指紋、AudioContext 指紋
  • User-Agent、螢幕解析度、時區、字體列表、擴充套件列表
  • 推薦庫:FingerprintJS (開源、無 Cookie、準確率 > 99%)

總結

方案適用範圍可行性建議
PHP + arp/nbtstat內網管理系統、區域網設備稽核有條件可行低頻率、後台任務、需 root/Admin 權限
JS ActiveX (WMI)極舊 IE 專用內網系統基本不可用棄用,遷移至指紋技術
瀏覽器指紋所有現代瀏覽器、跨網路環境高度推薦首選方案,無需特殊權限

結論:MAC 地址獲取受物理網路拓撲與瀏覽器安全模型雙重限制,不應作為通用身份識別手段。請根據業務場景選擇指紋識別、Token 認證或內網專用 ARP 查詢。

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