Utilisation de vues sécurisées

Cette rubrique couvre les concepts et la syntaxe permettant de définir des vues et des vues matérialisées comme sécurisées.

Dans ce chapitre :

Aperçu des vues sécurisées

Pourquoi utiliser des vues sécurisées ?

  • Pour une vue non sécurisée, les optimisations internes peuvent exposer indirectement des données.

    Certaines des optimisations internes des vues nécessitent l’accès aux données sous-jacentes dans les tables de base de la vue. Cet accès pourrait permettre aux données qui sont cachées aux utilisateurs de la vue d’être affichées au moyen d’un code utilisateur, comme des fonctions définies par l’utilisateur ou d’autres méthodes programmatiques. Les vues sécurisées n’utilisent pas ces optimisations, ce qui garantit que les utilisateurs n’ont pas accès aux données sous-jacentes.

  • Pour une vue non sécurisée, la définition de la vue est visible par les autres utilisateurs.

    En outre, par défaut, l’expression de requête utilisée pour créer une vue standard, également appelée définition de vue ou texte, est visible par les utilisateurs dans des commandes et interfaces diverses. Pour plus d’informations, voir Interaction avec des vues sécurisées (dans cette rubrique).

    Pour des raisons de sécurité ou de confidentialité, il est possible que vous ne souhaitiez pas exposer les tables sous-jacentes ou les détails structurels internes d’une vue. Avec les vues sécurisées, la définition et les détails de la vue ne sont visibles que par les utilisateurs autorisés (c’est-à-dire les utilisateurs qui se voient attribuer le rôle qui possède la vue).

Quand utiliser une vue sécurisée ?

Les vues doivent être définies comme sécurisées lorsqu’elles sont spécifiquement conçues pour la confidentialité des données, c’est-à-dire pour limiter l’accès aux données sensibles qui ne doivent pas être exposées à tous les utilisateurs de la ou des tables sous-jacentes.

Les vues sécurisées ne doivent pas être utilisées pour des vues qui sont définies pour simplifier les requêtes, telles que les vues créées pour simplifier les requêtes pour lesquelles les utilisateurs n’ont pas besoin de comprendre la représentation des données sous-jacente. Les vues sécurisées peuvent s’exécuter plus lentement que les vues non sécurisées.

Astuce

Lorsque vous décidez d’utiliser ou non une vue sécurisée, vous devez prendre en compte l’objectif de la vue, et peser le pour et le contre entre confidentialité/sécurité des données et performance des requêtes.

Comment les données peuvent-elles être exposées par une vue non sécurisée ?

En nous basant sur l’exemple de widgets suivant, imaginons un utilisateur qui n’a accès qu’aux widgets rouges. Imaginons que l’utilisateur se demande s’il existe des widgets violets et lance la requête suivante :

SELECT *
    FROM widgets_view
    WHERE 1/iff(color = 'Purple', 0, 1) = 1;
Copy

Si des widgets violets existent, l’expression IFF() renvoie 0. L’opération de division échoue alors en raison d’une erreur de division par zéro, ce qui permet à l’utilisateur de déduire qu’il existe au moins un widget violet.

Création de vues sécurisées

Les vues sécurisées se définissent à l’aide du mot-clé SECURE et du DDL standard pour les vues :

Interaction avec des vues sécurisées

Affichage de la définition des vues sécurisées

La définition d’une vue sécurisée n’est exposée qu’aux utilisateurs autorisés (c’est-à-dire aux utilisateurs qui se sont vu attribuer le rôle qui possède la vue). Si un utilisateur non autorisé utilise l’une des commandes ou interfaces suivantes, la définition de vue ne s’affiche pas :

Cependant, les utilisateurs qui ont obtenu le privilège IMPORTED PRIVILEGES sur la base de données SNOWFLAKE ou une autre base de données partagée ont accès aux définitions de vues sécurisées via la vue VIEWS Account Usage.

