Documentation de référence sur le langage des règles personnalisées Google Cloud Armor

Google Cloud Armor vous permet de définir des règles priorisées avec des conditions de correspondance et des actions configurables dans une stratégie de sécurité. Une règle prend effet, ce qui signifie que l'action configurée est appliquée si la règle est la règle de priorité la plus élevée dont les conditions correspondent aux attributs de la requête entrante.

Il existe deux types de conditions de correspondance :

  • Une condition de correspondance de base contient des listes d'adresses IP ou des listes de plages d'adresses IP.
  • Une condition de correspondance avancée contient une expression comprenant plusieurs sous-expressions pour mettre en correspondance divers attributs d'une requête entrante.

Le langage des règles personnalisées est utilisé pour écrire les expressions dans des conditions de correspondance avancées pour les règles de stratégie de sécurité. Le langage des règles personnalisées Google Cloud Armor est une extension de Common Expression Language (CEL).

Une expression nécessite deux composants :

  • Des attributs, pouvant être inspectés dans les expressions de règle
  • Des opérations, pouvant être effectuées sur les attributs dans le cadre d'une expression

Par exemple, l'expression suivante utilise les attributs origin.ip et 9.9.9.0/24 dans l'opération inIpRange(). Dans ce cas, l'expression renvoie "true" si origin.ip est compris dans la plage d'adresses IP 9.9.9.0/24.

inIpRange(origin.ip, '9.9.9.0/24')

Attributs

Les attributs représentent des informations provenant d'une requête entrante, telles que l'adresse IP d'origine ou le chemin d'URL demandé.

Champ Type Description du champ
origin.ip chaîne Adresse IP source de la requête.
request.headers plan Mappage chaîne à chaîne des en-têtes de requête HTTP. Si un en-tête contient plusieurs valeurs, la valeur figurant dans ce mappage est une chaîne de toutes les valeurs de l'en-tête, séparées par des virgules. Les clés de ce mappage sont toutes en minuscules. Seuls les 16 premiers ko de chaque valeur d'en-tête sont disponibles pour inspection. Toute valeur d'en-tête supérieure à 16 ko est tronquée selon les spécifications de l'équilibreur de charge Google Cloud.
request.method chaîne Méthode de requête HTTP, telle que GET ou POST.
request.path chaîne Chemin d'URL HTTP demandé.
request.scheme chaîne Schéma d'URL HTTP, tel que http ou https. Les valeurs de cet attribut sont toutes en minuscules.
request.query chaîne Requête d'URL HTTP au format name1=value&name2=value2, telle qu'elle apparaît sur la première ligne de la requête HTTP. Aucun décodage n'est effectué
origin.region_code chaîne Code pays Unicode associé à l'adresse IP d'origine, tel que US. Si vous créez une règle ou une expression qui utilise des codes de pays ou de région ISO 3166-1 alpha-2, Google Cloud Armor traite chaque code indépendamment. Les règles et expressions Google Cloud Armor utilisent explicitement ces codes de région pour autoriser ou refuser des requêtes.

Pour plus d'informations, consultez la section unicode_region_subtag de la spécification Unicode Technical Standard.

origin.asn Entier Numéro ASN (Autonomous System Number) associé à l'adresse IP d'origine Le numéro ASN unique est déterminé en fonction de l'opérateur réseau qui accepte les préfixes d'adresse IP contenant l'adresse IP d'origine.

Attributs reCAPTCHA Enterprise

Cette section liste les attributs qui ne s'appliquent qu'aux jetons ou aux cookies d'exception reCAPTCHA Enterprise. Une sous-expression basée sur ces attributs renvoie false si le jeton ou le cookie d'exception reCAPTCHA à évaluer n'est pas disponible ou n'est pas valide (malformé, non concordant ou ayant expiré).

Champ Type Description du champ
token.recaptcha_exemption.valid bool Présence d'un cookie d'exception reCAPTCHA valide.

Attributs des jetons d'action

