development

UUID는 얼마나 독특합니까?

big-blog 2020. 2. 22. 11:42
반응형

UUID는 얼마나 독특합니까?


UUID를 사용하여 무언가를 고유하게 식별하는 것이 얼마나 안전합니까 (서버에 업로드 된 파일에 사용하고 있습니까)? 내가 이해하는 것처럼 난수를 기반으로합니다. 그러나 충분한 시간이 주어지면 결국 순수한 기회로 스스로 반복 할 것 같습니다. 이 문제를 완화하기 위해 더 나은 시스템이나 어떤 유형의 패턴이 있습니까?


매우 안전:

주어진 사람이 운석에 맞을 때의 연간 위험은 170 억으로 1 번의 확률로 추정되는데, 이는 확률이 약 0.00000000006 (6 × 10-11 )이며 이는 수십억 조의 UUID를 생성 할 확률과 같습니다. 1 년 안에 하나의 사본을 가지고 있습니다. 다시 말해, 향후 100 년 동안 초당 10 억 개의 UUID를 생성 한 후에 만 ​​하나의 복제본을 생성 할 확률은 약 50 %입니다.

경고:

그러나 이러한 확률은 충분한 엔트로피를 사용하여 UUID가 생성 된 경우에만 유지됩니다. 그렇지 않으면 통계 분산이 더 낮을 수 있으므로 복제 확률이 크게 높아질 수 있습니다. 분산 된 응용 프로그램에 고유 식별자가 필요한 경우 많은 장치의 데이터를 병합하더라도 UUID가 충돌하지 않도록 모든 장치에 사용되는 시드 및 생성기의 임의성은 응용 프로그램 수명 동안 안정적이어야합니다. 이것이 가능하지 않은 경우 RFC4122는 네임 스페이스 변형을 대신 사용할 것을 권장합니다.

출처 : 보편적으로 고유 한 식별자에 대한 Wikipedia 기사 무작위 UUID 복제 가능성 섹션 (링크로 인해 섹션이 수정되기 전 2016 년 12 월부터 수정 됨)

또한 동일하게 고유 한 고유 식별자 기사 인 Collisions 의 동일한 주제에 대한 현재 섹션을 참조하십시오 .


"충분한 시간을 준다"는 말은 100 년을 의미하며 초당 10 억의 비율로 생성한다면 100 년 후에 50 %의 확률로 충돌 할 가능성이 있습니다.


두 가지 유형의 UUID가 있으므로 "안전"은 사용중인 유형 (UUID 사양에서 "버전"이라고 함)에 따라 다릅니다.

  • 버전 1은 시간 기반 MAC 주소 UUID입니다. 128 비트에는 네트워크 카드의 MAC 주소 (제조업체에서 고유하게 지정)에 대한 48 비트와 100 나노초의 해상도를 가진 60 비트 클록이 포함됩니다. 이 시계 는 3603 AD로 포장 되므로 이러한 UUID는 적어도 그때까지 안전합니다 (초당 1000 만 개 이상의 새로운 UUID가 필요하거나 누군가가 네트워크 카드를 복제하지 않는 한). 나는 시계가 1582 년 10 월 15 일에 시작하기 때문에 "적어도"라고 말한다. 그래서 당신은 작은 복제의 가능성이 있기 전에 당신이 시계가 감겨 진 후 약 400 년을 보낸다.

  • 버전 4는 난수 UUID입니다. 6 개의 고정 비트가 있으며 나머지 UUID는 122 비트의 임의성입니다. 복제 가능성이 매우 적은 위키 백과 또는 기타 분석을 참조하십시오 .

  • 버전 3은 MD5를 사용하고 버전 5는 임의 또는 의사 난수 생성기 대신 SHA-1을 사용하여 122 비트를 만듭니다. 따라서 안전성 측면에서 버전 4는 통계 문제인 것과 같습니다 (다이제스트 알고리즘이 처리하는 항목이 항상 고유한지 확인하는 한).

  • 버전 2는 버전 1과 유사하지만 시계가 더 작으므로 훨씬 빨리 랩핑됩니다. 그러나 버전 2 UUID는 DCE 용이므로이를 사용하지 않아야합니다.

