Затенение идентификаторов базы данных - PullRequest
7 голосов
/ 03 марта 2010

У меня есть таблица с первичным ключом, который является автоинкрементом. Я хочу, чтобы изображение было связано с первичным ключом, но я не хочу, чтобы первичный ключ был раскрыт. Назвать изображения как-то так:

$filename = md5($primarykey + $secret_string) . '.jpg';

будет хорошим решением?

Я обеспокоен тем, что может произойти столкновение и файл будет перезаписан.

Другой вариант, конечно, заключается в том, чтобы сгенерировать случайную строку, проверить, что она не существует в виде файла и сохранить ее в базе данных ... но id предпочитает не хранить дополнительные данные, если они не нужны.

Другим вариантом является логическое преобразование в стиле youtube url, например, 1 = a 2 = b, но со случайным порядком, например, 1 = x 2 = m ... но тогда есть вероятность его декодирования ... плюс md5 вероятно, будет легче, чем любая функция URL-адреса YouTube.

Полагаю, я имею дело с более чем двумя миллионами записей, так каков вероятный коллизионный случай? Какой вариант вы бы выбрали или можете придумать лучший подход?

Ответы [ 10 ]

2 голосов
/ 03 марта 2010

Используйте линейный конгруэнтный генератор . Если вы правильно выберете значения, у вас будет псевдослучайная последовательность с очень большим периодом. Никаких коллизий, но учтите, что это просто метод запутывания, который не обеспечит никакой реальной безопасности (но я предполагаю, что это не то, что вы ищете).

2 голосов
/ 04 марта 2010

Я думаю, я имею дело с более чем два миллиона записей, так что же вероятный капот столкновения?

Согласно Википедии вам понадобится более 2 * 10 ^ 19 записей, чтобы получить 50% -ную вероятность иметь хотя бы одно столкновение, поэтому я бы сказал, что вам не о чем беспокоиться .

1 голос
/ 03 марта 2010

Код, который вы предоставили, хорошо подходит для этой работы. Вам не нужно беспокоиться о коллизиях, ни одно целое число, которое использует ваша база данных, не приведет к тому же хешу md5, что и любой другой.

Если вы хотите быть действительно уверен: вот небольшой тестовый скрипт;)

<?php
for($i = 0; $i < 1000000; ++$i) {
    $hash = md5($i);
    if(isset($x[$hash])) { die("COLLISION!"); }
    $x[$hash] = true;
}        }
echo "All is well";

Более сложное решение кажется пустой тратой вашего времени, но в случае, если вам нужны более короткие идентификаторы, вы можете назначить короткий случайный сгенерированный идентификатор каждому изображению (и проверить, действительно ли он использовался во время генерации, и сгенерировать другое, если это случай)

0 голосов
/ 04 марта 2010

Если вы можете добавить столбец, добавьте GUID в качестве столбца UNIQUE в таблице и используйте <GUID>.jpg в качестве имени ключа. Алгоритмы GUID не должны создавать дубликаты в обозримом будущем, но на всякий случай ограничение UNIQUE может это уловить.

0 голосов
/ 04 марта 2010

Алгоритм хеширования, такой как MD5, не является хорошим решением для этого, поскольку хеши по определению не гарантируют уникальность (они создают хэши с конечным числом значений).

То, что вы хотите, это шифрование. Взгляните на javax.crypto.Cipher.

0 голосов
/ 03 марта 2010

Я согласен с использованием Base64. Вы также можете использовать Guid. Или просто сохраните имя файла в таблице, что я и сделал.

Кроме того, позаботьтесь о том, чтобы избежать потерянных файлов

0 голосов
/ 03 марта 2010

Обычно для скрытия идентификаторов базы данных в URL-адресах вы фактически шифруете идентификатор, поскольку скрытие должно быть обратимым, чтобы сервер мог искать запись базы данных по скрытому идентификатору. Обратимость, возможно, не так важна для вашего случая сопоставления идентификаторов базы данных с именами файлов, но это простой шаблон, который также исключает возможность коллизий.

Вы хотите преобразовать зашифрованные данные в ASCII, используя base64 или шестнадцатеричное кодирование, например ::

base64_encode(encrypt(id, secret_key))

И расшифровка:

decrypt(base64_decode(id), secret_key)

(выше псевдокод, вам нужно найти соответствующие функции в PHP)

Вам не нужно ничего особенного для шифрования. Достаточно простого блочного шифра, такого как DES.

0 голосов
/ 03 марта 2010

На самом деле у вас есть два варианта:

  • Создание чего-либо и проверка отсутствия столкновений
  • Создай что-нибудь и надейся на отсутствие столкновений

Обычно вы можете использовать следующие опции: - хеш - случайно сгенерированная строка - UUID

Hash Если вы выбираете хеш, выбирайте что-то с низкой частотой столкновений. Кроме того, при выполнении хэша учитывайте, почему вы хотите скрыть идентификаторы БД. Кто-то не займет много времени, чтобы выяснить ваши хэши, если вы хэшируете простые числа, вам абсолютно необходимо засолить их. Преимущества соленого хэша - быстрая генерация и низкая вероятность коллизий (в небольших случаях абсолютно нет необходимости проверять их, поэтому более быстрые вставки). Недостатком является то, что любая правильная реализация будет SHA256 или лучше, что означает, что это долго. Вы можете сделать несколько шестнадцатеричных преобразований, если хотите сэкономить пространство DB / Index, которое может быть больше, чем вы хотите.

Случайная строка Это вы можете генерировать для любой длины, которая подходит вам, любого набора символов или чисел a-Z0-9. Это также означает «больше» данных в более короткой строке, которая используется в URI, данных REQUEST и т. Д. Недостатком является то, что вы должны проверить, находится ли он в базе данных.

UUID Подобно хешу, быстро генерируемому, довольно низкому риску коллизий и может быть изменен, чтобы быть «менее» уродливым, чем чистый результат.

Мое предложение Не делай этого. Я имел дело с этим раньше на очень большой реализации, которая выросла из очень маленькой реализации. В конце концов вы начинаете делать «умные» вещи, такие как создание совершенно уникальных идентификаторов (например, тип контента + ваш идентификатор) и начинаете видеть какое-то значение в нем, но затем вам приходится иметь дело с масштабом. Масштабировать это очень сложно. БД оптимизированы для идентификаторов в качестве первичных ключей, поэтому нужно удивительно много думать о них, если вы хотите, чтобы они масштабировались по вертикали. Если необходимо, используйте его только для взаимодействия с внешним клиентом.

0 голосов
/ 03 марта 2010

Если вы хотите использовать идентификатор, но не хотите раскрывать идентификатор и хотите низкий риск коллизий; Одним из вариантов будет использование хеша идентификатора. Хеш будет согласованным, необратимым и (за исключением огромных наборов данных - 2 32 иш в зависимости от используемого хеша) уникальным для каждой фотографии. Похоже, у вас есть основная идея этого вопроса:

$filename = md5($primarykey + $secret_string) . '.jpg';

Вы заменяете MD5 лучшим алгоритмом хеширования по вашему выбору. Желательно что-то с большим выходом. Основываясь на просмотре различных статей в ответ на комментарии, может показаться, что SHA512 или что-то подобное подойдет лучше.

0 голосов
/ 03 марта 2010

Просто используйте хэш первичного ключа. Вероятность столкновения очень мала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...