Xung đột khi tạo UUID trong JavaScript?


94

Điều này liên quan đến câu hỏi này . Tôi đang sử dụng mã bên dưới từ câu trả lời này để tạo UUID trong JavaScript:

'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);
});

Giải pháp này dường như hoạt động tốt, nhưng tôi đang gặp phải những va chạm. Đây là những gì tôi có:

  • Một ứng dụng web chạy trong Google Chrome.
  • 16 người dùng.
  • khoảng 4000 UUID đã được tạo ra trong 2 tháng qua bởi những người dùng này.
  • Tôi nhận được khoảng 20 lần va chạm - ví dụ: UUID mới được tạo hôm nay giống với khoảng 2 tháng trước (người dùng khác).

Điều gì đang gây ra vấn đề này và làm cách nào để tránh nó?


2
Kết hợp một số ngẫu nhiên tốt với thời gian hiện tại (tính bằng mili giây). Tỷ lệ các số ngẫu nhiên va chạm vào cùng một thời điểm thực sự rất, thực sự, rất thấp.
jfriend00

7
@ jfriend00 nếu bạn cần làm điều đó thì nó không phải là "số ngẫu nhiên tốt", thậm chí không phải là số giả ngẫu nhiên tốt.
Attila O.

2
những gì hiện các (r&0x3|0x8)phần trung bình / thẩm định?
Kristian

Điều gì về việc thêm một Date.now (). ToString () vào nó?
Vitim.us

4
Có một vấn đề lớn trong kiến ​​trúc của bạn, không liên quan đến UUID - ứng dụng khách có thể cố tình tạo ID xung đột. Chỉ tạo ID bởi hệ thống mà bạn tin tưởng. Tuy nhiên, là một giải pháp thay thế, hãy thêm các ID do ứng dụng khách tạo trước với user_id, để ứng dụng khách bị lỗi / đối thủ chỉ có thể xung đột với chính họ (và xử lý điều đó ở phía máy chủ).
Dzmitry Lazerka

Câu trả lời:


35

Dự đoán tốt nhất của tôi là nó Math.random()bị hỏng trên hệ thống của bạn vì lý do nào đó (nghe có vẻ kỳ lạ). Đây là báo cáo đầu tiên tôi thấy về bất kỳ ai bị va chạm.

node-uuidcó một bộ khai thác thử nghiệm mà bạn có thể sử dụng để kiểm tra sự phân bố của các chữ số hex trong mã đó. Nếu điều đó có vẻ ổn thì không Math.random(), vì vậy hãy thử thay thế triển khai UUID bạn đang sử dụng vào uuid()phương thức ở đó và xem liệu bạn có còn nhận được kết quả tốt hay không.

[Cập nhật: Vừa xem báo cáo của Veselin về lỗi Math.random()khi khởi động. Vì vấn đề chỉ xảy ra khi khởi động, nên node-uuidbài kiểm tra khó có thể hữu ích. Tôi sẽ bình luận chi tiết hơn về liên kết devoluk.com.]


1
Cảm ơn, tôi đang sử dụng uuid.js, vì nó sử dụng tiền điện tử mạnh mẽ của trình duyệt nếu có. Sẽ xem nếu có bất kỳ va chạm.
Muxa,

bạn có thể cung cấp một liên kết đến mã uuid.js mà bạn đang đề cập đến không? (xin lỗi, không chắc bạn muốn nói gì.)
broofa

10
Không có va chạm nào cho đến nay :)
Muxa

Dù sao, nếu nó Chrome và chỉ khi khởi động, ứng dụng của bạn có thể tạo ra và loại bỏ một hàng, nói, guids mười sử dụng chức năng trên :)
Vinko Vrsalovic

Vấn đề là với entropy giới hạn mà bạn nhận được từ Math.random (). Đối với một số trình duyệt, entropy thấp chỉ bằng 41 bit cùng nhau. Gọi Math.random () nhiều lần sẽ không làm tăng entropy. Nếu bạn thực sự muốn các UUID v4 duy nhất, bạn cần sử dụng RNG mạnh về mặt mã hóa tạo ra ít nhất 122 bit entropy cho mỗi UUID được tạo.
mlehmk

36

Quả thực có những va chạm nhưng chỉ dưới Google Chrome. Kiểm tra kinh nghiệm của tôi về chủ đề này tại đây

http://devoluk.com/google-chrome-math-random-issue.html