따라서 모든 실제 문제에 대해 안전합니다. 확률에 도달하는 것이 불편한 경우 (예를 들어, 당신의 지구에서 큰 소행성에 의해 지구가 파괴되는 것에 대해 걱정하는 사람의 유형 인 경우), 버전 1 UUID를 사용하고 고유해야합니다 ( 당신이 3603 AD를 지나서 살 계획이 없다면, 당신의 일생 동안.

그렇다면 왜 모두가 단순히 버전 1 UUID를 사용하지 않습니까? 버전 1 UUID는 생성 된 머신의 MAC 주소를 공개하고 예측할 수 있기 때문입니다. 두 가지 UUID를 사용하는 애플리케이션에 보안에 영향을 줄 수 있습니다.


이에 대한 대답은 UUID 버전에 크게 좌우 될 수 있습니다.

많은 UUID 생성기는 버전 4 임의의 숫자를 사용합니다. 그러나 이들 중 다수는 Pseudo 난수 생성기를 사용하여 생성합니다.

UUID를 생성하는 데 약간의 기간이 지난 시드 PRNG를 잘못 사용하면 전혀 안전하지 않다고 말할 수 있습니다.

따라서 알고리즘을 생성하는 데 사용 된 알고리즘만큼 안전합니다.

반대로,이 질문에 대한 답을 알고 있다면 버전 4 uuid가 사용하기에 안전해야한다고 생각합니다. 사실 나는 네트워크 블록 파일 시스템에서 블록을 식별하기 위해 그것을 사용하고 있으며 지금까지 충돌이 없었습니다.

필자의 경우, 사용중인 PRNG는 메르 센 트위스터이며 / dev / urandom을 포함한 여러 소스에서 나온 씨앗이 뿌리 내리는 방식에주의를 기울이고 있습니다. Mersenne twister의주기는 2 ^ 19937-1입니다. 반복되는 UUID를보기까지는 매우 오랜 시간이 걸릴 것입니다.


Wikipedia 에서 인용 :

따라서 누구나 UUID를 생성하고이를 사용하여 다른 사람이 의도하지 않게 식별자를 사용하지 않을 것이라는 확실한 확신을 가지고 무언가를 식별 할 수 있습니다.

실제로 실제로 얼마나 안전한지에 대해 아주 자세하게 설명합니다. 따라서 귀하의 질문에 대답하십시오 : 예, 충분히 안전합니다.


UUID 체계는 일반적으로 의사 난수 요소뿐만 아니라 현재 시스템 시간과 네트워크 MAC 주소와 같은 사용 가능한 경우 종종 고유 한 하드웨어 ID를 사용합니다.

UUID를 사용하는 요점은 자신이 할 수있는 것보다 고유 한 ID를 제공하는 더 나은 작업을 수행 할 수 있다는 점입니다. 이것은 자신의 롤링보다는 타사 암호화 라이브러리를 사용하는 것과 동일한 근거입니다. 스스로하는 것이 더 재미있을 수도 있지만, 그렇게하는 것은 일반적으로 덜 책임이 있습니다.


몇 년 동안 해왔습니다. 문제가 발생하지 마십시오.

나는 보통 모든 키와 수정 된 날짜 등을 포함하는 하나의 테이블을 갖도록 DB를 설정했습니다. 중복 키 문제가 발생하지 않았습니다.

유일한 단점은 일부 정보를 빨리 찾기 위해 쿼리를 작성할 때 키를 많이 복사하고 붙여 넣는 것입니다. 더 이상 ID를 기억하기가 쉽지 않습니다.


다음은 고유성을 테스트하기위한 테스트 스 니펫입니다. @ scalabl3 님의 댓글에서 영감을 받음

재밌는 것은, 물론, 우연히 일치하는 우연의 일치, 운 및 신의 개입 수준에서 동일한 2 행을 생성 할 수 있지만, 헤아릴 수없는 확률에도 불구하고 여전히 가능합니다! : D 그렇습니다. 복제본을 만들 때의 순간에 대한 생각의 즐거움을 위해 말하십시오! 스크린 샷 비디오! – scalabl3 10 월 20 일 15:19:11

운이 좋으면 확인란을 선택하면 현재 생성 된 ID 만 확인합니다. 히스토리 점검을 원하면 선택하지 않은 상태로 두십시오. 체크되지 않은 상태로두면 어느 시점에서 램이 소진 될 수 있습니다. CPU를 친숙하게 만들어서 필요할 때 빠르게 중단 할 수 있습니다. 스 니펫 실행 버튼을 다시 누르거나 페이지를 나가십시오.

Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
  Math.trueRandom = (function() {
  var crypt = window.crypto || window.msCrypto;

  if (crypt && crypt.getRandomValues) {
      // if we have a crypto library, use it
      var random = function(min, max) {
          var rval = 0;
          var range = max - min;
          if (range < 2) {
              return min;
          }

          var bits_needed = Math.ceil(Math.log2(range));
          if (bits_needed > 53) {
            throw new Exception("We cannot generate numbers larger than 53 bits.");
          }
          var bytes_needed = Math.ceil(bits_needed / 8);
          var mask = Math.pow(2, bits_needed) - 1;
          // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111

          // Create byte array and fill with N random numbers
          var byteArray = new Uint8Array(bytes_needed);
          crypt.getRandomValues(byteArray);

          var p = (bytes_needed - 1) * 8;
          for(var i = 0; i < bytes_needed; i++ ) {
              rval += byteArray[i] * Math.pow(2, p);
              p -= 8;
          }

          // Use & to apply the mask and reduce the number of recursive lookups
          rval = rval & mask;

          if (rval >= range) {
              // Integer out of acceptable range
              return random(min, max);
          }
          // Return an integer that falls within the range
          return min + rval;
      }
      return function() {
          var r = random(0, 1000000000) / 1000000000;
          return r;
      };
  } else {
      // From http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <baagoe@baagoe.com>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

Math.guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
      var r = Math.trueRandom() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};
function logit(item1, item2) {
    console.log("Do "+item1+" and "+item2+" equal? "+(item1 == item2 ? "OMG! take a screenshot and you'll be epic on the world of cryptography, buy a lottery ticket now!":"No they do not. shame. no fame")+ ", runs: "+window.numberofRuns);
}
numberofRuns = 0;
function test() {
   window.numberofRuns++;
   var x = Math.guid();
   var y = Math.guid();
   var test = x == y || historyTest(x,y);

   logit(x,y);
   return test;

}
historyArr = [];
historyCount = 0;
function historyTest(item1, item2) {
    if(window.luckyDog) {
       return false;
    }
    for(var i = historyCount; i > -1; i--) {
        logit(item1,window.historyArr[i]);
        if(item1 == history[i]) {
            
            return true;
        }
        logit(item2,window.historyArr[i]);
        if(item2 == history[i]) {
            
            return true;
        }

    }
    window.historyArr.push(item1);
    window.historyArr.push(item2);
    window.historyCount+=2;
    return false;
}
luckyDog = false;
document.body.onload = function() {
document.getElementById('runit').onclick  = function() {
window.luckyDog = document.getElementById('lucky').checked;
var val = document.getElementById('input').value
if(val.trim() == '0') {
    var intervaltimer = window.setInterval(function() {
         var test = window.test();
         if(test) {
            window.clearInterval(intervaltimer);
         }
    },0);
}
else {
   var num = parseInt(val);
   if(num > 0) {
        var intervaltimer = window.setInterval(function() {
         var test = window.test();
         num--;
         if(num < 0 || test) {
    
         window.clearInterval(intervaltimer);
         }
    },0);
   }
}
};
};
Please input how often the calulation should run. set to 0 for forever. Check the checkbox if you feel lucky.<BR/>
<input type="text" value="0" id="input"><input type="checkbox" id="lucky"><button id="runit">Run</button><BR/>


나는 다른 답변과 동의합니다. UUID는 거의 모든 실제적인 목적 1 , 그리고 확실히 당신의 목적을 위해 충분히 안전 합니다.

그러나 (가설 적으로) 그렇지 않다고 가정하십시오.

이 문제를 완화하기 위해 더 나은 시스템이나 어떤 유형의 패턴이 있습니까?

다음은 몇 가지 접근 방식입니다.

  1. 더 큰 UUID를 사용하십시오. 예를 들어, 대신 128 난수 비트의 사용 256 또는 512 또는 ... 당신은 유형 4 스타일에 추가하는 각 비트 UUID는 엔트로피의 신뢰할 수있는 원본이 있다고 가정, 반에 의해 충돌의 가능성을 줄일 수 2 .

  2. UUID를 생성하고 발행 한 각각의 UUID를 기록하는 중앙 집중식 또는 분산 서비스를 구축하십시오. 새로운 것을 생성 할 때마다 UUID가 이전에 발행 된 적이 없는지 확인합니다. 그러한 서비스는 서비스를 운영하는 사람들이 절대적으로 신뢰할 수 있고 부패 할 수 없다고 가정하면 기술적으로 간단합니다 (제 생각에). 불행히도, 특히 정부가 간섭 할 가능성이있는 경우에는 그렇지 않습니다. 그래서,이 방법은 아마 비현실적이며, 할 수있다 3 현실 세계에서 불가능합니다.


1-UUID의 독창성이 자국의 수도에서 핵 미사일을 발사했는지 여부를 결정하면 많은 동료 시민들은 "확률이 매우 낮다"고 확신하지 못할 것입니다. 따라서 나의 "거의 거의"자격.

2-여기 철학적 질문이 있습니다. 진정으로 임의의 것이 있습니까? 그렇지 않은 경우 어떻게 알 수 있습니까? 우리가 알고있는 우주는 시뮬레이션입니까? 물리 법칙을 수정하여 결과를 바꿀 수있는 하나님이 있습니까?

3-이 문제에 대한 연구 논문을 아는 사람이 있으면 의견을 말하십시오.


이것이 당신에게 중요한지 모르겠지만 GUID는 전 세계적으로 고유하지만 GUID의 하위 문자열은 그렇지 않습니다 .

참고 URL : https://stackoverflow.com/questions/1155008/how-unique-is-uuid



반응형