通过浏览器扩展获取本机 MAC 地址

06-01 978阅读

在 Web 技术主导的 B/S 架构项目中,获取终端设备硬件信息(如 MAC 地址)的需求经常会碰到。尽管 Electron/CEF 等混合应用框架可通过系统级 API 轻松实现,但纯浏览器环境下的硬件信息获取则不那么容易。因为现代浏览器基于沙箱机制和隐私保护策略,严格禁止网页直接访问底层硬件资源。

但用户的需求不能不考虑,特别是在做商业项目时,这时就不得不给出方案,总结下来有如下三种方案:

  • 扩展 JS API:比如以前在做广电 TVOS 系统,局方就制定了一个 NGB-H 的 JS API 扩展标准。标准里面定义了很多与硬件有关的 JS API,其中就包括获取 IP 地址、MAC 地址等。这种方案的缺点是需要修改浏览器内核,工作量比较大。而且 Web 应用不能运行在标准的浏览器上,会给开发和调试带来不便。

  • 本地 http 服务:开发一个系统服务程序,该服务程序也同时是一个精简的 HTTP server,通过 RESTful API 提供硬件信息查询。web 应用通过 XMLHttpRequest 或 fetch 调用本地运行的 HTTP server,HTTP server 以 JSON 字符串的形式返回本机信息。这种方案需要在客户端安装一个服务,部署起来比较麻烦,而且需要考虑跨域的问题,需要特别小心。

  • chrome 扩展 + 本地应用:chrome 扩展提供了一种 Native Messaging 机制,用于和本地应用进行交互。这里的本地应用可以是一个可执行程序,也可以是一个脚本。这种方案不需要修改浏览器内核,插件开发也相对比较简单,缺点是部署有些麻烦,需要将本地应用(脚本)部署到指定的位置。

    这里就详细讨论第三种方案,以获取 MAC 为例,说明通过浏览器扩展获取本机 MAC 地址的方法。本示例以 Deepin 系统和 Chrome 浏览器为例,对于 Windows 和 Mac OS 脚本可能需要稍加修改。

    Native Messaging

    Native Messaging 是一种允许浏览器扩展与本地应用程序(Native Host)进行安全通信的机制,其核心设计在于突破浏览器沙箱限制,实现跨进程的 JSON 消息交互。

    • 浏览器扩展:通过声明 nativeMessaging 权限,向浏览器注册通信需求

    • Native Host:本地可执行程序(如 qt 应用程序、Python 脚本),需在系统中注册路径和权限(通过 manifest 文件)

    • 消息通道:基于标准输入输出(stdin/stdout)实现双向 JSON 数据传输

      通过这种机制,开发者能在保证安全性的前提下,将浏览器功能扩展到本地系统层级,广泛应用于企业工具、硬件控制等复杂场景。

      示例

      本文的完整示例程序可以在 https://e.coding.net/mogoweb/qt-in-action/chrome-extensions-samples.git 获取。

      一、项目结构

      native-messaging/
      ├── extension
      │   ├── icon-128.png         # 插件图标
      │   ├── main.html            # 插件界面
      │   ├── main.js              # 插件脚本
      │   └── manifest.json        # 插件配置文件
      ├── host/
      │   ├── com.uniontech.browser.extension.getmac.json    # Native Host 配置文件
      │   └── native-getmac        # 获取 MAC 地址,和插件通讯的 python 脚本

      二、核心代码实现

      Chrome 插件部分

      manifest.json

      {
        "manifest_version": 3,
      "name": "GetMac",
      "version": "1.0",
      "description": "Get host MAC address.",
      "action": {
          "default_title": "Get host MAC address",
          "default_popup": "main.html"
        },
      "icons": {
          "128": "icon-128.png"
        },
      "permissions": ["nativeMessaging"]
      }

      main.js

      function connect() {
      const hostName = 'com.uniontech.browser.extension.getmac';
        appendMessage('Connecting to native messaging host ' + hostName + '');
        port = chrome.runtime.connectNative(hostName);
        port.onMessage.addListener(onNativeMessage);
        port.onDisconnect.addListener(onDisconnected);
        updateUiState();
      }
      document.addEventListener('DOMContentLoaded', function () {
      document.getElementById('connect-button').addEventListener('click', connect);
      document
          .getElementById('send-message-button')
          .addEventListener('click', sendNativeMessage);
        updateUiState();
      });
      本地 python 程序

      native-getmac

      通过浏览器扩展获取本机 MAC 地址
      (图片来源网络,侵删)
      import struct
      import sys
      import threading
      import queue as Queue
      import uuid
      def get_mac_address():
        mac_num = uuid.getnode()  # 获取48位整型地址
        mac_hex = [
            f'{(mac_num >> shift) & 0xff:02x}'# 按字节分割并转十六进制
              for shift in range(0, 48, 8)        # 从高位到低位处理
          ][::-1]  # 反转顺序以符合人类阅读习惯
      return":".join(mac_hex)
      # Helper function that sends a message to the webapp.
      def send_message(message):
         # Write message size.
        sys.stdout.buffer.write(struct.pack('I', len(message)))
      # Write the message itself.
        sys.stdout.write(message)
        sys.stdout.flush()
      # Thread that reads messages from the webapp.
      def read_thread_func(queue):
        message_number = 0
      while1:
          # Read the message length (first 4 bytes).
          text_length_bytes = sys.stdin.buffer.read(4)
          if len(text_length_bytes) == 0:
            if queue:
              queue.put(None)
            sys.exit(0)
          # Unpack message length as 4 byte integer.
          text_length = struct.unpack('@I', text_length_bytes)[0]
          # Read the text (JSON object) of the message.
          text = sys.stdin.buffer.read(text_length).decode('utf-8')
          if text == '{"text":"exit"}':
            break
          if queue:
            queue.put(text)
          else:
            # In headless mode just send an echo message back.
            send_message('{"echo": %s}' % text)
      def main():
        send_message('"Mac: ' + get_mac_address() + '"')
        read_thread_func(None)
        sys.exit(0)
      if __name__ == '__main__':
        main()
      Native Host 配置

      com.uniontech.browser.extension.getmac.json

      {
        "name": "com.uniontech.browser.extension.getmac",
        "description": "Browser Native Messaging API to get MAC address",
        "path": "HOST_PATH",
        "type": "stdio",
        "allowed_origins": ["chrome-extension://npjblgiigcihbbfekfndobpbfibgldee/"]
      }

      注意,这个 json 中的 HOST_PATH 会通过 install_host.sh 脚本替换为实际的地址。

      通过浏览器扩展获取本机 MAC 地址
      (图片来源网络,侵删)

      三、注册与部署

      ./install_host.sh

      这个脚本实际上是将 com.uniontech.browser.extension.getmac.json 文件中的 HOST_PATH 替换成实际地址,并复制到 ~/.config/google-chrome/NativeMessagingHosts/ 目录。

      四、功能测试

      1. 加载插件到 Chrome(chrome://extensions → 开发者模式 → 加载已解压的扩展程序)

        通过浏览器扩展获取本机 MAC 地址
        (图片来源网络,侵删)
      2. 点击插件,点击 connect 按钮。

      在上面的界面中,我们还可以在插件中给本地应用发送消息,并接收本地应用返回的消息。

      小结

      本文探讨了一种通过 Chrome 插件和 Native Messaging 机制获取 MAC 地址的方法。通过修改本机 native 应用,我们还可以获取更多的硬件信息,甚至可以做更多的硬件控制。这种方法不需要修改浏览器内核,在 Linux、Windows 等系统都适用,甚至在 firefox 等浏览器上也有类似的机制,适应面广。

      希望本文提供的方法对大家有用,如果有更好的方案,欢迎交流。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码