Ограниченные разрешения PostgreSQL для веб-приложения
Цель
Создайте базу данных с тремя пользователями и ограничьте их привилегии (я просто думаю вслух, поэтому мое разделение пользователей также открыто для исправления):
- Суперпользователь - этот пользователь допускает самое начальное предоставление базы данных. Создайте базу данных приложения, создайте других пользователей, установите их привилегии. По умолчанию
postgres
суперпользователь работает для меня, так что это сделано. - Администратор - этот пользователь имеет доступ только к базе данных, которая была создана во время подготовки. Администратор может CRUD для всех данных во всех таблицах, а также для таблиц CRUD и т. Д. Ситуация типа "Суперпользователь только для этой базы данных". Когда приложение обновляется, администратор - это пользователь, который использует автоматизированные инструменты для обработки миграций базы данных.
- Пользователь приложения - этот пользователь, в конечном счете, тот, кто поддерживает функциональность веб-приложения. Обратите внимание, что это не имеет ничего общего с пользователями на веб-страницах и т. Д. - это пользователь, которого сервер использует для выполнения запросов, вставки и удаления данных. Я явно не хочу, чтобы этот пользователь мог изменять права доступа к чему-либо, создавать / уничтожать таблицы или индексы или что-либо структурное.
Что я пробовал
Прежде всего, глядя на (в целом отличную) документацию 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-инъекции, это уменьшит ущерб, поскольку у пользователя базы данных будет ограниченный доступ. Это ошибочно?
Аккуратные статьи, которые я нашел на эту тему:
- http://www.ibm.com/developerworks/opensource/library/os-postgresecurity/index.html
- ПРЕДУПРЕЖДЕНИЕ PDF: https://wiki.postgresql.org/images/d/d1/Managing_rights_in_postgresql.pdf
- https://www.digitalocean.com/community/tutorials/how-to-use-roles-and-manage-grant-permissions-in-postgresql-on-a-vps--2
- http://blog.2ndquadrant.com/auditing-users-and-roles-in-postgresql/
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
данные в таблицах, где нет необходимости для пользователя.
Для веб-приложений я разделил разрешения на три роли, каждая из которых наследует от своей предшественницы.
- Только чтение - используется для запросов SELECT и вызовов функций
- Insert - используется для операторов INSERT
- Обновление и удаление - они используются в основном для администрирования, поскольку общедоступное интерфейсное приложение обычно не изменяет и не удаляет данные.
Таким образом, даже если хакеру удается выполнить 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;