FirebirdSQL logo

Le deuxième niveau du modèle de sécurité de Firebird est celui des privilèges SQL. Après une connexion réussie (niveau un), un utilisateur autorisé a accès au serveur et à toutes les bases de données de ce serveur, mais cela ne signifie pas qu’il a accès à tous les objets de toutes les bases de données. Une fois qu’un objet est créé, seuls l’utilisateur qui a créé l’objet (son propriétaire) et les administrateurs y ont accès. Un utilisateur a besoin de privilèges pour chaque objet auquel il doit accéder. En général, les privilèges doivent être accordés explicitement par

Un privilège comprend le type d’accès DML (SELECT, INSERT, UPDATE, DELETE, EXECUTE et REFERENCES), le nom de l’objet de base de données pour lequel le privilège est accordé (table, vue, procédure ou rôle) et le nom de l’objet du privilège (utilisateur, procédure, déclencheur, rôle). Il existe différentes façons d’accorder plusieurs types d’accès au même objet de base de données à plusieurs utilisateurs dans une seule instruction GRANT. Les privilèges peuvent être révoqués à l’aide de l’instruction REVOKE.

Tous les privilèges d’accès aux objets de la base de données sont stockés dans la base de données elle-même, et ne peuvent être appliqués à aucune autre base de données.

Le propriétaire de l’objet de la base de données

L’utilisateur qui a créé un objet de base de données en devient le propriétaire. Seuls le propriétaire de l’objet et les utilisateurs ayant les privilèges administrateurs dans la base de données peuvent modifier ou supprimer l’objet de la base de données. Le propriétaire de la base de données, c’est-à-dire l’utilisateur qui l’a créé, dispose de tous les droits sur les objets qui ont été créés par d’autres utilisateurs.

Les administrateurs ou le propriétaire de l’objet peuvent accorder des privilèges à d’autres utilisateurs, y compris des privilèges pour accorder des privilèges à d’autres utilisateurs. Le processus réel d’octroi et de révocation des privilèges au niveau SQL est mis en œuvre par deux opérateurs :GRANT, REVOKE.

Privilèges d’exécution du code SQL

Tous les objets de métadonnées contenant du code DML ou PSQL peuvent être exécutés dans l’un des modes suivants :

  • Avec des privilèges d’utilisateur appelant (privilèges CURRENT_USER) ;

  • En définissant les privilèges de l’utilisateur (propriétaire de l’objet de métadonnées).

Historiquement, tous les modules PSQL sont exécutés avec les privilèges de l’utilisateur appelant par défaut. À partir de Firebird 4.0, il est maintenant possible de spécifier des objets de métadonnées à exécuter par l’utilisateur appelant ou définissant. Ceci est fait avec l’option SQL SECURITY, qui peut être spécifiée pour une table, un trigger, une procédure, une fonction ou un package. Si l’option INVOKER est sélectionnée, l’objet de métadonnées sera exécuté avec les privilèges de l’utilisateur appelant. Si l’option DEFINER est sélectionnée, l’objet de métadonnées sera exécuté avec les privilèges de l’utilisateur qui le définit (propriétaire). Ces privilèges s’ajouteront aux privilèges accordés au module PSQL lui-même à l’aide de l’opérateur GRANT.

Les privilèges d’exécution avec lesquels tout module PSQL est exécuté par défaut (non spécifiés par le module lui-même) peuvent être modifiés à l’aide de la commande

ALTER DATABASE SET DEFAULT SQL SECURITY {DEFINER | INVOKER}

L’option INVOKER est utilisée par défaut pour maintenir une compatibilité ascendante.

Note
Remarques
  • Les vues (VIEWs) sont toujours exécutées avec les privilèges de l’utilisateur qui les définit (propriétaire) ;

  • Par défaut, les déclencheurs héritent des privilèges d’exécution qui ont été spécifiés pour la table. Les privilèges d’exécution peuvent être remplacés dans le déclencheur lui-même ;

  • Les procédures et les fonctions du paquet héritent toujours des privilèges d’exécution spécifiés lors de la définition du paquet. Les privilèges d’exécution ne peuvent pas être remplacés dans les procédures et fonctions du paquet elles-mêmes ;

  • Les blocs PSQL anonymes (EXECUTE BLOCK) sont toujours exécutés avec les privilèges de l’appelant.

Dans les procédures stockées, les fonctions et les triggers, vous pouvez vérifier l’utilisateur effectif actuel, c’est-à-dire l’utilisateur dont les privilèges sont en cours d’exécution, en utilisant la variable de contexte système EFFECTIVE_USER de l’espace de noms SYSTEM.

select RDB$GET_CONTEXT('SYSTEM', 'EFFECTIVE_USER') from RDB$DATABASE;
Note

Le même objet peut être appelé dans différents contextes de sécurité et nécessiter des privilèges différents. Par exemple, nous avons :

  • une procédure stockée INV avec SECURITY INVOKER qui insère des enregistrements dans la table T ;

  • une procédure stockée DEF avec SQL SECURITY DEFINER qui est définie par l’utilisateur SYSDBA.

Si l’utilisateur U appelle la procédure INV, alors le privilège INSERT accordé à l’utilisateur U sera nécessaire pour accéder à la table T (et bien sûr le privilège EXECUTE pour INV). Dans ce cas, U est l’utilisateur effectif (EFFECTIVE_USER) lors de l’exécution de INV.

Si l’utilisateur U appelle la procédure DEF, le privilège INSERT accordé à l’utilisateur SYSDBA (et EXECUTE sur DEF pour l’utilisateur U) sera nécessaire pour accéder à la table T. Dans ce cas, SYSDBA est l’utilisateur effectif (EFFECTIVE_USER) lors de l’exécution de DEF. Si la procédure INV est appelée à l’intérieur de DEF, alors l’utilisateur effectif au moment de l’exécution de INV est aussi SYSDBA.

