Ответ 1
Настройка политик безопасности на основе параметра сеанса - это идея BAD BAD BAD (я ненавижу оба CAPS и жирный), поэтому поверьте мне, что я имею в виду). Любой пользователь может SET SESSION 'app_name.app_user' = 'bob'
, поэтому, как только кто-то выяснит, что "app_name.app_user" - это дверь (поверьте мне, они будут), тогда вся ваша безопасность выходит за дверь.
Единственный способ, который я вижу, - это использовать таблицу, доступную только для вашего webadmin
, в которой хранятся токены сеанса (тип uuid
, отличная от text
для удобства использования). Функция login()
SECURITY DEFINER
(при условии, что владелец webadmin
), установив токен, а также сеанс SET
ting, а затем таблица, принадлежащая (или имеющая соответствующие привилегии для) webadmin
, ссылается на это таблицы и сеанса в своей политике.
К сожалению, вы не можете использовать временные (сеансовые) таблицы здесь, потому что вы не можете создавать политики во временной таблице, поэтому вам нужно использовать "настоящую" таблицу. Это что-то вроде штрафа за производительность, но весит это против повреждения взлома...
На практике:
CREATE FUNCTION login (uname text, pwd text) RETURNS boolean AS $$
DECLARE
t uuid;
BEGIN
PERFORM * FROM users WHERE user = uname AND password = pwd;
IF FOUND THEN
INSERT INTO sessions SET token = uuid_generate_v4()::text, user ....
RETURNING token INTO t;
SET SESSION "app_name.token" = t;
RETURN true;
ELSE
SET SESSION "app_name.token" = '';
RETURN false;
END IF;
END; $$ LANGUAGE plpgsql STRICT;
И теперь ваша политика будет ссылаться на sessions
:
CREATE POLICY p ON t1 FOR SELECT
USING (SELECT true FROM sessions WHERE token = current_setting('app_name.token'));
(Поскольку uuid
можно считать уникальным, нет необходимости в LIMIT 1
. ordering или другой магии, если uuid
находится в таблице, политика будет проходить, в противном случае сбой.) uuid
невозможно угадать (в любом случае, в любом случае) и невозможно получить кого-либо, кроме webadmin
.