JavaScript에서 UUID를 생성 할 때 충돌이 발생합니까?


94

이것은 이 질문 과 관련 있습니다. 이 답변의 아래 코드를 사용하여 JavaScript에서 UUID를 생성합니다.

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

이 솔루션은 잘 작동하는 것처럼 보였지만 충돌이 발생합니다. 내가 가진 것은 다음과 같습니다.

  • Google 크롬에서 실행되는 웹 앱.
  • 16 명의 사용자.
  • 이러한 사용자에 의해 지난 2 개월 동안 약 4000 개의 UUID가 생성되었습니다.
  • 약 20 건의 충돌이 발생했습니다. 예를 들어 오늘 생성 된 새 UUID가 약 2 개월 전과 동일했습니다 (다른 사용자).

이 문제의 원인은 무엇이며 어떻게 방지 할 수 있습니까?


2
좋은 난수를 현재 시간 (밀리 초)과 결합합니다. 난수가 정확히 동시에 충돌 할 확률은 정말, 정말, 정말 낮습니다.
jfriend00

7
@ jfriend00 필요한 경우 "좋은 난수"가 아니며 적절한 의사 난수도 아닙니다.
Attila O.

2
무엇이 수행 (r&0x3|0x8)에 부분 평균 / 평가를?
Kristian

Date.now (). toString ()을 추가하는 것은 어떻습니까?
Vitim.us

4
UUID와 관련이없는 아키텍처에 큰 문제가 있습니다. 클라이언트가 의도적으로 충돌 ID를 생성 할 수 있습니다. 신뢰하는 시스템에서만 ID를 생성하십시오. 그러나 해결 방법으로 클라이언트 생성 ID 앞에 user_id를 추가하여 적 / 오류있는 클라이언트가 자신과 만 충돌하고 서버 측에서이를 처리 할 수 ​​있도록합니다.
Dzmitry Lazerka

답변:


35

내 추측으로는 Math.random()어떤 이유로 시스템에서 고장났다 는 것 입니다 (그렇게 들리 겠지만 기이함). 이것은 내가 본 사람이 충돌을 겪는 첫 번째 보고서입니다.

node-uuid해당 코드에서 16 진수 분포를 테스트하는 데 사용할 수 있는 테스트 도구 가 있습니다. 괜찮아 보이면 그렇지 않은 Math.random()것이므로 사용중인 UUID 구현을 uuid()메서드에 대체하고 여전히 좋은 결과를 얻는 지 확인하십시오.

[업데이트 : 방금 시작할 때 버그에 대한 Veselin의 보고서를 보았습니다 Math.random(). 문제는 시작시에만 발생하므로 node-uuid테스트가 유용하지 않을 수 있습니다. devoluk.com 링크에서 더 자세히 설명하겠습니다.]


1
감사합니다. 가능한 경우 브라우저의 강력한 암호화를 사용하기 때문에 uuid.js를 사용하겠습니다. 충돌이 있는지 확인합니다.
Muxa

참조하는 uuid.js 코드에 대한 링크를 제공 할 수 있습니까? (미안하지 않도록 당신은 의미 LIB있다.)
broofa

10
있었다 충돌없이 지금까지 :)
Muxa

어쨌든, 시작할 때, 앱 생성 : 위의 함수를 사용하여 열 GUID를 말하자면, 행 버릴 수 그것의 크롬 경우에만
Vinko Vrsalovic

문제는 Math.random ()에서 얻은 제한된 엔트로피입니다. 일부 브라우저의 경우 엔트로피는 모두 합쳐서 41 비트만큼 낮습니다. Math.random ()을 여러 번 호출해도 엔트로피가 증가하지 않습니다. 고유 한 v4 UUID를 정말로 원한다면 생성 된 UUID 당 최소 122 비트 엔트로피를 생성하는 강력한 암호화 RNG를 사용해야합니다.
mlehmk 2015 년

36

실제로 충돌이 있지만 Google 크롬에서만 발생합니다. 여기에서 주제에 대한 내 경험을 확인하십시오.

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

