Безопасное целочисленное хеширование для номера заказа

Скажем у меня есть столик Orders с автоматически увеличивающимся идентификатором, например 1, 2, 3, 4 … и они в настоящее время запрашиваются как http://www.example.com/order?id={1,2,3} ..

Теперь я хочу хешировать первичный ключ [1, 2, 3, ..] в другой номер, называемый номером заказа, чтобы наш клиент мог ссылаться на них в своем запросе, например,

1 -> 100192938303
2 -> 293029200002

Я хочу следующее:

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

Является ли это возможным?

0

Решение

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

while (true) {
$id = get_random_integer();
$stmt = $db->prepare("INSERT INTO Orders (id, foo, bar) VALUES (:id, 'foo', 'bar')");
try {
$stmt->execute(array(':id' => $id));
//OK
break;
} catch (Exception $ex) {
if (is_duplicate_id_exception) {
//generate new id and try again
continue;
}
//Some other problem
throw $ex;
}
}

Таким образом, вы:

  • избегать столкновений
  • не требуется хеширование и отображение {hash -> id}
  • есть идентификаторы, которые не содержат информацию о количестве заказов
2

Другие решения

Вы предложили использовать соленый хеш. Поскольку хеш является односторонней функцией, и вам нужно будет преобразовать хеш в исходное значение, вам потребуется одно из следующих действий для перевода хеша в исходное значение заказа:

  • Перебирайте вероятные значения заказа, принимая соленый хеш каждого, пока вы не определите соответствующий хэш или не исчерпаете пул допустимых идентификаторов заказа.
  • Кэшируйте вероятные значения заказа один раз (например, при запуске приложения) и сохраняйте в хеш-таблице. Этот подход намного быстрее после создания кэша, но требует дополнительного поиска.

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

Я думаю, что предпочтительный подход в вашем примере будет использовать шифрование, а не хэш. Шифрование идентификатора заказа будет соответствовать требованиям конфиденциальности и двусторонней передачи без затрат на кэш хэшей или поиск в базе данных. Подход может выглядеть примерно так:

  1. Зашифруйте идентификатор заказа своим ключом.
  2. Base64 кодирует идентификатор заказа и возвращает клиенту в качестве токена.
  3. Получив зашифрованный токен от клиента, расшифруйте строку Base64
  4. Расшифруйте расшифрованную строку с помощью ключа, чтобы получить исходный номер заказа.

Например, для заказа 42 и ключа DES E0EC4E44EF2C6CEE и ноль IV, вы бы отправили dmTt0kbIlcA= клиенту в качестве идентификатора заказа (если вы кодируете 42 как 32-разрядное целое число с прямым порядком байтов). (Нулевой IV здесь уместен, поскольку наличие уникального зашифрованного текста не является проблемой в вашем сценарии.)

0

Вот две идеи:

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

Вдобавок ко всему, простой обратимый хеш может быть просто «боковым сложением» битов. Для чего-то более изощренного, вне головы, популярное семейство алгоритмов MurmurHash считается обратимым.

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

  1. Используйте потоковый шифр, АКА, криптографический ГСЧ. Это уместно, если общее количество заказов будет довольно маленьким. То, что вам нужно, это уникальная последовательность чисел, которая отображается один в один с последовательностью счетных чисел. Так что сгенерируйте последовательность уникальных случайных чисел, используя RC4 или HMAC по вашему выбору, удаляя дубликаты на ходу. (Может быть, творческий способ сделать это быстро — это фильтр Блума.)

Для сопоставления внутренних и внешних идентификаторов вы просто генерируете последовательность. И наоборот, вы продолжаете идти, пока не найдете идентификатор или не достигнете максимального идентификатора заказа. Это алгоритм O (n), который, очевидно, не идеален, но если вы хотите немного пойти на компромисс, добавить больше сложности или быть умным, вы можете найти способ смягчить это. Например, вы можете хранить кэш идентификаторов в оперативной памяти.

Отредактировано:

Я сам скептически отношусь к № 2 из-за линейной сложности, поэтому я пробежал несколько цифр. Используя контрольные числа Crypto ++ от процессора Core2, если вы выделяете 10 мс на преобразование чисел и используете 40-битные идентификаторы (что приводит к гипотетическому получению одного квадриллиона заказов), вы получаете максимальный идентификатор заказа около 250000000. И я думаю, что вы могли бы удвоить это, используя меньший ключ.

Так что этот метод может пойти в любую сторону. Для мелких вещей это нормально. (Приведенные выше предположения являются консервативными.) Но для крупномасштабных вещей это может раздражать. Этого достаточно, чтобы провести вас через запуск продукта; вы захотите вернуться к нему примерно в то время, когда вы начали говорить о том, как построить свое программное обеспечение как распределенную систему, что также поможет решить эту проблему. Но в этот момент вам, вероятно, лучше ставить под сомнение первоначальные предположения и просто хранить эту вещь в базе данных где-то.

0

Вы можете закодировать свой идентификатор заказа с помощью base64_encode (), прежде чем отправить его в форму GET, а затем base64_decode (), когда вы захватите переменные, отправленные формой.

Вы даже можете добавить соли, например, base64_encode ($ id. «salt»)

-2
По вопросам рекламы [email protected]