Les utilisateurs ayant le rôle ACCOUNTADMIN ou le rôle de base de données SNOWFLAKE.OBJECT_VIEWER peuvent également voir les définitions de vues sécurisées via cette vue. Le moyen d’accès préféré, le moins privilégié, est le rôle de base de données SNOWFLAKE.OBJECT_VIEWER.

Déterminer si une vue est sécurisée

Pour les vues non matérialisées, la colonne IS_SECURE des vues Schéma d’information et Utilisation du compte indiquent s’il s’agit d’une vue sécurisée ou non. Par exemple, pour une vue nommée MYVIEW dans la base de données mydb :

Information Schema :

select table_catalog, table_schema, table_name, is_secure
    from mydb.information_schema.views
    where table_name = 'MYVIEW';
Copy

Account Usage :

select table_catalog, table_schema, table_name, is_secure
    from snowflake.account_usage.views
    where table_name = 'MYVIEW';
Copy

(Pour des informations générales sur les différences entre les vues INFORMATION_SCHEMA et les vues ACCOUNT_USAGE, voir Différences entre Account Usage et Information Schema).

Vous pouvez également utiliser la commande SHOW VIEWS pour afficher des informations similaires (notez que le nom de la vue ne respecte pas la casse) :

SHOW VIEWS LIKE 'myview';
Copy

Pour les vues matérialisées, utilisez la commande SHOW MATERIALIZED VIEWS pour identifier si une vue est sécurisée. Par exemple :

SHOW MATERIALIZED VIEWS LIKE 'my_mv';
Copy

Affichage des détails de la vue sécurisée dans le profil de requête

Les éléments internes d’une vue sécurisée ne sont pas exposés dans Profil de requête (dans l’interface Web). C’est aussi le cas pour le propriétaire de la vue sécurisée, puisque des non-propriétaires peuvent avoir accès au profil de requête d’un propriétaire.

Utilisation de vues sécurisées avec le contrôle d’accès Snowflake

La sécurité des vues peut être intégrée avec les utilisateurs et les rôles de Snowflake à l’aide des fonctions contextuelles CURRENT_ROLE et CURRENT_USER. L’exemple suivant illustre l’utilisation de rôles pour contrôler l’accès aux lignes d’une table. Outre la table qui contient les données (widgets), l’exemple utilise une table d’accès (widget_access_rules) pour suivre quels rôles ont accès à quelles lignes dans la table de données :

CREATE TABLE widgets (
    id NUMBER(38,0) DEFAULT widget_id_sequence.nextval, 
    name VARCHAR,
    color VARCHAR,
    price NUMBER(38,0),
    created_on TIMESTAMP_LTZ(9));
CREATE TABLE widget_access_rules (
    widget_id NUMBER(38,0),
    role_name VARCHAR);
CREATE OR REPLACE SECURE VIEW widgets_view AS
    SELECT w.*
        FROM widgets AS w
        WHERE w.id IN (SELECT widget_id
                           FROM widget_access_rules AS a
                           WHERE upper(role_name) = CURRENT_ROLE()
                      )
    ;
Copy

La clause WHERE limite les widgets que chaque rôle peut voir.

Supposons qu’un utilisateur qui n’a accès qu’aux widgets rouges exécute la requête présentée précédemment :

SELECT *
    FROM widgets_view
    WHERE 1/iff(color = 'Purple', 0, 1) = 1;
Copy

La clause WHERE de la vue sécurisée est exécutée avant toute clause WHERE de la requête de l’utilisateur. Les widgets violets étant exclus par la vue, la requête de l’utilisateur ne génère jamais d’erreur de division par zéro.

Si la vue n’était pas sécurisée, l’optimiseur Snowflake pourrait réorganiser les prédicats dans les clauses WHERE. Cela pourrait permettre au prédicat de la requête de l’utilisateur de s’exécuter en premier, ce qui permettrait à l’erreur de division par zéro de se produire.

Bonnes pratiques pour l’utilisation de vues sécurisées