Champ Type Description du champ
token.recaptcha_action.score float Score d'un jeton d'action reCAPTCHA. Un score valide varie de 0.0 à 1.0, où 0.0 désigne très probablement un utilisateur illégitime et 1.0 désigne très probablement un utilisateur légitime.
token.recaptcha_action.captcha_status string État captcha d'un jeton reCAPTCHA. Un état valide est NONE, PASS ou FAIL, où NONE fait référence à l'absence de questions d'authentification lors de l'évaluation reCAPTCHA, de sorte que le champ captcha ne figure pas dans le jeton d'action.
token.recaptcha_action.action string Nom de l'action (jusqu'à 100 caractères) provenant d'un jeton d'action reCAPTCHA Enterprise. Consultez la section Noms des actions.
token.recaptcha_action.valid bool Présence d'un jeton d'action reCAPTCHA valide.

Attributs des jetons de session

Champ Type Description du champ
token.recaptcha_session.score float Score d'un jeton de session reCAPTCHA. Un score valide varie de 0.0 à 1.0, où 0.0 désigne très probablement un utilisateur illégitime et 1.0 désigne très probablement un utilisateur légitime.
token.recaptcha_session.valid bool Présence d'un jeton de session reCAPTCHA valide.

Opérations

La documentation de référence suivante décrit les opérateurs que vous pouvez utiliser avec des attributs (représentés par x, y et k) pour définir des expressions de règle.

Description Description
x == "foo" Renvoie "true" si x est égal au littéral de chaîne constante donné.
x == R"fo'o" Renvoie "true" si x est égal au littéral de chaîne brute donné qui n'interprète pas les séquences d'échappement. Les littéraux de chaîne brute sont pratiques pour exprimer des chaînes qui doivent elles-mêmes utiliser des caractères de séquence d'échappement.
x == y Renvoie "true" si x est égal à y.
x != y Renvoie "true" si x n'est pas égal à y.
x + y Renvoie la chaîne concaténée xy.
x && y Renvoie "true" si x et y sont vrais.
x || y Renvoie "true" si x, y ou les deux sont vrais.
!x Renvoie "true" si la valeur booléenne x est fausse ou renvoie "false" si la valeur booléenne x est vraie.
x.contains(y) Renvoie "true" si la chaîne x contient la sous-chaîne y.
x.startsWith(y) Renvoie "true" si la chaîne x commence par la sous-chaîne y.
x.endsWith(y) Renvoie "true" si la chaîne x se termine par la sous-chaîne y.
x.matches(y) Renvoie "true" si la chaîne x correspond au y du modèle RE2 spécifié. Le modèle RE2 est compilé à l'aide de l'option RE2::Latin1 qui désactive les fonctionnalités Unicode.
inIpRange(x, y) Renvoie la valeur "true" si l'adresse IP x est comprise dans la plage d'adresses IP y. Les masques de sous-réseau des adresses IPv6 ne peuvent pas être supérieurs à /64.
x.lower() Renvoie la valeur en minuscules de la chaîne x.
x.upper() Renvoie la valeur en majuscules de la chaîne x.
x.base64Decode() Renvoie la valeur décodée en base64 de x. Les caractères _ - sont d'abord remplacés par / + respectivement. Renvoie "" (chaîne vide) si x n'est pas une valeur base64 valide.
has(m['k']) Renvoie "true" si la clé k est disponible dans le mappage m.
m['k'] Renvoie la valeur à la clé k dans le mappage chaîne à chaîne m si k est disponible. Sinon, renvoie une erreur. L'approche recommandée consiste à vérifier d'abord la disponibilité à l'aide de "has(m['k'])==true".
int(x) Convertit le résultat de chaîne de x en type int. Il peut ensuite être utilisé pour établir une comparaison d'entiers à l'aide d'opérateurs arithmétiques standards tels que ">" et "<=". Cela ne fonctionne que pour les valeurs qui sont supposées être des entiers.

Exemples d'expressions

Pour chacune de ces expressions, l'action entreprise varie selon que l'expression est incluse dans une règle de refus ou d'autorisation.

