Вибір підходу аутентифікації для фінансового додатка на PostgreSQL


15

Спочатку деяке тло.

Проект LedgerSMB - це програмний проект з відкритим кодом для фінансового обліку, який працює на PostgreSQL. Ми реалізуємо дуже велику кількість бізнес-логіки у визначених користувачем функціях, які виступають основним інструментом відображення між методами програмного об’єкта та поведінкою бази даних. В даний час ми використовуємо користувачів баз даних як користувачів автентифікації, частково за вибором (це дозволяє централізовану логіку безпеки, так що інші інструменти можуть записувати та повторно використовувати дозволи, надані користувачам), а частково за необхідністю (після того, як ми відключились від SQL-Ledger, там не було багато варіантів оновлення безпеки на цій кодовій базі).

Це дає нам доступ до розумної кількості варіантів одиночного входу, до яких має доступ PostgreSQL, від LDAP до Kerberos 5. Ми можемо навіть використовувати PAM, коли стосуються паролів. Це також дозволяє нам повторно використовувати дозволи при інтеграції з іншими програмами або дозволяючи іншим клієнтським інтерфейсам. Для програми фінансового обліку це здається чистим виграшем.

Тут пов'язані очевидні витрати. Щодо веб-додатків, ми обмежені типами http auth, які можна підтримувати. Наприклад, DIGEST повністю вийшов. BASIC працює, і ми могли досить легко реалізувати KRB5 (я планую підтримувати це і працювати над коробкою для 1.4). Дуже сильні заходи аутентифікації не можуть бути належним чином керовані цим рішенням, хоча, можливо, ми можемо їх привласнити, якщо це необхідно (наприклад, BASIC + клієнтська SSL серта з cn, що відповідає імені користувача та конкретному кореневому ca).

У той же час ми стикаємося з неабиякою критикою, здебільшого з боку натовпу розробників, а іноді й з боку dba, які говорять мені, що додаток повинен бути бар'єром безпеки, а не базою даних. Я вважаю, що менший периметр безпеки, як правило, краще, що повторне використання логіки бізнесу та логіки безпеки йдуть разом, і що мені здається небезпечним повторне використання бізнес-логіки без повторного використання логіки безпеки на тому ж рівні програми.

Я пропускаю тут якісь значні компроміси? Чи є ґетчі, які я не розглядаю?


1
Перехресне повідомлення до загального списку розсилки pgsql. Дивіться нитку, що починається тут .
Крейг Рінгер

Відповіді:


17

Я думаю, ви суперечите автентифікацію та авторизацію .

Я повністю погоджуюся, що зберігати модель безпеки в БД є розумним, тим більше, що LedgerSMB розроблений з урахуванням доступу кількох клієнтів. Якщо ви не плануєте на 3-й рівня з проміжним шаром має ідеальний сенс мати користувач в якості ролей бази даних, особливо для що - щось на зразок обліку додатки.

Це не означає, що вам доведеться аутентифікувати користувачів проти бази даних, використовуючи підтримуваний PostgreSQL метод аутентифікації. Користувачі вашої бази даних, ролі та гранти можуть використовуватися для авторизації лише за вашим бажанням.

Ось як працює для веб-інтерфейсу, наприклад:

  • janeпідключається до веб-сервера ui та автентифікується, використовуючи будь-який бажаний метод, скажімо, рукостискання з клієнтським сертифікатом HTTPS X.509 та DIGEST auth. Тепер сервер має підключення від користувача, який він приймає насправді jane.

  • Сервер підключається до PostgreSQL за допомогою фіксованого імені користувача / пароля (або Kerberos або будь-якого іншого), автентифікуючи себе на сервері db як користувачеві webui. Сервер db довіряє webuiаутентифікувати своїх користувачів, тому webuiбуло надано відповідні GRANTs (див. Нижче).

  • Під час цього з'єднання сервер використовує, SET ROLE jane;щоб припустити рівень авторизації користувача jane. Поки RESET ROLE;або SET ROLEне запущено інше , з'єднання функціонує з тими ж правами доступу, що janeі з SELECT current_user()ін jane.

  • Сервер підтримує зв'язок між підключенням до бази даних, на якому він має SET ROLEперейти, janeта веб-сеансом для користувача jane, не дозволяючи, щоб PostgreSQL-з'єднання використовувалося іншими з'єднаннями з іншими користувачами без нового SET ROLEпроміжку.

Тепер ви автентифікуєтесь поза сервером, але зберігаєте авторизацію на сервері. Pg повинен знати, які існують користувачі, але не потребує паролів або методів аутентифікації для них.

Побачити:

Деталі

Сервер webui контролює виконання запитів, і він не збирається дозволяти janeзапускати необроблений SQL (сподіваюся!), Тому janeне може RESET ROLE; SET ROLE special_admin_user;через веб-інтерфейс. Для додаткової безпеки я додав би фільтр операторів на сервер, який відхилив, SET ROLEі RESET ROLEякщо тільки з'єднання не було або входило в пул непризначених з'єднань.

