1-1 сопоставление для обфускации id

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

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

  • Необходимо выделить дополнительное поле базы данных. Я знаю, что я мог бы использовать GUID в качестве моего основного ключа, но мой auto-increment integer PK является правильным для большинства целей, и я не хочу его изменять.

  • Необходимо подумать о возможности коллизий hash/GUID. Я полностью согласен со всеми аргументами о столкновениях с GUID как вероятное самопроизвольное сжигание или что-то в этом роде, но, не обращая внимания на исключительные случаи, потому что они исключительны, противоречит всему, чему меня учили, и это продолжает беспокоить меня, даже когда я знаю Мне нужно больше беспокоиться о других вещах.

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

Мне интересны 1-1 сопоставления диапазона id, растяжимые или сжимаемые, так что, например, 16-разрядные идентификаторы сопоставляются с 16-разрядными идентификаторами, 32-разрядными идентификаторами, сопоставленными 32-разрядными идентификаторами и т.д., и это остановит кто-то пытался угадать общее количество выделенных идентификаторов или скорость распределения идентификаторов за период.

Например, если мои идентификаторы пользователя являются 16-битными целыми числами (0..65535), то примером преобразования, которое несколько запутывает выделение идентификатора, является функция f (x) = (x mult 1001) mod 65536. внутренняя идентификационная последовательность 1, 2, 3 становится общедоступной идентификационной последовательностью 1001, 2002, 3003. С дополнительным уровнем обфускации от базового преобразования, например до основания 36, последовательность становится "rt", "1jm", "2bf" ". Когда система получает запрос к URL-адресу? Userid = 2bf, он преобразуется из базы 36 для получения 3003 и применяет обратное преобразование g (x) = (x mult 1113) mod 65536, чтобы вернуться к внутреннему id = 3.

Такую схему достаточно, чтобы остановить случайное наблюдение случайных пользователей, но она легко разрешима кем-то, кто достаточно заинтересован, чтобы попытаться ее разгадать. Может ли кто-нибудь предложить что-то более сильное, но легко реализуемое в PHP без специальных библиотек? Это приближается к собственной схеме шифрования, так что, возможно, существует правильный алгоритм шифрования, который широко доступен и имеет свойство растяжимости, упомянутое выше?

РЕДАКТИРОВАТЬ: немного отступив, несколько обсуждений на codinghorror о выборе из трех видов ключей - суррогатных (ориентированных), суррогатное (целочисленное), естественное. В этих терминах я пытаюсь скрыть целостный суррогатный ключ от пользователей, но я ищу что-то сжатое, что делает не слишком длинными URL-адреса, которые я не знаю, как сделать со стандартным 128-битным GUID, Иногда, как предлагает нижеприведенная принцесса, проблема может быть устранена естественным ключом.

ИЗМЕНИТЬ 2/РЕЗЮМЕ:

  • Учитывая ограничения на вопрос, который я задал (растяжимость, обратимость, легкость реализации), наиболее подходящим решением до сих пор является обфускация на основе XOR, предложенная кем-то и Бретоном.
  • Было бы безответственно, если бы я предположил, что я могу добиться чего-то большего, чем запутывание/безопасность от неясности. Знание того, что это целая последовательность, вероятно, является кроваткой, которую мог бы использовать любой компетентный злоумышленник.
  • Я еще немного подумал над идеей дополнительного поля базы данных. Одним из преимуществ дополнительного поля является то, что он делает его более простым для будущих программистов, которые пытаются ознакомиться с системой, просматривая базу данных. В противном случае им придется прорыть исходный код (или документацию, г-н), чтобы выяснить, как запрос на заданный URL-адрес разрешен для данной записи в базе данных.
  • Если я разрешаю дополнительное поле базы данных, то некоторые из других предположений в вопросе становятся несущественными (например, преобразование не должно быть обратимым). Это становится другим вопросом, поэтому я оставлю его там. Спасибо всем за то, что поделились своими знаниями.

Ответ 1

Я нахожу, что простое шифрование XOR лучше всего подходит для обфускации URL. Вы можете продолжать использовать любой серийный номер, который вы используете без изменений. Дальнейшее шифрование XOR не увеличивает длину исходной строки. Если ваш текст равен 22 байтам, зашифрованная строка также будет содержать 22 байта. Это не так просто, как угадать как гниль 13, но не тяжелый вес, как DSE/RSA.

Найдите сеть для шифрования PHP XOR, чтобы найти некоторую реализацию. Первый, который я нашел, здесь.

Ответ 2

Я играл с такими вещами сам, своим дилетантским способом, и пришел к своего рода коварному алгоритму скремблирования чисел, включающему смешанные радиусы. В основном у меня есть функция, которая отображает число между 0-N и другим числом в диапазоне 0-N. Для URLS я затем сопоставляю это число с несколькими английскими словами. (слова легче запомнить).

Упрощенная версия того, что я делаю, без смешанных радиусов: у вас есть число, равное 32 битам, поэтому заблаговременно имеет ключ доступа длиной 32 бита и XOR ключ доступа с вашим номером ввода. Затем перетасовывайте биты в определенном переупорядочении. (возможно, на основе вашего ключа доступа).

