Работал я в одном стартапе на Кложе. Код прошел через десятки разработчиков и представлял лоскутное одеяло: разные подходы и библиотеки. Каждый разработчик городил что-то сбоку, а не исправлял текущее положение дел. Была своя ORM с километрами кода и склейкой SQL-строк. Много там всего было, и в том числе база данных.

Эта база прямо сейчас стоит в памяти. Она тоже прошла через серию разработчиков, каждый из которых знал, как делать правильно. Одни ребята забивали на нормализацию; другие решили, что добавлять колонки утомительно и сделали поле info с типом jsonb, в которое валили все подряд. Были материализованные вьюхи, обновлять которые было затратно, и которые без конца обновлялись из-за косяков в очереди сообщений. Ни одна запись физически не удалялась, а помечалась флагом is_deleted = true. Много багов было связано с тем, что данные выбирались без этой проверки.

Но это не все. Основатель фирмы считал себя специалистом по безопасности и придумал вот что. В Постгресе есть штука под названием ROW CHECK: проверка доступа на уровне записи. Если некая функция my_check(row) возвращает null или false, то клиент словно не видит этой записи. Это медленно, но работало.

Почему директор так сделал? Он хранил в одной таблице данные разных клиентов и опасался, что из-за ошибки в коде один клиент увидит данные другого. Поэтому каждая таблица хранила избыточные айдишки, и в рамках каждого запроса выставлялась переменная current_owner. Функция ROW CHECK проверяла, что ее значение совпадает с айдишками записи.

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

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

Забавно, но наибольший урон базе нанес именно директор, а не хакеры или кривой код. Хакерам, видимо, стартап был не интересен, хотя в самописной ORM были дыры для инъекций. Код, хоть и был не супер, не страдал тем, что читал чужие данные. Свои удаленные – да, но не чужие.

Можно сказать одно: все запреты проверяются на прочность теми, кто их создает. У меня доступ на прод был только для чтения. В другом стартапе права на запись были, но под той учеткой я не ходил. В конце концов, был страх, что за подобный инцидент уводят. А у директора страха не было, вот и результат.

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