Autoriser ou refuser l'accès en fonction d'une plage d'adresses IP en IPv4 ou IPv6

  • L'expression suivante correspond aux requêtes provenant de la plage d'adresses IP 9.9.9.0/24 :

    inIpRange(origin.ip, '9.9.9.0/24')
    
  • L'expression suivante correspond aux requêtes provenant de la plage d'adresses IP 2001:db8::/32 :

    inIpRange(origin.ip, '2001:db8::/32')
    
  • L'expression suivante correspond aux requêtes qui présentent un cookie contenant 80=BLAH :

    has(request.headers['cookie']) && request.headers['cookie'].contains('80=BLAH')
    

Autoriser ou refuser le trafic avec un en-tête referer non vide

  • L'expression suivante correspond aux requêtes qui ont un en-tête referer non vide :

    has(request.headers['referer']) && request.headers['referer'] != ""
    

Autoriser ou refuser le trafic en fonction de l'URL de l'hôte dans l'en-tête

  • L'expression suivante correspond aux requêtes adressées à une URL spécifique :

    request.headers['host'].lower().contains('test.example.com')
    

Autoriser ou refuser le trafic provenant d'une région spécifique

Si votre application Web n'est pas disponible dans la région AU, toutes les requêtes provenant de cette région doivent être bloquées.

  • Dans une règle de refus, utilisez l'expression suivante, qui correspond aux requêtes de la région AU :

    origin.region_code == 'AU'
    

Si votre application Web est exclusivement disponible dans la région AU, les requêtes provenant de toutes les autres régions doivent être bloquées.

  • Dans une règle de refus, utilisez l'expression suivante pour faire correspondre les requêtes de toutes les régions autres que la région AU :

    origin.region_code != 'AU'
    

Les codes de région sont basés sur les codes ISO 3166-1 alpha-2. Dans certains cas, une région correspond à un pays, mais ce n'est pas toujours le cas. Par exemple, le code US comprend tous les États des États-Unis, un district et six zones périphériques.

Autoriser ou refuser le trafic provenant d'un numéro ASN spécifique

Si votre application Web doit être bloquée pour les clients desservis par un opérateur réseau spécifique, vous pouvez utiliser le numéro ASN de l'opérateur réseau à bloquer.

  • Dans une règle de refus, utilisez l'expression suivante, qui identifie les requêtes provenant d'un numéro ASN spécifique :

    origin.asn == 123
    

Si votre application Web doit être exclusivement disponible pour les clients situés derrière un opérateur réseau spécifique, les requêtes de tous les autres opérateurs réseau doivent être bloquées.

  • Dans une règle de refus, utilisez l'expression suivante, qui identifie tous les autres opérateurs réseau autres que celui que vous souhaitez autoriser.

    origin.asn != 123
    

Expressions multiples

Pour inclure plusieurs conditions dans une seule règle, combinez plusieurs sous-expressions.

  • Dans l'exemple suivant, les requêtes provenant de 1.2.3.0/24 (comme vos testeurs alpha) dans la région AU correspondent à l'expression suivante :

    origin.region_code == "AU" && inIpRange(origin.ip, '1.2.3.0/24')
    
  • L'expression suivante correspond aux requêtes provenant de 1.2.3.4 où un en-tête user-agent contient la chaîne WordPress :

    inIpRange(origin.ip, '1.2.3.4/32') &&
    has(request.headers['user-agent']) && request.headers['user-agent'].contains('WordPress')
    

Autoriser ou refuser le trafic pour un URI de requête qui correspond à une expression régulière

  • L'expression suivante correspond aux requêtes dont l'URI contient la chaîne bad_path :

    request.path.matches('/bad_path/')
    
  • L'expression suivante correspond aux requêtes dont le champ d'en-tête User-Agent contient Chrome :

    request.headers['user-agent'].matches('Chrome')
    
  • L'expression suivante montre une correspondance non sensible à la casse pour l'en-tête User-Agent contenant wordpress. Elle correspond à User-Agent:WordPress/605.1.15, User-Agent:wordPress et d'autres variantes de wordpress :

    request.headers['user-agent'].matches('(?i:wordpress)')
    

Autoriser ou refuser le trafic contenant une valeur décodée en base64 spécifique

  • L'expression suivante correspond aux requêtes qui ont la valeur décodée en base64 myValue pour l'en-tête user-id :

    has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')
    

