【发布时间】:2012-03-17 22:38:18
【问题描述】:
我知道stackoverflow中有很多类似的问题,例如:
- What's a good way to uniquely identify a computer?
- What is a good unique PC identifier?
- Unique computer id C#
- WIN32_Processor::Is ProcessorId Unique for all computers
- How to uniquely identify computer using C#?
...还有几十个,我都研究过了。
问题在于,一些已接受的答案建议将 MAC 地址作为唯一标识符,这是完全不正确的。其他一些答案建议使用各种组件的组合,这似乎更合乎逻辑。但是,在使用组合的情况下,应该考虑哪个组件自然不太可能频繁更改。几天前,我们为软件许可问题开发了一个密钥生成器,我们使用 CPUID 和 MAC 的组合来唯一识别 Windows pc,直到实际测试我们认为我们的方法足够好。具有讽刺意味的是,当我们对其进行测试时,我们发现三台计算机使用我们的密钥生成器返回相同的 id!
那么,真的有任何方法可以唯一地识别任何计算机吗?现在我们只需要让我们的密钥生成器在 windows pc 上工作。由于我们的系统是在 .net 上开发的,因此使用 c# 的某种方式(如果可能的话)会很棒。
更新:
很抱歉造成了一些混乱和明显的误报。我们在检索硬件信息的方法中发现了一些错误。最初我想删除这个问题,因为现在我自己的困惑已经消失,我相信两个或多个组件的组合足以识别计算机。但是,后来我决定保留它,因为我认为我应该澄清导致问题的原因,因为同样的事情将来可能会伤害其他人。
这是我们正在做的(不包括其他代码):
我们使用 getManagementInfo 函数来检索 MAC 和处理器 ID
private String getManagementInfo(String StrKey_String, String strIndex)
{
String strHwInfo = null;
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + StrKey_String);
foreach (ManagementObject share in searcher.Get())
{
strHwInfo += share[strIndex];
}
}
catch (Exception ex)
{
// show some error message
}
return strHwInfo;
}
然后我们在需要的地方使用该函数来检索 MAC 地址
string strMAC = getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress");
并检索处理器ID
string strProcessorId = getManagementInfo("Win32_Processor", "ProcessorId");
此时,如果有多个 MAC 地址,strMAC 将包含多个 MAC 地址。为了只取一个,我们只取了前 17 个字符(12 个 MAC 数字和中间的 5 个冒号)。
strMAC = strMAC.Length > 17 ? strMAC.Remove(17) : strMAC;
这是我们犯错的地方。因为getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress") 返回了一些额外的 MAC 地址,这些地址确实在使用中。例如,当我们通过getmac 命令在命令提示符中搜索 MAC 地址时,它会为每台电脑显示一个或两个不同的 MAC 地址。但是getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress") 返回了四到五个 MAC 地址,其中一些对于所有计算机都是相同的。由于我们只是获取了函数返回的第一个 MAC 地址,而不是检查其他任何内容,因此偶然在strMAC 中获取了相同的 MAC 地址。
Sowkot Osman 的以下代码通过仅返回第一个活动/启用的 MAC 地址来解决问题:
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
}
private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
但是,对于相同的处理器 ID 问题,我是完全正确的。当我们将wmic cpu get ProcessorId 命令放在它们的命令提示符中时,这三个都返回了相同的处理器 ID。
现在我们决定使用主板序列号而不是处理器 ID 来与 MAC 地址进行组合。我认为我们的目的将通过这种方式实现,如果在某些情况下不能实现,那么我们应该在少数情况下放弃它。
【问题讨论】:
-
简单的答案是否定的。由于 PC 由许多可互换的部件组成。随着时间的推移,唯一可能保持不变的就是这种情况。因此,您需要指定的第一件事是您认为 PC 的哪些部分(就硬件而言)是“PC”。无论您选择什么,都将是某种妥协,因此您对先前答案的看法会模棱两可或不正确。
-
如果您使用 CPUID 和 MAC 地址来识别机器并且三台机器返回相同的 ID,那么您的代码中存在错误。 MAC 地址是全球唯一的,在工厂分配。
-
MAC 地址可以更改/欺骗,因此将其作为单一身份验证方法是不明智的。这就是为什么我们决定使用 MAC 和 CPUID 的组合,这受到@Paul Alexander 和其他人在之前发布的类似问题中给出的建议的影响。即使在那之后获得相同的身份也是非常奇怪和奇怪的。我们使用另一个软件重新检查了问题,它还为三台计算机中的两台计算机返回了相同的 MAC 和处理器 ID,而我们还没有对第三台计算机进行测试。
-
如果您要坚持使用主板序列号,请确保您的代码在检索序列号不起作用的情况下能够应对。例如,对于虚拟机来说这可能是不可能的,在某些情况下甚至在真实硬件上也可能是不可能的。 (我仍然认为这是一个糟糕的决定,因为如果有问题的主板死机,它会让用户完全陷入困境,这是糟糕的客户关系。)
-
伪造的 MAC ID 仅在 LAN 中有效。如果在系统内部使用 getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress") 之类的函数,它实际上是从硬件中检索原始 MAC ID,而不是伪造的 MAC ID。所以,不用担心 MAC 地址欺骗。
标签: c# windows uniqueidentifier