从express请求对象中获取客户端MAC地址

3

我想从传入请求对象中获取MAC地址。我的应用程序在nginx代理后运行,所以为了获取IP地址,我使用下面的语法,它可以正常工作。

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

同样,有没有一种方法可以获取已发出请求的MAC地址。发现了这个包https://www.npmjs.com/package/getmac,但我不确定它是否有帮助。基本上,我需要获取每个传入请求的MAC和IP地址。


HTTP请求不包含任何MAC地址吗? - Bergi
你需要它做什么? - Bergi
@Bergi,我正在尝试获取IP地址和MAC地址,以识别发出请求的终端用户设备。我正在开发的应用程序涉及订阅,并且我正在尝试捕获每天的订阅数量,所以当从桌面或任何手持设备发出请求时,我会尝试收集这些信息。 - Sai
你可以获取IP地址,但无法获取MAC地址。这是出于良好的原因而不公开。如果你想区分台式机和手持设备,那么你应该使用其他机制。 - Bergi
谢谢@Bergi,也许我需要使用"用户代理"来识别请求的设备。 - Sai
是的。用户代理字符串、屏幕尺寸,还有其他一些东西。有很多方法可以实现。试着找一个已经为你做好了的库,而不是重新发明轮子。 - Bergi
4个回答

6

所以在这种情况下,由于我正在尝试获取发出请求的设备的MAC地址,是否有任何插件或软件包可以满足这个要求呢? - Sai
2
就像我刚才说的,这个信息在你那边是不存在的,所以你无法获取MAC地址,就此打住。-(只有当你对发送请求的设备有控制权时,你当然可以添加代码将MAC地址作为参数发送。) - CherryDT
1
没有什么是不可能的。另一个问题可能是:Paypal如何获取其客户的MAC地址,并将其用作账户安全程序? - codervince
我不认为他们可以仅凭浏览器获取您的MAC地址 - 也许他们使用了一个需要您授权的Java小程序,或者在客户端机器上运行的其他编码部分?关键是,“没有什么是不可能的”并不会让信息凭空出现。MAC地址不会通过互联网传输 - 您的路由器可以看到它,或者如果您直接连接(例如通过3G),您的ISP可以看到它,但下一个跳已经无法看到,他们会看到您的路由器或ISP的MAC地址等。没有任何东西将您的MAC地址转发给链中下一个网络硬件。 - CherryDT
如果客户端直接连接呢? - Alexandr Zarubkin
除非你是指通过交叉型局域网电缆连接两台计算机,否则并不存在这样的事情。 - CherryDT

1

您无法从请求中获取它,但您可以先获取它,然后将其存储在req.session中。

如何获取MAC地址:

const os = require( 'os' );
var mac_ip = os.networkInterfaces()['en3'][3]['mac'];
console.log('ip_test: ', ip_test);
req.session.macip = mac_ip;

你可以记录下 networkInterfaces 来检查你想要的所有内容:
var networkInterfaces = os.networkInterfaces();
console.log( networkInterfaces );

注意:此方法仅可获取运行节点进程的设备的MAC地址。如果从您的服务器运行,则此方法将获取您的服务器的MAC地址,而不是发出请求的客户端的MAC地址。


0

这个回答可能对原问题过于具体,但其他人可能会发现这很有用。根据其他答案,这种方法并不适用于所有情况,但在以下详细说明的条件下确实有效。

我的使用情况

  • 仅限本地网络服务器
  • Linux计算机

我的解决方案

我之前编写了一个脚本来查找已知MAC地址的特定计算机是否在网络上。

homeip=$(sudo arp-scan -lq | grep -i -m 1 $homemac | grep -oP "\d+\.\d+\.\d+\.\d+")

然而,这样做需要很长时间(在子网掩码为255.255.192.0的网络上执行可能需要超过30秒!)

该脚本缓存了IP地址,可以使用类似以下内容迅速验证该机器的有效性:

ping -c 1 -w 2 -q $homeip > /dev/null
$(arp -a | grep -m 1 -oP "(?<=\($homeip\) at )([\da-f]{2}:){5}[\da-f]{2}") != "$homemac"

因此,我决定为我的服务器采用一种粗略的身份验证方式,即通过MAC地址将某些用户列入白名单。这样做分为多部分。 < p > < code > resolveip
#!/bin/bash

out=$(arp -a | grep -m 1 -oP "(?<=\($1\) at )([\da-f]{2}:){5}[\da-f]{2}")
if [ -z "$out" ]; then
    ping -c 1 -w 1 $1 > /dev/null
    echo $(arp -a | grep -m 1 -oP "(?<=\($1\) at )([\da-f]{2}:){5}[\da-f]{2}")
else
    echo $out
fi

创建一个包装器。
function getRequestingMAC(requestingIP) {
    return new Promise((resolve, reject) => {
        execFile(`resolveip`, [requestingIP], (error, stdout, stderr) => {
            resolve(stdout.toString().trim());
        });
    });

    // Sync-style
    // return execFileSync(`resolveip`, [requestingIP]).toString().trim();
}

并且像这样使用:

app.use((req, res, next) => {
    if (req.hostname === "localhost") {
    } else {
        //match first occurrence of ipv4 ip, not ideal regex
        let ip = (req.headers['x-forwarded-for'] || req.socket.remoteAddress).match(/\d{1,3}(\.\d{1,3}){3}/)[0];
        console.log(ip);
        loop: {
            // check if request came from known ip (my ip)
            const ifaces = require('os').networkInterfaces();
            for (const ifaceKey in ifaces) {
                let iface = ifaces[ifaceKey];
                if (iface.some(it => it.address === ip)) {
                    console.log("Local Request");
                    break loop;
                }
            }
            // else, request mac
            getRequestingMAC(ip).then((ans) => {
                console.log("Request Came From", ans, ip);
                // Give me a banner notif when access attempted
                exec(`zenity --notification --text "Foreign request\n${ans} (${ip}) to ${req.url}"`);
            });
        }
    }
    next();
})

这可以更改为在调用next()之前等待mac,并阻止非白名单请求。

注意

再次强调,这在操作的用例中不起作用,但在我的用例中可以并且确实起作用。


0
MAC地址用于节点之间的通信,属于OSI模型中的数据链路层。它们不会暴露在你的本地网络之外。在Linux的net-tools软件包中可以找到arp命令,它可以列出IP地址与本地网络中设备的MAC地址之间的映射。你可以使用以下命令通过IP地址找到特定设备的MAC地址。
arp -n | grep 192.168.1.2 | grep -Eo '([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}'

要在Node.js中执行上述shell脚本,可以使用child_process模块:
const { exec } = require('child_process');

exec("arp -n | grep 192.168.1.2 | grep -Eo '([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}'", (error, stdout, stderr) => {
  if (error) {
    console.error(`Error: ${error.message}`);
    return;
  }
  if (stderr) {
    console.error(`stderr: ${stderr}`);
    return;
  }
  console.log(stdout);
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接