Читая как-то статью Сессии — всегда ли они нужны? вспомнил свои давнишние мучения по тому же самому поводу.
Когда-то я тоже строил хеши из полученных и серверных данных, дабы не показывать пользователю его внутренний идентификатор, а в базе хранил подпись последнего.
Однако, со временем меня перестал устраивать подобный алгоритм, а количество контейнеров в cookies захотелось сократить до минимума.
Не взыщите, если уже было (искал — на хабре не нашёл), а также если кому не понравится, да не гордости ради, а пользы для:
(алгоритм кодирования/декодирования идентификатора умещается в одну строку, но для удобства чтения разнесён поэтапно)
(Описания функций смотрите в документации.)
Что мы получаем? А мы получаем бинарную строку в 32 символа, которая кодируется и раскодируется на лету (вышеуказанный код на моей машине занял 0.00007 секунды).
Алгоритм как угодно можно упрощать или усложнять, но в любом случае — если он не известен тому, кто хочет его раскодировать, то у него попросту ничего не получится.
Алгоритм приведённого примера, на самом деле, очень прост и есть вероятность, что злоумышленник его вычислит, однако изменив его немного, вы можете получить любую непредсказуемую последовательность в контейнере $cookie, которую сможете преобразовать обратно только вы сами.
К примеру, вместо переворачивания всей строки (
и ваш алгоритм становится динамическим! Всё зависит только от вашей фантазии (к примеру, в зависимости от браузера пользователя — вы можете переворачивать начало или конец строки, а то и середину).
Из плюсов:
— при возвращении на сервер со строкой производятся такие преобразования, что вы можете безопасно использовать её в SQL запросе;
— в случае если вы сами не раскрываете алгоритма — его практически невозможно разгадать;
— и идентификатор и его подпись спрятаны внутри одной строки;
— вы можете быть уверены, что идентификатор нигде не повториться (в изначальном примере);
— как минимум от 0 до 100 000 000 строка не будет превышать (опять таки, согласно изначального примера) 32 символов (дальше я не проверял :)
— нет привязки к конкретному компьютеру, потому как всё сверяется по
Из минусов:
— указанный выше динамический алгоритм не приемлим — возможны числовые совпадения, данные строки приведены только для ознакомления (способы решения данной проблемы найти несложно);
— теоритически возможно методом простого перебора от 0 до 11111111111111111111111111111111 попасть в любой из аккаунтов, но и это решаемо (кто ищет, тот всегда найдёт);
— ещё что-то? буду рад выслушать мнения и аргументации в ту или иную сторону.
По теме:
— CRC32;
— Сессии — всегда ли они нужны?;
— PHP Documentation.
Когда-то я тоже строил хеши из полученных и серверных данных, дабы не показывать пользователю его внутренний идентификатор, а в базе хранил подпись последнего.
Однако, со временем меня перестал устраивать подобный алгоритм, а количество контейнеров в 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.