Les vues sécurisées empêchent les utilisateurs d’être éventuellement exposés aux données des lignes de tables filtrées par la vue. Toutefois, il existe d’autres moyens par lesquels un propriétaire de données risque d’exposer par inadvertance des informations sur les données sous-jacentes si les vues ne sont pas correctement construites. Dans cette section, nous abordons certains pièges à éviter.

Pour illustrer ces pièges, nous utilisons les tables d’échantillon widgets et des vues définies dans les exemples précédents de ce chapitre.

Colonnes générées par séquence

Une pratique courante pour générer des clés de substitution est d’utiliser une séquence ou une colonne d’auto-incrémentation. Si ces clés sont exposées à des utilisateurs qui n’ont pas accès à toutes les données sous-jacentes, l’utilisateur pourrait deviner les détails de la distribution de données sous-jacente. Par exemple, widgets_view expose la colonne ID. Si un ID est généré à partir d’une séquence, alors un utilisateur de widgets_view pourrait déduire le nombre total de widgets créés entre les horodatages de création de deux widgets auxquels l’utilisateur a accès. Imaginez la requête et le résultat suivants :

select * from widgets_view order by created_on;

------+-----------------------+-------+-------+-------------------------------+
  ID  |         NAME          | COLOR | PRICE |          CREATED_ON           |
------+-----------------------+-------+-------+-------------------------------+
...
 315  | Small round widget    | Red   | 1     | 2017-01-07 15:22:14.810 -0700 |
 1455 | Small cylinder widget | Blue  | 2     | 2017-01-15 03:00:12.106 -0700 |
...
Copy

En se basant sur les résultats, l’utilisateur pourrait soupçonner que 1139 widgets (1455 - 315) ont été créés entre le 7 et le 15 janvier. Si ces informations sont trop sensibles pour être exposées aux utilisateurs d’une vue, vous pouvez utiliser l’une des options suivantes :

  • N’exposez pas la colonne générée par séquence dans le cadre de la vue.

  • Utilisez des identificateurs aléatoires (p. ex. générés par UUID_STRING) plutôt que des valeurs générées par séquence.

  • Floutez programmatiquement les identificateurs.

Taille des données analysées

Pour les requêtes contenant des vues sécurisées, Snowflake n’expose pas la quantité de données analysées (en termes d’octets ou de micro-partitions) ni la quantité totale de données. Le but est de protéger les informations des utilisateurs qui n’ont accès qu’à un sous-ensemble des données. Toutefois, les utilisateurs pourraient toujours être capables de faire des observations sur la quantité de données sous-jacentes en fonction des caractéristiques de performance des requêtes. Par exemple, une requête qui dure deux fois plus longtemps pourrait traiter deux fois plus de données. Bien que ces observations soient au mieux approximatives, il est préférable que ce genre d’informations ne soit pas exposé dans certains cas.

Dans ces cas, il est préférable de matérialiser les données par utilisateur/rôle plutôt que d’exposer aux utilisateurs les vues sur les données de base. Dans le cas de la table widgets, une table serait créée pour chaque rôle ayant accès aux widgets, ces rôles contenant uniquement les widgets accessibles par ce rôle, et un rôle aurait accès à leur table. Cela est beaucoup plus compliqué que d’utiliser une vue unique, mais pour les situations de très haute sécurité, cela peut être justifié.

Vues sécurisées et partage de données

Lorsque vous utilisez des vues sécurisées avec Secure Data Sharing, utilisez la fonction CURRENT_ACCOUNT pour autoriser les utilisateurs d’un compte spécifique à accéder aux lignes d’une table de base.

Note

Lorsque vous utilisez les fonctions CURRENT_ROLE et CURRENT_USER avec des vues sécurisées qui seront partagées avec d’autres comptes Snowflake, Snowflake renvoie une valeur NULL pour ces fonctions. La raison en est que le propriétaire des données partagées ne contrôle généralement pas les utilisateurs ou les rôles du compte avec lequel la vue est partagée.