Скажем у меня есть столик Orders
с автоматически увеличивающимся идентификатором, например 1, 2, 3, 4 … и они в настоящее время запрашиваются как http://www.example.com/order?id={1,2,3} ..
Теперь я хочу хешировать первичный ключ [1, 2, 3, ..] в другой номер, называемый номером заказа, чтобы наш клиент мог ссылаться на них в своем запросе, например,
1 -> 100192938303
2 -> 293029200002
Я хочу следующее:
Является ли это возможным?
Я думаю, что вы, вероятно, можете выбрать более простой подход — не используйте автоматическое увеличение идентификатора, используйте случайные целые числа в качестве идентификаторов. Пример:
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;
}
}
Таким образом, вы:
Вы предложили использовать соленый хеш. Поскольку хеш является односторонней функцией, и вам нужно будет преобразовать хеш в исходное значение, вам потребуется одно из следующих действий для перевода хеша в исходное значение заказа:
Вы также отметили, что исходный идентификатор заказа является конфиденциальным, поскольку злоумышленник, который может получить несколько идентификаторов заказа, может определить объем заказа. Конфиденциальность идентификатора заказа — это отдельная проблема, связанная с конфиденциальностью самого заказа, который не рассматривается в данном вопросе и может решаться с помощью отдельного механизма контроля доступа.
Я думаю, что предпочтительный подход в вашем примере будет использовать шифрование, а не хэш. Шифрование идентификатора заказа будет соответствовать требованиям конфиденциальности и двусторонней передачи без затрат на кэш хэшей или поиск в базе данных. Подход может выглядеть примерно так:
Например, для заказа 42 и ключа DES E0EC4E44EF2C6CEE
и ноль IV, вы бы отправили dmTt0kbIlcA=
клиенту в качестве идентификатора заказа (если вы кодируете 42 как 32-разрядное целое число с прямым порядком байтов). (Нулевой IV здесь уместен, поскольку наличие уникального зашифрованного текста не является проблемой в вашем сценарии.)
Вот две идеи:
Вдобавок ко всему, простой обратимый хеш может быть просто «боковым сложением» битов. Для чего-то более изощренного, вне головы, популярное семейство алгоритмов MurmurHash считается обратимым.
Я не знаю ни о каких криптографически сильных обратимых хешах. Однако другие ответы на тему симметричного шифрования похожи на эту идею.
Для сопоставления внутренних и внешних идентификаторов вы просто генерируете последовательность. И наоборот, вы продолжаете идти, пока не найдете идентификатор или не достигнете максимального идентификатора заказа. Это алгоритм O (n), который, очевидно, не идеален, но если вы хотите немного пойти на компромисс, добавить больше сложности или быть умным, вы можете найти способ смягчить это. Например, вы можете хранить кэш идентификаторов в оперативной памяти.
Отредактировано:
Я сам скептически отношусь к № 2 из-за линейной сложности, поэтому я пробежал несколько цифр. Используя контрольные числа Crypto ++ от процессора Core2, если вы выделяете 10 мс на преобразование чисел и используете 40-битные идентификаторы (что приводит к гипотетическому получению одного квадриллиона заказов), вы получаете максимальный идентификатор заказа около 250000000. И я думаю, что вы могли бы удвоить это, используя меньший ключ.
Так что этот метод может пойти в любую сторону. Для мелких вещей это нормально. (Приведенные выше предположения являются консервативными.) Но для крупномасштабных вещей это может раздражать. Этого достаточно, чтобы провести вас через запуск продукта; вы захотите вернуться к нему примерно в то время, когда вы начали говорить о том, как построить свое программное обеспечение как распределенную систему, что также поможет решить эту проблему. Но в этот момент вам, вероятно, лучше ставить под сомнение первоначальные предположения и просто хранить эту вещь в базе данных где-то.
Вы можете закодировать свой идентификатор заказа с помощью base64_encode (), прежде чем отправить его в форму GET, а затем base64_decode (), когда вы захватите переменные, отправленные формой.
Вы даже можете добавить соли, например, base64_encode ($ id. «salt»)