上一篇從身份證號是如何生成,來認識了中心機構下生成惟一標識的方法,這一篇來看看面對龐大的計算機世界,無中心機構時,那又如何生成惟一標識呢?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/通用標識碼
如上內容均爲本身總結,不免會有錯誤或者認識誤差,若有問題,但願你們留言指正,以避免誤人,如有什麼問題請留言,會盡力回答之。若是對你有幫助不要忘了分享給你的朋友或者點擊右下方的「在看」哦!也能夠關注做者,查看歷史文章而且關注最新動態,助你早日成爲一名全棧工程師!