Самое приятное в этом -

  • Никаких столкновений, пока вы перетасовываете и xor одинаково каждый раз
  • Не нужно хранить обфусканные ключи в базе данных
  • По-прежнему используйте свои упорядоченные IDS внутри, так как вы можете отменить обфускацию
  • Вы можете повторить операцию несколько раз, чтобы получить более обфускационные результаты.

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

Ответ 3

Вам может показаться полезным вернуться к идее использования GUID, потому что вы можете создавать GUID таким образом, чтобы не подвергать столкновению.

Просмотрите страницу Википедии по GUID - алгоритм "Тип 1" использует как MAC-адрес ПК, так и текущую дату/время в качестве входов. Это гарантирует, что столкновения просто невозможны.

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

Ответ 4

Я вчера увидел этот вопрос: как reddit генерирует идентификатор alphanum id

Я думаю, что это достаточно хороший метод (и особенно умный)

он использует Python

def to_base(q, alphabet):
    if q < 0: raise ValueError, "must supply a positive integer"
    l = len(alphabet)
    converted = []
    while q != 0:
        q, r = divmod(q, l)
        converted.insert(0, alphabet[r])
    return "".join(converted) or '0'

def to36(q):
    return to_base(q, '0123456789abcdefghijklmnopqrstuvwxyz')

Ответ 5

Добавьте поле char (10) в таблицу заказов... назовите его "order_number".

После создания нового порядка произвольно генерируйте целое число от 1... 9999999999. Проверьте, существует ли он в базе данных под "order_number". Если нет, обновите последнюю строку с этим значением. Если он существует, выберите другое число наугад.

Используйте 'order_number' для общедоступных URL-адресов, возможно, всегда заполненных нулями.

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

Вырезано из здесь.

ОБНОВЛЕНО Как и при использовании GUID aproach, описанного Bevan, если столбец ограничен как уникальный, то вам не нужно его потеть. Я предполагаю, что это ничем не отличается от использования GUID, за исключением того, что заказчику и службе обслуживания клиентов будет легче рассказать о заказе.

Ответ 6

Я нашел гораздо более простой способ. Скажем, вы хотите нанести N цифр, псевдослучайно на N цифр. вы находите следующее старшее число из N, и вы делаете свою функцию

prandmap(x) return x * nextPrime(N) % N

это приведет к выполнению функции, которая повторяется (или имеет период) каждый N, число не генерируется дважды, пока x = N + 1. Он всегда начинается с 0, но после этого псевдослучайно.

Ответ 7

Я честно говорю, что шифрование/расшифровка данных строки запроса - плохой подход к этой проблеме. Самое простое решение - отправлять данные с помощью POST вместо GET. Если пользователи нажимают на ссылки с данными запроса, вам нужно прибегнуть к некоторым javascript hacks для отправки данных POST (сохраняйте доступность для пользователей с выключенным Javascript). Это не мешает пользователям просматривать исходный код, но, по крайней мере, он не чувствителен к индексированию поисковыми системами, предполагая, что данные, которые вы пытаетесь скрыть, действительно чувствительны в первую очередь.

Другой подход - использовать натуральный уникальный ключ. Например, если вы ежемесячно выставляете счета клиентам, тогда "yyyyMM [customerID]" однозначно идентифицирует конкретный счет-фактуру для конкретного пользователя.

Ответ 8

Из вашего описания, лично, я бы начал работать с любой стандартной библиотекой шифрования (я программист на Java, но я предполагаю, что для PHP должна быть доступна базовая библиотека шифрования AES):

  • в базе данных, просто ключевые вещи, как обычно,
  • всякий раз, когда вам нужно передать ключ клиенту, используйте довольно прочную стандартную систему шифрования (например, AES) для преобразования ключа в/из строки мусора. В качестве обычного текста используйте 128-байтовый буфер (скажем), содержащий: 4 байтовый ключ, 60 случайных байтов, а затем 64-байтовый хэш среднего качества из предыдущих 64 байтов (см. Численные рецепты для пример) - очевидно, когда вы получаете такую ​​строку, вы расшифровываете ее, а затем проверяете, соответствует ли хеш, прежде чем попасть в БД. Если вы немного параноик, отправьте AES-зашифрованный буфер случайных байтов с вашим ключом в произвольной позиции, а также безопасный хэш этого буфера в качестве отдельного параметра. Первый вариант, вероятно, является разумным компромиссом между производительностью и безопасностью для ваших целей, однако, особенно в сочетании с другими мерами безопасности.
  • В тот день, когда вы обрабатываете так много счетов-фактур, что AES, шифровав их в пути, слишком дорого стоит, выходите и покупайте себе большой толстый сервер с большим количеством процессоров, чтобы отпраздновать.

Кроме того, если вы хотите скрыть, что переменная является идентификатором счета, вы можете назвать ее чем-то иным, чем "invoice_id".