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 ?

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.

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 interrogations de données pour lesquelles les utilisateurs n’ont pas besoin de comprendre la représentation des données sous-jacente. En effet, l’optimiseur de requêtes Snowflake, lorsqu’il évalue les vues sécurisées, contourne certaines optimisations utilisées pour les vues classiques. Cela pourrait avoir des conséquences sur les performances des requêtes pour les vues 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 vous basant sur l’exemple de widget suivant, imaginez un utilisateur qui n’a accès qu’à un petit sous-ensemble de widgets, et que tous ces widgets sont 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;

Si widgets_view n’est pas une vue sécurisée, alors cette requête pourrait générer une erreur si un widget violet existe, même si l’utilisateur actuel n’a pas accès à ce widget. Notez que la génération d’erreurs dépend du fait que l’optimiseur de requêtes décide d’évaluer le filtre de l’utilisateur avant ou après le prédicat d’autorisation (dans la sous-requête IN). Si widgets_view est une vue sécurisée, l’optimiseur de requêtes n’évalue pas le filtre de l’utilisateur avant le prédicat d’autorisation.

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 :

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 :

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

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

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';

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';

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 :

Note

Cet exemple suppose que les tables widgets et widget_access_rules existent déjà. Il ne fournit pas la syntaxe pour créer les tables ou les remplir avec des données.

desc table widgets;

------------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+
    name    |       type        |  kind  | null? | default | primary key | unique key | check  | expression | comment |
------------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+
 ID         | NUMBER(38,0)      | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
 NAME       | VARCHAR(16777216) | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
 COLOR      | VARCHAR(16777216) | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
 PRICE      | NUMBER(38,0)      | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
 CREATED_ON | TIMESTAMP_LTZ(9)  | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
------------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+

desc table widget_access_rules;

-----------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+
   name    |       type        |  kind  | null? | default | primary key | unique key | check  | expression | comment |
-----------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+
 WIDGET_ID | NUMBER(38,0)      | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
 ROLE_NAME | VARCHAR(16777216) | COLUMN | Y     | [NULL]  | N           | N          | [NULL] | [NULL]     | [NULL]  |
-----------+-------------------+--------+-------+---------+-------------+------------+--------+------------+---------+

create or replace secure view widgets_view as
select w.*
from widgets w
where w.id in (select widget_id
               from widget_access_rules a
               where upper(role_name) = CURRENT_ROLE());

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 |
...

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 Partage des données sécurisé dans Snowflake, utilisez la fonction CURRENT_ACCOUNT pour autoriser les utilisateurs d’un compte spécifique à accéder aux lignes d’une table de base.

Note

Snowflake ne permet pas d’utiliser CURRENT_ROLE ou CURRENT_USER dans les vues sécurisées qui seront partagées avec d’autres comptes, puisque le propriétaire des données partagées ne contrôle généralement pas les rôles et les utilisateurs du compte avec lesquels elles sont partagées.