当前位置: 首页 > article >正文

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

在 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 <b>' + hostName + '</b>');
  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

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 脚本替换为实际的地址。

三、注册与部署

./install_host.sh

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

四、功能测试

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

  2. 点击插件,点击 connect 按钮。


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

小结

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

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


http://www.kler.cn/a/592694.html

相关文章:

  • 设计模式之代理模式:原理、实现与应用
  • python中测试数据管理整理
  • linux sh脚本关于返回字符串调试问题(adb shell)
  • Winform优化控件布局性能 SuspendLayout 和 ResumeLayout 方法详解
  • 游戏引擎学习第164天
  • openEuler24.03 LTS下安装Hadoop3完全分布式
  • Java并发(知识整理)
  • JS做贪吃蛇小游戏(源码)
  • uni-app——计时器和界面交互API
  • 【笔记】深度学习模型训练的 GPU 内存优化之旅:重计算篇
  • 人工智能中神经网络是如何进行预测的
  • 涨薪技术|Kubernetes(k8s)之yaml语法大全
  • AI实干家:HK深度体验-【第3篇-香港、新加坡、深圳、上海、首尔五座城市在金融数据维度的对比分析】
  • 31天Python入门——第5天:循环那些事儿
  • 【Go每日一练】随机密码生成器
  • 大语言模型黑盒越狱攻击之模板补全
  • Android retrofit 接口请求,提示CLEARTEXT communication处理
  • PostgreSQL:语言基础与数据库操作
  • 苹果电脑mac M1 15.0 安装虚拟机以及Debian系统 |Debian优化汉化中文 |Debian换阿里下载源 |Debian新建用户
  • 【简单有效!】Gradio利用html插件实现video视频流循环播放