Проектирование API, которые не раскрывают первичные ключи базы данных

Проектирование API, которые не раскрывают первичные ключи базы данных
Проектирование API, которые не раскрывают первичные ключи базы данных - markuswinkler @ Unsplash

Люди говорят "не раскрывайте первичные ключи из базы данных в вашем API", потому что это большая утечка безопасности, поэтому я пытаюсь придумать способ:

  • RESTful HTTP запросы для обращения к ресурсам на стороне сервера без необходимости использования их DB PK
    • пример: Я хочу обновить ресурс Widget с PK ID 293, поэтому я хочу получить эквивалент POST /myapi/widgets/293, но без необходимости упоминать 293.
  • RESTful HTTP ответы должны иметь возможность ссылаться на ресурсы на стороне сервера без отправки обратно их DB PKs
    • пример: Я хочу получить все синие виджеты, поэтому я хочу запросить GET /myapi/widgets?color=blue и все виджеты, которые вернутся в массиве JSON, не должны иметь своих DB PK
    • .

Я могу решить вторую проблему (чтение) с помощью DTO, и просто убедиться, что у меня есть WidgetDto, который не включает поле Widget#id вообще.

Но что касается ссылок на ресурсы без их ключей базы данных, каковы типичные решения здесь?

Единственное, что я могу придумать, это генерировать UUID для каждого ресурса (каждого Widget) и хранить его в БД вместе с первичным ключом, например:

[widgets] table
===
[id] --> bigint primary key auto increment not null
[ref_id] --> varchar(36) not null (UUID)

...и затем часто менять UUID. Но это создает свои собственные головные боли, если что-то на стороне клиента кэшируется или в настоящее время использует ссылку на ресурс, а мы меняем его UUID на стороне сервера. Есть идеи? Спасибо!

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

Если у вас есть API, который [кто-то узнает] поддерживает...

GET /myapi/widgets/293

...тогда ничто не мешает им попробовать...

GET /myapi/widgets/294
GET /myapi/widgets/295
GET /myapi/widgets/296
GET /myapi/widgets/297
. . . 

... пока они не получат что-то обратно.

Другая проблема с этим подходом заключается в том, что эти значения [предположительно только для базы данных] могут сохраняться за пределами вашей базы данных. Допустим, ваше приложение знает, что оно работает с виджетом 21153, поэтому оно сохраняет это значение для собственного использования (неважно где). Затем ваша база данных подвергается реорганизации (по какой-либо причине), и все эти предположительно относящиеся только к базе данных внутренние значения изменяются. (Да, да, я знаю; первичные ключи никогда не должны меняться, но...)

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

Если вместо этого общение основано на естественном ключе, который идентифицирует ту же запись, в данном случае «очки Ladyman217», то этой проблемы можно полностью избежать. Конечно, вам нужно «неформатировать» эти естественные ключи (в соответствующие значения первичного ключа) на пути «в», что означает, что больше индексов и тому подобное поддерживают это, и вам нужно «форматировать» в естественные ключи на обратном пути. "вне". (То же самое можно сказать о датах и ​​числах, но это уже другая история).
Ничего не приходит бесплатно.

По сути, связь базы данных с внешним миром должна осуществляться в терминах, значимых для внешнего мира. Утечка специфики базы данных только делает вещи более хрупкими в долгосрочной перспективе.


LetsCodeIt, 29 декабря 2022 г., 13:41

Похожие посты

Как создавать финансовые отчеты с подробной информациейНаписание растущей симуляции, которая масштабируетсяНужно ли хранить нередактируемые списки элементов в базе данных?Стоит ли использовать последовательный идентификатор базы данных в качестве ключа во внешнем хранилище значений ключа?Можете ли вы предложить способы обеспечения конфиденциальности данных клиентов в продукте SaaS, которым управляете сами?Оптимальный метод хранения миниатюр изображенийПроектирование REST API: как представить пользователей, присоединяющихся к группам и покидающих их?Конечная точка REST API для запроса всех доступных данных с ресурсаСледует ли ограничивать размер массива JSON, чтобы избежать злоупотреблений? Или это уже покрывается ограничениями на размер?Уместно ли (RESTful) иметь ресурс, который является агрегацией другого ресурса?