Рубрики
Без рубрики

Выставлять последовательные идентификаторы – это плохо! Вот как этого избежать.

Статья, первоначально опубликованная в моем личном блоге: Как не раскрывать свои первичные ключи при работе над L… С тегами java, безопасность, база данных.

Статья, первоначально опубликованная в моем личном блоге: Как не раскрывать свои первичные ключи

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

Кроме того, я наткнулся на интересную статью об использовании идентификаторов UUID в качестве первичных ключей. Было несколько действительно замечательных моментов, касающихся производительности и оптимизации запросов. Короче говоря, лучше всего использовать числовые значения в качестве первичного ключа. Итак, я начал менять свою реализацию. Но потом мне в голову пришла другая проблема: безопасность.

Почему разоблачение ПК плохо?

По своей природе автоматически увеличиваемые первичные ключи увеличиваются на один для каждой новой записи. Это отлично подходит для предотвращения столкновений, но это означает, что их легко угадать. Если вы каким-то образом узнаете, что пользователь с идентификатором 27 существует, это, скорее всего, означает, что есть по крайней мере 26 других пользователей с идентификаторами от 1 до 26. Злоумышленник может попытаться воспользоваться этим, отправив запросы с разными идентификаторами. Кроме того, поскольку Администратор обычно регистрируется первым пользователем, он может легко угадать идентификатор и попытаться получить доступ.

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

Файл Cookie Сеанса Воспроизведения

Вы можете подумать, что пока ваши URL-адреса не содержат первичного ключа, все в порядке. Однако есть и другой сценарий: файлы cookie. Всякий раз, когда пользователь входит в систему, сеанс должен быть сохранен, чтобы пользователь мог оставаться в системе и правильно перемещаться по страницам с ограниченным доступом. Play Framework делает это, сохраняя файл cookie сеанса воспроизведения, который выглядит примерно так:

Это можно легко найти с помощью инспектора браузера. На первый взгляд это может показаться случайной строкой символов, однако это гораздо больше. На самом деле это строка JSON в кодировке BASE64 с некоторыми дополнительными, не читаемыми человеком данными в конце. Расшифровать строку легко, и, хотя ее изменение в файле cookie может оказаться невозможным, она все равно может предоставить злоумышленнику ценную информацию, если PK сохранен.

Решение: Как избежать раскрытия ПК

Вы используете UUID! Но подождите, разве я только что не сказал, что использовать UUID плохо? Вы по-прежнему используете числовое, автоматически увеличиваемое значение для PK и FK, но прикрепляете к нему в отдельном столбце идентификатор UUID. Всякий раз, когда вы имеете дело с внутренними данными в одном и том же приложении/системе, используется числовой первичный ключ.

@Entity
@Table(name = "users")
public class UserDO {
    @Id
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "uuid", columnDefinition = "VARCHAR(36)")
    @Type(type = "uuid-char")
    private UUID uuid;

    @Column
    private String username;

    @Column
    private String email;

    @Column
    private String passwordHash;

    @Column
    private String passwordSalt;
}

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

Любые дополнительные данные, на которые ссылаются с помощью FK, все еще могут быть легко извлечены БД и переведены в спящий режим, поскольку используется числовое значение. Короче говоря, вы получаете лучшее из обоих миров, используя числовой PK внутри и UUID снаружи. Первоначальный поиск предмета может быть немного медленнее, но я считаю, что это незначительно.

Статья, первоначально опубликованная в моем личном блоге: Как не раскрывать свои первичные ключи

Оригинал: “https://dev.to/pazvanti/exposing-sequential-ids-is-bad-here-is-how-to-avoid-it-1mjp”