Autoriser ou refuser le trafic dont le corps HTTP contient un en-tête content-length nul

  • L'expression suivante correspond aux requêtes dont le corps HTTP contient un en-tête content-length nul :

    int(request.headers["content-length"]) == 0
    

Règles préconfigurées

Les règles préconfigurées utilisent des signatures statiques préconfigurées, des expressions régulières ou les deux pour mettre en correspondance les en-têtes de requête HTTP et les paramètres de requête. Les règles préconfigurées disponibles sont basées sur l'ensemble de règles de base OWASP ModSecurity version 3.0.2. Google Cloud Armor fournit ces ensembles d'expressions prédéfinis :

  • xss-<version> : défense contre les attaques par script intersites
  • sqli-<version> : défense contre les attaques par injection SQL
  • lfi-<version> : défense contre les attaques par inclusion de fichiers locaux
  • rfi-<version> : défense contre les attaques par inclusion de fichiers distants ;
  • rce-<version> : défense contre les attaques par exécution de code à distance

Pour répertorier toutes les règles préconfigurées disponibles, consultez la section Répertorier les règles préconfigurées disponibles.

Pour plus d'informations sur les règles préconfigurées, consultez le cas d'utilisation Atténuer les attaques de couche d'application à l'aide de règles préconfigurées.

Noms des ensembles d'expressions

Les noms des ensembles d'expressions ont le format <attack category>-<version field>. La catégorie d'attaque spécifie le type d'attaques contre lesquelles vous souhaitez vous protéger, comme xss (script intersites) ou sqli (injection SQL).

Les champs de version compatibles sont stable et canary. Les ajouts et changements effectués dans les règles sont d'abord publiés dans la version canary. Lorsque des ajouts et des changements sont considérés comme sûrs et stables, ils sont promus vers la version stable.

ID de membre de l'ensemble d'expressions

Un ensemble d'expressions contient plusieurs expressions, chacune ayant son propre ID d'ensemble de règles de base (CRS, Core Rule Set). Par exemple, l'ensemble d'expressions xss-stable inclut une expression appelée owasp-crs-v020901-id981136-xss, qui correspond à l'ID de règle 981136 pour version 2.9.1. Vous pouvez utiliser les ID de CRS pour empêcher l'utilisation d'expressions spécifiques, ce qui est utile si une expression particulière déclenche systématiquement un faux positif. Pour plus d'informations, consultez les informations de dépannage concernant les faux positifs.

Pour plus d'informations sur l'ensemble de règles de base et l'ajustement à différents niveaux de sensibilité, consultez la page Ajuster les règles WAF Google Cloud Armor.

Opérateur pour les règles préconfigurées

Description Description
evaluatePreconfiguredExpr(string, LIST)

Renvoie "true" si l'une des expressions figurant dans l'ensemble d'expressions spécifié renvoie "true".

Le premier argument est le nom de l'ensemble d'expressions, tel que xss-stable. Le deuxième argument (facultatif) est une liste d'ID sous forme de chaînes séparées par des virgules, qui doivent être exclues de l'évaluation. La liste d'exclusion est utile lorsqu'un membre donné de l'ensemble d'expressions déclenche un faux positif.

Exemples de règles préconfigurées

  • L'expression suivante utilise la règle préconfigurée xss-stable pour atténuer les attaques XSS :

    evaluatePreconfiguredExpr('xss-stable')
    
  • L'expression suivante utilise toutes les expressions de la règle préconfigurée xss-stable, à l'exception des ID membres 981136 et 981138 :

    evaluatePreconfiguredExpr('xss-stable', ['owasp-crs-v020901-id981136-xss',
    'owasp-crs-v020901-id981138-xss'])
    
  • L'expression suivante utilise une règle préconfigurée pour atténuer les attaques SQLi à partir de la plage d'adresses IP 198.51.100.0/24 :

    inIpRange(origin.ip, '198.51.100.0/24') && evaluatePreconfiguredExpr('sqli-stable')
    

Étape suivante