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 ayant la priorité la plus élevée lorsque les attributs de la requête entrante correspondent à ceux exprimés dans la condition de correspondance de la règle.

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.

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'] != ""
    

Refuser le trafic provenant d'une région spécifique

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

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

    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.

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.1. Google Cloud Armor fournit deux 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

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

Étapes suivantes