Ограниченные разрешения PostgreSQL для веб-приложения

Цель

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

  1. Суперпользователь - этот пользователь допускает самое начальное предоставление базы данных. Создайте базу данных приложения, создайте других пользователей, установите их привилегии. По умолчанию postgres суперпользователь работает для меня, так что это сделано.
  2. Администратор - этот пользователь имеет доступ только к базе данных, которая была создана во время подготовки. Администратор может CRUD для всех данных во всех таблицах, а также для таблиц CRUD и т. Д. Ситуация типа "Суперпользователь только для этой базы данных". Когда приложение обновляется, администратор - это пользователь, который использует автоматизированные инструменты для обработки миграций базы данных.
  3. Пользователь приложения - этот пользователь, в конечном счете, тот, кто поддерживает функциональность веб-приложения. Обратите внимание, что это не имеет ничего общего с пользователями на веб-страницах и т. Д. - это пользователь, которого сервер использует для выполнения запросов, вставки и удаления данных. Я явно не хочу, чтобы этот пользователь мог изменять права доступа к чему-либо, создавать / уничтожать таблицы или индексы или что-либо структурное.

Что я пробовал

Прежде всего, глядя на (в целом отличную) документацию PostgreSQL, страница о Гранте в значительной степени оставляет меня косоглазым. Потратив несколько часов на чтение ролей и привилегий PostgreSQL, я, как правило, растерялся. Я думаю, что немного потрудившись, я смогу придумать то, что я хочу для пользователя с правами администратора, но я довольно сильно застрял в "пользователе приложения". Я дошел до этого далеко (имена и пароли являются просто местозаполнителями):

$ psql -U postgres
postgres=# CREATE USER "app-admin" WITH PASSWORD 'password';
CREATE ROLE
postgres=# CREATE USER "app-user" WITH PASSWORD 'password';
CREATE ROLE
postgres=# CREATE DATABASE "test-database" WITH OWNER "app-admin";
CREATE DATABASE
postgres=# \c "test-database"
You are now connected to database "test-database" as user "postgres".
test-database=# DROP SCHEMA "public";
DROP SCHEMA
test-database=# CREATE SCHEMA "app" AUTHORIZATION "app-admin";
CREATE SCHEMA

И вот тут я неуверен. Мне кажется, что я пытаюсь избежать ответа: "по умолчанию все отозвать, а затем перечислить все привилегии, которые вам понадобятся на всех разных уровнях для всех разных объектов". Я пытаюсь избежать этого, потому что я прямо не знаю, что мне там нужно. Если это закончится тем, что я получу ответ, тогда мне просто придется сесть на корточки и прочитать больше, но обычно, когда я начинаю идти по таким путям, я что-то упустил.

вопросы

Как мне ограничить привилегии для app-user поэтому они не могут изменять какие-либо структурные данные (например, не могут добавлять или уничтожать таблицы), но могут соединяться и что-либо делать со строками (безопасность на уровне строк даже не на моем радаре). Разве эта общая модель привилегий не совпадает с тем, что ожидает PostgreSQL? Я чувствую, что что-то упускаю, если мне нужно пройтись по каждому варианту на этой странице "гранта", чтобы выполнить что-то вроде этого - будь то моя мотивация сделать это в первую очередь или средства, с помощью которых я собираюсь Это.

контекст

Я пытаюсь создать свое первое сквозное веб-приложение. Я сделал достаточно общей разработки программного обеспечения и разработки веб-приложений, теперь я пытаюсь понять те части, которые я обычно воспринимаю как должное изо дня в день. Я пытаюсь настроить сервер PostgreSQL, помня о принципе наименьших привилегий.

Side-квест

Я не видел, чтобы это было сделано в веб-приложениях, где я просто присоединился к команде разработчиков, хотя они, как правило, невелики и мало используются. Делает ли это на самом деле что-нибудь? У кого-нибудь есть веские причины, почему нужно делать что-то подобное или почему это плохая или неэффективная идея? Я предполагал, что если в конечном итоге я получу уязвимость SQL-инъекции, это уменьшит ущерб, поскольку у пользователя базы данных будет ограниченный доступ. Это ошибочно?