(Liên kết bị hỏng kể từ năm 2019. Liên kết lưu trữ: https://web.archive.org/web/20190121220947/http://devoluk.com/google-chrome-math-random-issue.html .)

Có vẻ như va chạm chỉ xảy ra trong vài lần gọi đầu tiên của Math.random. Vì nếu bạn chỉ chạy phương thức createGUID / testGUIDs ở trên (rõ ràng là điều đầu tiên tôi đã thử), nó chỉ hoạt động mà không có bất kỳ va chạm nào.

Vì vậy, để thực hiện kiểm tra đầy đủ, người ta cần khởi động lại Google Chrome, tạo 32 byte, khởi động lại Chrome, tạo, khởi động lại, tạo ...


2
Điều đó khá đáng lo ngại - đã có ai đưa ra báo cáo lỗi chưa?
UpTheCreek

1
Đặc biệt thích các liên kết đến máy phát điện số ngẫu nhiên tốt hơn trong javascript: baagoe.com/en/RandomMusings/javascript
Leopd

thật đáng buồn, liên kết cho biết bây giờ đã bị hỏng :(
Gus


7
Bất kỳ ai có thể xác nhận nếu lỗi này đã được giải quyết?
Xdrone

20

Để những người khác có thể nhận thức được điều này - tôi đã gặp phải một số lượng lớn các va chạm rõ ràng đáng ngạc nhiên bằng cách sử dụng kỹ thuật tạo UUID được đề cập ở đây. Những va chạm này vẫn tiếp tục ngay cả sau khi tôi chuyển sang seedrandom cho trình tạo số ngẫu nhiên của mình. Bạn có thể tưởng tượng điều đó đã khiến tôi phải vò đầu bứt tóc.

Cuối cùng tôi đã phát hiện ra rằng vấn đề (hầu như?) Chỉ liên quan đến các chương trình thu thập thông tin web của Google. Ngay sau khi tôi bắt đầu bỏ qua các yêu cầu với "googlebot" trong trường tác nhân người dùng, các va chạm đã biến mất. Tôi đoán rằng họ phải lưu trữ các kết quả của các tập lệnh JS theo một cách bán thông minh nào đó, với kết quả cuối cùng là trình duyệt của họ không thể được tính vào để hoạt động theo cách mà các trình duyệt bình thường làm.

Chỉ là một FYI.


2
Gặp phải vấn đề tương tự với hệ thống đo lường của chúng tôi. Đã thấy hàng nghìn xung đột UUID bằng cách sử dụng mô-đun 'node-uuid' để tạo ID phiên trong trình duyệt. Hóa ra đó là googlebot. Cảm ơn!
domkck

4

Tôi muốn đăng điều này làm bình luận cho câu hỏi của bạn, nhưng có vẻ như StackOverflow không cho phép tôi.

Tôi vừa chạy thử nghiệm sơ bộ 100.000 lần lặp trong Chrome bằng thuật toán UUID mà bạn đã đăng và không có va chạm. Đây là một đoạn mã:

var createGUID = function() {
    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);
    });
}

var testGUIDs = function(upperlimit) {
    alert('Doing collision test on ' + upperlimit + ' GUID creations.');
    var i=0, guids=[];
    while (i++<upperlimit) {
        var guid=createGUID();
        if (guids.indexOf(guid)!=-1) {
            alert('Collision with ' + guid + ' after ' + i + ' iterations');
        }
        guids.push(guid);
    }
    alert(guids.length + ' iterations completed.');
}

testGUIDs(100000);

Bạn có chắc là không có chuyện gì khác xảy ra ở đây không?


4
Có, tôi cũng đã chạy một số thử nghiệm cục bộ và không có va chạm. Xung đột xảy ra giữa các UUID được tạo trên các máy của người dùng khác nhau. Tôi có thể cần tạo một số dữ liệu trên các máy khác nhau và kiểm tra các va chạm.
Muxa

2
Ngoài ra, tôi nhận thấy rằng xung đột giữa các UUID được tạo cách nhau 3-4 tuần.
Muxa

Rất kỳ quặc. Bạn đang chạy trên nền tảng nào?
user533676

1
Có vẻ như không có một lỗ hổng cơ bản nào trong Math.random () của V8, nhưng Chromium 11 đã thêm hỗ trợ tạo số ngẫu nhiên mạnh mẽ bằng cách sử dụng API window.crypto.getRandomValues ​​nếu bạn muốn thử nó. Xem blog.chromium.org/2011/06/… .
user533676

Chạy trên sự kết hợp của Windows 7 và Windows XP.
Muxa

3

Câu trả lời ban đầu đăng giải pháp UUID này đã được cập nhật vào ngày 26 tháng 6 năm 2017:

Một bài viết hay từ các nhà phát triển Chrome thảo luận về trạng thái của chất lượng Math.random PRNG trong Chrome, Firefox và Safari. tl; dr - Tính đến cuối năm 2015, nó "khá tốt", nhưng không phải là chất lượng mật mã. Để giải quyết vấn đề đó, đây là phiên bản cập nhật của giải pháp ở trên sử dụng ES6, cryptoAPI và một chút thuật sĩ JS mà tôi không thể ghi nhận :

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  )
}

console.log(uuidv4());


0

Các câu trả lời ở đây liên quan đến "điều gì gây ra sự cố?" (Vấn đề hạt giống Chrome Math.random) nhưng không phải "làm cách nào để tránh nó?".

Nếu bạn vẫn đang tìm cách tránh vấn đề này, tôi đã viết câu trả lời này một thời gian trước như một bản sửa đổi về chức năng của Broofa để giải quyết vấn đề chính xác này. Nó hoạt động bằng cách bù trừ 13 số hex đầu tiên bằng một phần hex của dấu thời gian, có nghĩa là ngay cả khi Math.random nằm trên cùng một hạt giống, nó vẫn sẽ tạo ra một UUID khác trừ khi được tạo ở cùng một mili giây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.