Exemples

Example 1. Création d’une table avec des privilèges définis par l’utilisateur

Dans ce cas, l’utilisateur JOE a seulement besoin du privilège SELECT sur la table t. Si la table avait été créée avec les privilèges de l’utilisateur appelant (INVOKER), le privilège EXECUTE pour la table sur la fonction f devrait également être accordé.

SET TERM ^;

CREATE FUNCTION f() RETURNS INT
AS
BEGIN
  RETURN 3;
END^

SET TERM ;^

CREATE TABLE t (
  i INTEGER,
  c COMPUTED BY (i + f())
)
SQL SECURITY DEFINER;

INSERT INTO t VALUES (2);

GRANT SELECT ON TABLE t TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

SELECT * FROM t;
Example 2. Création d’une procédure avec des privilèges définis par l’utilisateur

Dans ce cas, l’utilisateur JOE n’a besoin que du privilège EXECUTE sur la procédure p. Si la procédure avait été créée avec des privilèges d’utilisateur appelant (option INVOKER), le privilège INSERT pour la procédure p sur la table t devrait également être accordé.

CREATE TABLE t (i INTEGER);

SET TERM ^;

CREATE PROCEDURE p (i INTEGER)
SQL SECURITY DEFINER
AS
BEGIN
  INSERT INTO t VALUES (:i);
END^

SET TERM ;^

GRANT EXECUTE ON PROCEDURE p TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

EXECUTE PROCEDURE p(1);
Example 3. Création d’une fonction avec des privilèges définis par l’utilisateur

Dans ce cas, l’utilisateur JOE a seulement besoin du privilège EXECUTE pour la fonction f. Si la fonction avait été créée avec des privilèges d’utilisateur appelant (option INVOKER), le privilège SELECT pour la fonction f sur la table t devrait également être accordé.

CREATE TABLE t (i INTEGER PRIMARY KEY, j INTEGER);

INSERT INTO t(i, j) VALUES(1, 2);
INSERT INTO t(i, j) VALUES(2, 5);

COMMIT;

SET TERM ^;

CREATE FUNCTION f (i INTEGER)
SQL SECURITY DEFINER
AS
  DECLARE j INTEGER DEFAULT NULL;
BEGIN
  SELECT j
  FROM t
  WHERE i = :i
  INTO j;

  RETURN COALESCE(j, 0);
END^

SET TERM ;^

GRANT EXECUTE ON FUNCTION f TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

SELECT f(1) AS j FROM RDB$DATABASE;
Example 4. Création d’un déclencheur avec des privilèges définis par l’utilisateur

Dans ce cas, l’utilisateur JOE a seulement besoin du privilège INSERT sur la table tr. Si le déclencheur avait été créé avec les privilèges de l’utilisateur appelant (option INVOKER), alors le privilège INSERT pour le déclencheur tr_ins sur la table t devrait également être accordé.

CREATE TABLE tr (i INTEGER);
CREATE TABLE t (i INTEGER);

SET TERM ^;

CREATE TRIGGER tr_ins FOR tr AFTER INSERT
SQL SECURITY DEFINER
AS
BEGIN
  INSERT INTO t(i) VALUES(NEW.i);
END^

SET TERM ;^

GRANT INSERT ON TABLE tr TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

INSERT INTO tr(i) VALUES(2);

COMMIT;

Le même résultat peut être obtenu en spécifiant SQL SECURITY DEFINER pour la table tr.

CREATE TABLE tr (i INTEGER) SQL SECURITY DEFINER;
CREATE TABLE t (i INTEGER);

SET TERM ^;

CREATE TRIGGER tr_ins FOR tr AFTER INSERT
AS
BEGIN
  INSERT INTO t(i) VALUES(NEW.i);
END^

SET TERM ;^

GRANT INSERT ON TABLE tr TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

INSERT INTO tr(i) VALUES(2);

COMMIT;
Example 5. Suppression des privilèges d’exécution d’un déclencheur
Si le déclencheur est explicitement défini sur l’option SQL SECURITY, l’instruction suivante doit être exécutée pour hériter des privilèges d’exécution de la table.
ALTER TRIGGER tr_ins DROP SQL SECURITY;
Example 6. Création d’un paquet avec des privilèges définis par l’utilisateur

Dans ce cas, l’utilisateur JOE n’a besoin que du privilège EXECUTE sur le paquet pk. Si le paquet avait été créé avec des privilèges d’utilisateur appelant (l’option INVOKER), il devrait également donner le privilège INSERT pour le paquet pk sur la table t.

CREATE TABLE t (i INTEGER);

SET TERM ^;

CREATE PACKAGE pk
SQL SECURITY DEFINER
AS
BEGIN
  FUNCTION f(i INTEGER) RETURNS INT;
END^

CREATE PACKAGE BODY pk
AS
BEGIN
  FUNCTION f(i INTEGER) RETURNS INT
  AS
  BEGIN
    INSERT INTO t VALUES (:i);
    RETURN i + 1;
  END
END^

SET TERM ;^

GRANT EXECUTE ON PACKAGE pk TO USER joe;

COMMIT;

CONNECT 'inet://localhost:test' USER joe PASSWORD 'pas';

SELECT pk.f(3) FROM rdb$database;
Example 7. Modification des privilèges d’exécution par défaut

Après avoir exécuté cette instruction PSQL, les modules seront créés par défaut avec l’option `SQL SECURITY DEFINER'.

ALTER DATABASE SET DEFAULT SQL SECURITY DEFINER;