Как стать автором
Обновить

Кодирование цифрового идентификатора

Время на прочтение2 мин
Количество просмотров2.4K
Читая как-то статью Сессии — всегда ли они нужны? вспомнил свои давнишние мучения по тому же самому поводу.
Когда-то я тоже строил хеши из полученных и серверных данных, дабы не показывать пользователю его внутренний идентификатор, а в базе хранил подпись последнего.

Однако, со временем меня перестал устраивать подобный алгоритм, а количество контейнеров в cookies захотелось сократить до минимума.
Не взыщите, если уже было (искал — на хабре не нашёл), а также если кому не понравится, да не гордости ради, а пользы для:

(алгоритм кодирования/декодирования идентификатора умещается в одну строку, но для удобства чтения разнесён поэтапно)
<?php
$user_id  = 1;
$crc32    = crc32($_SERVER['REMOTE_ADDR'] . '-' . $_SERVER['HTTP_USER_AGENT']);

// кодируем идентификатор
$cookie   = $user_id + abs($crc32);
$cookie   = decbin($cookie);
$cookie   = str_pad($cookie, 32, '0', TR_PAD_LEFT);
$cookie   = strrev($cookie);

// раскодируем идентификатор
$user_id  = strrev($cookie);
$user_id  = bindec($server);
$user_id -= abs($crc32);
?>

(Описания функций смотрите в документации.)

Что мы получаем? А мы получаем бинарную строку в 32 символа, которая кодируется и раскодируется на лету (вышеуказанный код на моей машине занял 0.00007 секунды).
Алгоритм как угодно можно упрощать или усложнять, но в любом случае — если он не известен тому, кто хочет его раскодировать, то у него попросту ничего не получится.
Алгоритм приведённого примера, на самом деле, очень прост и есть вероятность, что злоумышленник его вычислит, однако изменив его немного, вы можете получить любую непредсказуемую последовательность в контейнере $cookie, которую сможете преобразовать обратно только вы сами.
К примеру, вместо переворачивания всей строки ($cookie = strrev($cookie);) постройте следующее:
<?php
$chr_num  = (int)$_SERVER['REMOTE_ADDR'] % 30;
$str_rev  = strrev(substr($cookie, 0, $chr_num));
$cookie   = $str_rev . substr($cookie, $chr_num);
?>

и ваш алгоритм становится динамическим! Всё зависит только от вашей фантазии (к примеру, в зависимости от браузера пользователя — вы можете переворачивать начало или конец строки, а то и середину).

Из плюсов:
— при возвращении на сервер со строкой производятся такие преобразования, что вы можете безопасно использовать её в SQL запросе;
— в случае если вы сами не раскрываете алгоритма — его практически невозможно разгадать;
— и идентификатор и его подпись спрятаны внутри одной строки;
— вы можете быть уверены, что идентификатор нигде не повториться (в изначальном примере);
— как минимум от 0 до 100 000 000 строка не будет превышать (опять таки, согласно изначального примера) 32 символов (дальше я не проверял :)
— нет привязки к конкретному компьютеру, потому как всё сверяется по $user_id, а остальное касается только данного комьютера.

Из минусов:
— указанный выше динамический алгоритм не приемлим — возможны числовые совпадения, данные строки приведены только для ознакомления (способы решения данной проблемы найти несложно);
— теоритически возможно методом простого перебора от 0 до 11111111111111111111111111111111 попасть в любой из аккаунтов, но и это решаемо (кто ищет, тот всегда найдёт);
— ещё что-то? буду рад выслушать мнения и аргументации в ту или иную сторону.

По теме:
CRC32;
Сессии — всегда ли они нужны?;
PHP Documentation.
Теги:
Хабы:
Всего голосов 14: ↑6 и ↓8-2
Комментарии31

Публикации