Ви все ще можете використовувати пряму автентифікацію на Pg в інших клієнтах; можна вільно змішувати та поєднувати Ви просто повинні GRANTна webuiкористувача права SET ROLEкористувачів , які можуть увійти в систему через Інтернет , а потім дати цим користувачам будь-які звичайні CONNECTправа, паролі і т.д. , які ви хочете. Якщо ви хочете зробити їх лише в Інтернеті, REVOKEїх CONNECTправа на базу даних (і з public).

Щоб зробити такий розрив автентифікації / авторизації, я маю особливу роль, assume_any_userяку я повинен виконувати GRANTкожному новоствореному користувачеві. Потім я перейду GRANT assume_any_userдо справжнього імені користувача, використовуваного такими речами, як довірена веб-сторінка, надаючи їм права стати будь-яким користувачем, який їм подобається.

Дуже важливо , щоб assume_any_userна NOINHERITроль, так що webuiкористувач або будь-який інший не має privilges від своєї самості і може діяти тільки в базі даних , як тільки це SET ROLEдля реального користувача. Ні за яких обставин не повинно webuiбути власником або власником БД .

Якщо ви з'єднуєте з'єднання, ви можете використовувати SET LOCAL ROLEдля встановлення ролі лише в рамках транзакції, щоб ви могли повернути з'єднання до пулу після COMMITабо ROLLBACK. Остерігайтеся, що це RESET ROLEвсе ще працює, тому досі клієнт не може дозволити запускати будь-який SQL, який він хоче.

SET SESSION AUTHORIZATION- пов'язана, але сильніша версія цієї команди. Це не вимагає членства в ролі, але це лише команда суперпользователя. Ви не хочете, щоб ваш веб-інтерфейс підключався як супер-користувач. Це може бути скасовано з RESET SESSION AUTHORIZATION, SET SESSION AUTHORIZATION DEFAULTабо SET SESSION AUTHORIZATION theusernameповернути права суперкористувача , так що це не привілей , скидаючи бар'єр безпеки або.

Команда, яка працювала на кшталт, SET SESSION AUTHORIZATIONале була незворотною і діяла б, якби ви були членом ролі, але не суперпользователем, було б чудово. Наразі цього немає, але ви все одно можете добре розділити аутентифікацію та авторизацію, якщо ви обережні.

Приклад та пояснення

CREATE ROLE dbowner NOLOGIN;
CREATE TABLE test_table(x text);
INSERT INTO test_table(x) VALUES ('bork');
ALTER TABLE test_table OWNER TO dbowner;

CREATE ROLE assume_any_user NOINHERIT NOLOGIN;
CREATE ROLE webui LOGIN PASSWORD 'somepw' IN ROLE assume_any_user;

CREATE ROLE jane LOGIN PASSWORD 'somepw';
GRANT jane TO assume_any_user;
GRANT ALL ON TABLE test_table TO jane;

CREATE ROLE jim LOGIN PASSWORD 'somepw';
GRANT jim TO assume_any_user;

Тепер підключіть як webui. Зверніть увагу , що ви не можете нічого зробити , test_tableале ви можете SET ROLE з janeі потім ви можете отримати доступ до test_table:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | webui
(1 row)



regress=> SELECT * FROM test_table;
ERROR:  permission denied for relation test_table

regress=> SET ROLE jane;
SET

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jane
(1 row)

regress=> SELECT * FROM test_table;
  x   
------
 bork
(1 row)

Зверніть увагу , що webui може SET ROLE , щоб jim, навіть коли вже SET ROLEцифро janeі навіть якщо janeНЕ GRANTед право приймати на себе роль jim. SET ROLEвстановлює ваш ефективний ідентифікатор користувача, але він не знімає вашу здатність до SET ROLEінших ролей, це властивість ролі, яку ви зв'язали, а не вашої поточної ефективної ролі. Отже, ви повинні ретельно контролювати доступ до команд SET ROLEта RESET ROLE. AFAIK не має можливості назавжди SET ROLEвстановити з'єднання, по-справжньому стати цільовим користувачем, хоча це, звичайно, було б приємно мати.

Порівняйте:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SET ROLE jane;
SET

regress=> SET ROLE jim;
SET
regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jim
(1 row)

до:

$ psql -h 127.0.0.1 -U jane regress
Password for user jane:

regress=> SET ROLE webui;
ERROR:  permission denied to set role "webui"
regress=> SET ROLE jim;
ERROR:  permission denied to set role "jim"

Це означає, що ви SET ROLEне точно збігаєтесь із входом у систему як певна роль, що потрібно пам’ятати.

webuiне SET ROLEможе, dbownerоскільки це не було GRANTвідредаговано правильно:

regress=> SET ROLE dbowner;
ERROR:  permission denied to set role "dbowner"

тож само по собі воно досить безсиле, воно може брати на себе права інших користувачів і лише тоді, коли цим користувачам увімкнено доступ до Інтернету.


1
btw, можливо, ви захочете подивитися, як pgbouncerпрацює деякі деталі.
Крейг Рінгер

2
О, DISCARD ALLце ще один спосіб повернення прав до дефолту. Мені дуже хочеться, щоб у Pg було SET ROLE NORESETподібне чи таке ...
Крейг Рінгер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.