(링크는 2019 년 기준으로 끊어졌습니다 . 아카이브 링크 : https://web.archive.org/web/20190121220947/http://devoluk.com/google-chrome-math-random-issue.html .)

충돌은 Math.random의 처음 몇 번의 호출에서만 발생하는 것 같습니다. 위의 createGUID / testGUIDs 메서드를 실행하면 (분명히 내가 시도한 첫 번째) 충돌이 전혀 발생하지 않습니다.

따라서 전체 테스트를 수행하려면 Chrome을 다시 시작하고, 32 바이트를 생성하고, Chrome을 다시 시작하고, 생성하고, 다시 시작하고, 생성해야합니다.


2
그것은 꽤 걱정 스럽습니다. 버그 보고서를 제기 한 사람이 있습니까?
UpTheCreek

1
특히 자바 스크립트에서 더 나은 난수 생성기에 대한 링크처럼 : baagoe.com/en/RandomMusings/javascript
Leopd

슬프게도, 링크는 지금 :( 깨진 말했다
거스


7
누구든지이 버그가 해결되었는지 확인할 수 있습니까?
Xdrone 2014

20

다른 사람들이이 사실을 알 수 있도록 여기에 언급 된 UUID 생성 기법을 사용하여 놀랍도록 많은 수의 명백한 충돌이 발생했습니다. 이러한 충돌은 난수 생성기 에서 seedrandom 으로 전환 한 후에도 계속되었습니다 . 당신이 상상할 수 있듯이 그로 인해 머리카락이 찢어졌습니다.

나는 결국 문제가 Google의 웹 크롤러 봇과 관련된 (거의?) 독점적이라는 것을 알게되었습니다. user-agent 필드에서 "googlebot"을 사용하여 요청을 무시하기 시작하자 충돌이 사라졌습니다. 나는 그들이 JS 스크립트의 결과를 반 지능적인 방식으로 캐시해야한다고 생각하는데, 최종 결과는 그들의 스파이더 링 브라우저가 일반 브라우저가하는 방식으로 작동한다고 믿을 수 없다는 것입니다.

그냥 참고로.


2
메트릭 시스템에서 동일한 문제가 발생했습니다. 브라우저에서 세션 ID를 생성하기 위해 'node-uuid'모듈을 사용하여 수천 건의 UUID 충돌이 발생했습니다. 모두 구글 봇 이었다는 것이 밝혀졌습니다. 감사!
domkck

4

나는 이것을 귀하의 질문에 대한 의견으로 게시하고 싶었지만 분명히 StackOverflow가 나를 허용하지 않을 것입니다.

방금 게시 한 UUID 알고리즘을 사용하여 Chrome에서 100,000 번의 반복 테스트를 실행했지만 충돌이 발생하지 않았습니다. 다음은 코드 스 니펫입니다.

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

여기서 다른 일이없는 게 확실합니까?


4
예, 일부 지역 테스트를 실행했는데 충돌이 없었습니다. 서로 다른 사용자의 컴퓨터에서 생성되는 UUID간에 충돌이 발생합니다. 다른 컴퓨터에서 일부 데이터를 생성하고 충돌을 확인해야 할 수도 있습니다.
Muxa

2
또한 3 ~ 4 주 간격으로 생성 된 UUID간에 충돌이 발생하는 것을 확인했습니다.
Muxa 2011 년

매우 이상합니다. 어떤 플랫폼에서 실행 중입니까?
user533676

1
V8의 Math.random ()에 너무 기본적인 결함이있을 것 같지는 않지만 Chromium 11은 대신 시도하려는 경우 window.crypto.getRandomValues ​​API를 사용하여 강력한 난수 생성에 대한 지원을 추가했습니다. blog.chromium.org/2011/06/… 참조 .
user533676

Windows 7 및 Windows XP 조합에서 실행됩니다.
Muxa

3

이 UUID 솔루션을 처음 게시 한 답변 은 2017-06-28에 업데이트되었습니다.

Chrome, Firefox 및 Safari의 Math.random PRNG 품질 상태에 대해 설명하는 Chrome 개발자좋은 기사입니다 . tl; dr-2015 년 말 현재 "아주 훌륭"하지만 암호화 품질은 아닙니다. 이 문제를 해결하기 위해 ES6, cryptoAPI 및 약간의 JS 마법사 를 사용하는 위 솔루션의 업데이트 된 버전이 있습니다 .

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

여기의 답변은 "문제의 원인이 무엇입니까?"를 다룹니다. (Chrome Math.random 시드 문제) "어떻게 피할 수 있습니까?"가 아닙니다.

이 문제를 피하는 방법을 여전히 찾고 있다면 이 정확한 문제를 해결하기 위해 Broofa의 기능을 수정하여 잠시이 답변을 작성 했습니다 . 타임 스탬프의 16 진수 부분으로 처음 13 개의 16 진수를 오프셋하여 작동합니다. 즉, Math.random이 동일한 시드에 있더라도 정확히 동일한 밀리 초에 생성되지 않는 한 다른 UUID를 생성합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.