Аккуратные статьи, которые я нашел на эту тему:

2 ответа

Решение

Сначала я отвечу на ваш вопрос о побочных квестах:

вы полностью правы в своих заботах и ​​заботах, и каждый, кто разрабатывает приложение, должен думать об одних и тех же вещах. Все остальное небрежно и небрежно.

Чтобы уменьшить ущерб, который может быть вызван успешной атакой SQL-инъекцией, вы должны определенно использовать принцип наименьших привилегий.

Должно быть достаточно просто настроить систему, которая соответствует вашим требованиям.

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

/* create the database */
\c postgres postgres
CREATE DATABASE test_database WITH OWNER app_admin;
\c test_database postgres

/* drop public schema; other, less invasive option is to
   REVOKE ALL ON SCHEMA public FROM PUBLIC */
DROP SCHEMA public;
/* create an application schema */
CREATE SCHEMA app AUTHORIZATION app_admin;
/* further operations won't need superuser access */
\c test_database app_admin
/* allow app_user to access, but not create objects in the schema */
GRANT USAGE ON SCHEMA app TO app_user;

/* PUBLIC should not be allowed to execute functions created by app_admin */
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin
   REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

/* assuming that app_user should be allowed to do anything
   with data in all tables in that schema, allow access for all
   objects that app_admin will create there */
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT SELECT, USAGE ON SEQUENCES TO app_user;
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT EXECUTE ON FUNCTIONS TO app_user;

Но если вы относитесь к принципу наименее серьезно, вы должны предоставлять разрешения для таблиц индивидуально и, например, не разрешать app_user в DELETE а также UPDATE данные в таблицах, где нет необходимости для пользователя.

Для веб-приложений я разделил разрешения на три роли, каждая из которых наследует от своей предшественницы.

  1. Только чтение - используется для запросов SELECT и вызовов функций
  2. Insert - используется для операторов INSERT
  3. Обновление и удаление - они используются в основном для администрирования, поскольку общедоступное интерфейсное приложение обычно не изменяет и не удаляет данные.

Таким образом, даже если хакеру удается выполнить SQL-инъекцию, он ограничен разрешениями используемой роли, обычно только SELECT или INSERT.

Моим веб-приложениям обычно не нужны более навязчивые разрешения, такие как CREATE, DROP, TRUNCATE и т. Д., Поэтому я не предоставляю эти разрешения веб-приложениям.

В тех редких случаях, когда второй роли необходимо обновить или удалить что-либо, я либо даю ей разрешение для этой конкретной таблицы, либо помещаю код в функцию, которая создается с помощью SECURITY DEFINER,

/** role_read is read-only with SELECT and EXECUTE */
CREATE ROLE role_read;
/** role_read_add adds INSERT */
CREATE ROLE role_read_add;
/** role_read_add_modify adds UPDATE and DELETE */
CREATE ROLE role_read_add_modify;


GRANT USAGE ON SCHEMA <schema> TO role_read;

/** for existing objects */
GRANT SELECT  ON ALL TABLES    IN SCHEMA <schema> TO role_read;
GRANT SELECT  ON ALL SEQUENCES IN SCHEMA <schema> TO role_read;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA <schema> TO role_read;

/** for future objects */
ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
    GRANT SELECT ON TABLES TO role_read;

ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
    GRANT SELECT ON SEQUENCES TO role_read;

/** role_read_add inherits from role_read */
GRANT role_read TO role_read_add;

/** for existing objects */
GRANT INSERT ON ALL TABLES IN SCHEMA <schema> TO role_read_add;
GRANT ALL ON ALL SEQUENCES IN SCHEMA <schema> TO role_read;

/** for future objects */
ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
    GRANT INSERT ON TABLES TO role_read_add;

ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
    GRANT ALL ON SEQUENCES TO role_read_add;

/** role_read_add_modify inherits from role_read_add */
GRANT role_read_add TO role_read_add_modify;

/** for existing objects */
GRANT UPDATE, DELETE ON ALL TABLES IN SCHEMA <schema> 
    TO role_read_add_modify;

/** for future objects */
ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
    GRANT UPDATE, DELETE ON TABLES TO role_read_add_modify;
Другие вопросы по тегам