Некоторое время назад я работал над веб-приложением, где пользователи могли покупать билеты. Благодаря тому, как работали процессы нашего клиента, вы фактически получили в результате покупки URL-адрес с номером билета в нем.
Это были билеты на покупку недвижимости на Ближнем Востоке, и каждый билет потенциально стоил около 3 000 000 долларов. Очевидно, что выводить последовательные целые числа было бы плохой идеей. Мы использовали GUID, так как они в основном неосуществимы, но мой вопрос: достаточно ли они безопасны?
Насколько я понимаю, GUID, которые создает .NET, полностью псевдослучайны (за исключением нескольких неизменяемых битов). Однако я не знаю, какой алгоритм используется для их генерации.
Документация MSDN сообщает нам, что Random
быстр и небезопасен, а RNGCryptoServiceProvider
медленен и безопасен. То есть разумно предположить, что кто-то может приложить достаточно усилий, чтобы предсказать исход Random
, но не RNGCryptoServiceProvider
.
Если бы вы увидели достаточно длинную последовательность GUID, можно ли было бы прогнозировать фьючерсные? Если так, сколько вам нужно увидеть?
[В нашем конкретном случае позже были проведены проверки физической безопасности - вам нужно было предъявить паспорт, который вы использовали для покупки билета, - чтобы не было бы слишком плохо, если бы кто-то догадался о чём-то другом GUID, поэтому мы не потели в то время. Удобство использования GUID в качестве ключа базы данных сделало его полезным для использования типом данных.]
Edit:
Таким образом, ответ "недостаточно".
Используя приведенный ниже ответ 0xA3 и следуя ссылкам на вопрос , с которым он связан, следующий код сгенерирует криптографически случайный GUID, действительный для Раздел 4.4 RFC 4122 :
static Guid MakeCryptoGuid()
{
// Get 16 cryptographically random bytes
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] data = new byte[16];
rng.GetBytes(data);
// Mark it as a version 4 GUID
data[7] = (byte)((data[7] | (byte)0x40) & (byte)0x4f);
data[8] = (byte)((data[8] | (byte)0x80) & (byte)0xbf);
return new Guid(data);
}
Это создает GUID намного медленнее, чем Guid.NewGuid()
, но с 122 битами "очень случайных" данных они безопасно непредсказуемы.
Конечно, любой криптографически случайный текст был бы полезен для номера заявки, но GUID довольно удобны. : -)
Как и в случае с другими GUID версии 4, нет абсолютной гарантии уникальности, но шансы впечатляют. Если у вас одновременно меньше 326 915 130 309 695 865 (т. Е. sqrt (-2 * 2 ^ 122 * ln (0.99)) ) в игре, вы можете быть более чем на 99% уверены, что коллизий нет. Другими словами, если ваше приложение будет иметь ошибки переполнения повсюду, если у вас есть более чем int.MaxValue
практически всего, вы можете быть более чем на 99,99999999999999999% уверенными в отсутствии коллизий (то есть e ^ - ( ((2 ^ 31-1) ^ 2) / (2 * 2 ^ 122)) * * 1 048). Это примерно в тысячу раз увереннее, чем вы можете предположить, что метеорит не уничтожит большую часть жизни на Земле в течение одной секунды после запуска приложения (т. Е. один на 100 миллионов лет ).