par , 22/06/2018 à 09h29 (2555 Affichages)
Problématique
Oracle souffre d'une grosse faiblesse fonctionnelle au niveau des permissions DDL (Data Definition Language) que l'on peut donner.
- Il est possible de donner des droits de créer des objets à un utilisateur donné (user) dans son propre schéma (owner) avec les droits spécifiques CREATE TABLE, CREATE PROCEDURE, ... ou des droits plus génériques de type RESOURCE. Dans ce cas, l'utilisateur ne peut influer que sur SON propre schéma
- Si l'on souhaite qu'un utilisateur obtienne ces droits sur une autre schéma, il faut lui donner un droit ANY
Dans des environnements multi-applicatifs où la sécurité est gérée par affinité de schémas, cela pose un réel problème en terme de sécurité puisque le droit ANY donne la permissions associée à TOUS les schémas de la base de données.
Depuis la version 12, Oracle tente de pallier à cette carence sécuritaire par une "pirouette" : les bases multitenants. Il s'agit-là d'un bricolage : il part de la fausse idée qu'un ensemble de schémas interconnecté sera forcément regroupé dans une base... et que dans le cas contraire, on se débrouillera avec des permissions globales des fameux utilisateurs C#... on reporte donc le problème à un autre niveau, sans le résoudre... et l'option multitenant est onéreuse... pour ne pas dire dispendieuse
Solution gratuite
Il existe un autre moyen de contourner ce problème, toujours en mode bricolage : l'utilisation d'un déclencheur sur DDL.
Le concept est malgré tout particulier :
- on donne un droit trop étendu (ANY)
- un bride ce droit via le déclencheur
Il reste à opter pour l'option permissive ou restrictive
- permissive : on autorise tout ce que le ANY autorise, hormis pour ce que l'on bride en spécifiant les droits qu'on ne veut pas donner dans une table spécifique
- restrictive : on n'autorise que ce que l'on spécifie dans la table spécifique
La table spécifique en question aurait ce type de structure
1 2 3 4 5 6 7
| create table ddlperm
(username varchar2(128) not null, /*L'utilisateur que l'on veut traiter*/
schemas varchar2(128) not null, /*le schéma spécifique dans lequel il pourra utiliser son droit */
perm varchar2(100) , /*le droit en question (ALTER, CREATE, DROP, TRUNCATE, ....) */
objtype varchar2(23) not null /* le type d'objet traité (TABLE, PROCEDURE, VIEW, TRIGGER, PACKAGE...)*/
) ;
grant select on ddlperm to public; |
Un exemple de trigger en mode restrictif, mais je me focaliserai ensuite sur le mode permissif, plus aisé à gérer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| create trigger DDL_Trg before DDL ON DATABASE
declare val int ;
BEGIN
select count(*) into val
from vsdba.ddlperm
where username = user
and schemas = ora_dict_obj_owner
and perm = ora_sysevent
and objtype=ora_dict_obj_type ;
if val=0 then
RAISE_APPLICATION_ERROR ( num => -20000, msg => 'Permission DDL manquante : event='||ora_sysevent|| ',user='||user ||',owner='||ora_dict_obj_owner||',type='||ora_dict_obj_type);
end if ;
end ;
/ |
Attention dans ce cas : vous vous rendrez bien vite compte qu'il faut traiter les droits de façon fine... par exemple, un DROP TABLE Oracle fait en fait un DROP + ALTER TABLE... d'où mon intérêt pour le mode plus permissif.
En mode permissif , on laisse donc le droit ANY faire son effet au sens large et on interdit ce que l'on souhaite absolument bloquer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| create trigger DDL_Trg before DDL ON DATABASE
declare val int ;
BEGIN
select count(*) into val
from vsdba.ddlperm
where username = user
and schemas = ora_dict_obj_owner
and perm = ora_sysevent
and objtype=ora_dict_obj_type ;
if val>0 then
RAISE_APPLICATION_ERROR ( num => -20000, msg => 'Permission DDL bridée : event='||ora_sysevent|| ',user='||user ||',owner='||ora_dict_obj_owner||',type='||ora_dict_obj_type);
end if ;
end ; |
Vous l'aurez compris : il vous faut choisir l'une ou l'autre méthode, mais ne pas mixer les deux...
Vous pouvez bien entendu vous inspirer de ces codes et aller plus ou moins loin.
- en ne restant qu'au stade du contrôle du schéma, en supprimant la gestion des colonnes PERM et OBJTYPE
- en ajoutant ora_dict_obect pour mettre la granularité au niveau de l'objet
Granularité au niveau du schéma
Voici la version simpliste au niveau du schéma, en mode restrictif:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| create table ddlperm
(username varchar2(128) not null, /*L'utilisateur que l'on veut traiter*/
schemas varchar2(128) not null /*le schéma spécifique dans lequel il pourra utiliser son droit */
) ;
grant select on ddlperm to public;
insert into ddlperm ('user1','user2') ;
grant create any table to user1 ;
commit ;
create trigger DDL_Trg before DDL ON DATABASE
declare val int ;
BEGIN
select count(*) into val
from vsdba.ddlperm
where username = user
and schemas = ora_dict_obj_owner;
if val=0 then
RAISE_APPLICATION_ERROR ( num => -20000, msg => 'Droit '||ora_sysevent|| ' bridé sur le schéma '||ora_dict_obj_owner);
end if ;
end ;
/ |
On donne donc le droit à user1 de créer une table n'importe où via le droit ANY, mais on le limite au schéma user2 via notre trigger, si le couple {utilsiateur, schéma} ne se trouve pas dans la table ddlperm.