上一篇从身份证号是如何生成,来认识了中心机构下生成惟一标识的方法,这一篇来看看面对庞大的计算机世界,无中心机构时,那又如何生成惟一标识呢?javascript
认识UUIDjava
接下来从一个广为人知的模块UUID讲起,它彷佛在每一个语言里都有对应的实现,甚至在部分Unix系统直接提供了实现。node
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxxpython
其中M与N都有特殊含义,M表示UUID版本,目前只有五个版本,即只会出现1,2,3,4,5,数字 N的一至三个最高有效位表示 UUID 变体,目前只会出现8,9,a,b四种状况。算法
可是现实状况却并不是是这样,也从横纵两个方向去看。npm
1.计算机对于时间虽然精度很高,可是分布在世界各个角落里的状况下,计算机并不会经过某一个中心点获取当前时间,而是根据机器内部自身来获取,那就会出现一个问题,计算机自身时钟有误后被校准出现时间相同后生成uuid的问题,不过通常能够忽略,时间是相对的概念,只要自身一直保持一个时钟,便不会出现问题。2.实际上,MAC地址并不是彻底惟一。首先出厂计算机的商家也不是全球一家,即便约定了规范也不能保证网卡制造商没有偏差地为网卡分配惟一的 MAC地址。另外计算机在用户的手里,MAC地址在用户计算机上,用户要是了解计算机的原理构造,能不能主动的修改一下MAC地址呢?答案是能够的。3.同时执行生成UUID程序。当两个进程同时跑了一段生成UUID的代码时,它们所处的时间点一致,MAC地址也一致,这时候便也会出现生成相同UUID的状况。安全
以上从几个角度去看初版本的UUID生成后的会出现不惟一的缘由,可是上述状况出现仍是很小几率的,因此基本目前来讲最可靠能保证全球的惟一性的实现方法,也由于此,初版本UUID在一些前惟一性场景仍是很是常见。bash
使用示例服务器
Nodejs版本app
我翻阅了一下uuid这一版本的源码,虽然使用的人很是多,可是实际内部实现并无取机器的MAC地址,由随机数拼接而成。
const uuidv1 = require('uuid').v1;
const logger = console.log;
logger('uuid v1版本:%s', uuidv1());
// uuid v1版本:10e10f40-bd02-11e9-b241-97aa7a999bec复制代码
python版本
在python自带的uuid模块中,确实获取了机器网卡的MAC地址。
import uuid;
uuid.uuid1();
# UUID('e852b72e-ba4d-11e9-8e8e-acde48001122')复制代码
用ifconfig命令查看一下网卡MAC。
从上两个例子能够都可看出M位是1,N位在a,b,8,9内,都是符合UUID开始时所述的规范。最后的12位acde48001122正是我机器的网卡,一直保持不变的。
暴露MAC地址所产生的安全问题
这一版本的UUID比较大的一个问题就在于它的组成里含有用户的MAC地址,每台计算机绑定了一个用户,则MAC地址也对应了用户,这表明着MAC地址的暴露则形成了隐私问题与安全问题。
经过UUID抓获病毒制造者
1998年,由美国人David L. Smith运用Word的宏运算编写出的一个电脑病毒,其主要是经过邮件传播,邮件的标题一般为“这是给你的资料,不要让任何人看见”,一旦收件人打开邮件,病毒就会自动向用户通信录的前50位好友复制发送一样的邮件。尽管这种病毒不会删除电脑系统文件,但它引起的大量电子邮件会阻塞电子邮件服务器,使之瘫痪,形成了至关大的危害,最终就是这位病毒制造者David L. Smith就是由于在脚本中使用的UUID中暴露了机器的MAC信息,最后在计算机信息中心配合下,肯定其位置并缉拿归案。
3、基于MD5散列算法的UUID
默认的命名空间
nodejs中
// nodejs uuid源码中预约义的命名空间
generateUUID.DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
generateUUID.URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';复制代码
python中:
#python中默认预约义的命名空间
import uuid
uuid.NAMESPACE_DNS #UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8');
uuid.NAMESPACE_URL #UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8');
uuid.NAMESPACE_X500 #UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8');
uuid.NAMESPACE_XX #UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8');复制代码
版本特色:
1. 基于相同命名空间下,不一样输入值的生成的UUID不一样,并不是彻底不一样,有必定概率相同。
2. 基于相同命名空间下,相同输入值的生成的UUID不一样。
3. 基于不一样命名空间生成的UUID必定不会相同,固然我理解这是不出现MD5碰撞的前提下。
4. 基于两个输入值的UUID相同,那么必定是来自相同的命名空间下的同一个输入值。
使用示例
Nodejs版本
const uuidv3 = require('uuid/v3');
const logger = console.log;
logger('uuid v3版本:%s', uuidv3('myString', uuidv3.DNS))
// 21fc48e5-63f0-3849-8b9d-838a012a5936复制代码
python版
import uuid
uuid.uuid3(uuid.NAMESPACE_DNS, "myString")
# UUID('21fc48e5-63f0-3849-8b9d-838a012a5936')复制代码
一个 比较不错的基于JavaScript的实现。
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}复制代码
使用示例
Nodejs版本
const uuidv4 = require('uuid/v4');
const logger = console.log;
logger('uuid v4版本:%s', uuidv4())复制代码
python版本:
import uuid
uuid.uuid4()# UUID('1a9e40e2-3862-41d4-bd4e-0dd928e81055')复制代码
Nodejs的UUID v4版源码分析
nodejs的uuid包中,v4版本实现比较简单,你们也能够去翻阅查看。我这里删减一部分代码,将主干留下来说解。
// randomBytes的官方定义:生成加密的强伪随机数据。size参数是一个数字,指示要生成的字节数。
// 这里生成16字节数强伪随机数,返回类型为buffer的数据。
var rng = require('crypto').randomBytes(16);
// 将byte生成uuid 的 string的工具函数
function bytesToUuid(buf) {}
// 主干代码
module.exports = function v4() {
var rnds = rng();
// 位运算符&:两个数值的个位分别相与,同时为1才得1,只要一个为0就为0。
// 位运算符|:两个位只要有一个为1,那么结果都为1。不然就为0
// 将UUID的M和N位进行处理,处理后M位为4,N为a,b,8,9内的任意值
rnds[6] = (rnds[6] & 0x0f) | 0x40;
rnds[8] = (rnds[8] & 0x3f) | 0x80;
return bytesToUuid(rnds);
}复制代码
SHA1和MD5的区别
在Nodejs的uuid的实现中,V5与V3实现惟一不一致的就是散列函数不一样。
// v3版本
crypto.createHash('md5').update(bytes).digest();
// v5版本
crypto.createHash('sha1').update(bytes).digest();复制代码
使用示例
Nodejs版本
const uuidv5 = require('uuid/v5');
const logger = console.log;
logger('uuid v5版本:%s', uuidv5('hello.example.com', uuidv5.DNS))
// uuid v5版本:fdda765f-fc57-5604-a269-52a7df8164ec复制代码
python版本
import uuid
uuid.uuid5(uuid.NAMESPACE_DNS, "hello.example.com")
#UUID('fdda765f-fc57-5604-a269-52a7df8164ec')复制代码
[1]
Nodejs的uuid:https://www.npmjs.com/package/uuid
[2]
维基百科:https://zh.wikipedia.org/wiki/通用标识码
如上内容均为本身总结,不免会有错误或者认识误差,若有问题,但愿你们留言指正,以避免误人,如有什么问题请留言,会尽力回答之。若是对你有帮助不要忘了分享给你的朋友或者点击右下方的“在看”哦!也能够关注做者,查看历史文章而且关注最新动态,助你早日成为一名全栈工程师!