Referencia del lenguaje de reglas personalizadas de Google Cloud Armor

Google Cloud Armor te permite definir reglas prioritarias con condiciones y acciones de coincidencia que se pueden configurar en una política de seguridad. Una regla entra en vigor, lo que significa que se aplica la acción configurada, si la regla es la regla de mayor prioridad cuyas condiciones coinciden con los atributos de la solicitud entrante.

Hay dos tipos de condiciones de coincidencias.

  • Una condición de coincidencia básica contiene listas de direcciones IP o listas de rangos de direcciones IP.
  • Una condición de coincidencia avanzada contiene una expresión con múltiples subexpresiones para coincidir en función de una variedad de atributos de una solicitud entrante.

El lenguaje de reglas personalizadas se usa a fin de escribir las expresiones en condiciones de coincidencia avanzadas para las reglas de políticas de seguridad. El lenguaje de reglas personalizadas de Google Cloud Armor es una extensión del Common Expression Language (CEL).

Una expresión requiere los siguientes dos componentes:

  • Atributos que se pueden inspeccionar en expresiones de reglas
  • Operaciones que se pueden realizar en los atributos como parte de una expresión

Por ejemplo, en la siguiente expresión, se usan los atributos origin.ip9.9.9.0/24 en la operación inIpRange(). En este caso, la expresión muestra un valor verdadero si origin.ip está dentro del rango de direcciones IP 9.9.9.0/24.

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

Atributos

Los atributos representan información de una solicitud entrante, como la dirección IP de origen o la ruta de URL solicitada.

Campo Tipo Descripción del campo
origin.ip string Es la dirección IP de origen de la solicitud.
request.headers mapa Es un mapa de string a string de los encabezados de solicitud HTTP. Si un encabezado contiene varios valores, el valor de este mapa es una string separada por comas de todos los valores del encabezado. Las claves en este mapa están en minúsculas. Solo se pueden inspeccionar los primeros 16 KB de cada valor de encabezado. Cualquier valor de encabezado superior a 16 KB se trunca según las especificaciones del balanceador de cargas de Google Cloud.
request.method string Es el método de solicitud HTTP, como GET o POST.
request.path string La ruta de URL HTTP solicitada.
request.scheme string Es el esquema de URL HTTP, como http o https. Todos los valores de este atributo están en minúsculas.
request.query string Es la consulta de URL HTTP en el formato name1=value&name2=value2, como aparece en la primera línea de la solicitud HTTP. No se realiza ninguna decodificación.
origin.region_code string Es el código de país de Unicode que está asociado a la IP de origen, como US. Si creas una regla o una expresión que usa códigos de país o región ISO 3166-1 alfa-2, Google Cloud Armor trata cada código de forma independiente. Las reglas y expresiones de Google Cloud Armor usan esos códigos de región de forma explícita para permitir o denegar solicitudes.

Para obtener más información, consulta unicode_region_subtag en el estándar técnico de Unicode.

origin.asn string El número de sistema autónomo (ASN) asociado con la dirección IP de origen. El ASN único a nivel global se determina en función del operador de red que admite los prefijos de direcciones IP que contienen la dirección IP de origen.

Operations

En la siguiente referencia, se describen los operadores que puedes usar con atributos (representados por xyk) para definir expresiones de reglas.

Expresiones Descripción
x == "foo" El resultado es verdadero si x es igual al literal de string constante determinado.
x == R"fo'o" El resultado es verdadero si x es igual al literal de string sin procesar determinado que no interpreta las secuencias de escape. Los literales de string sin procesar son convenientes para expresar strings que deben usar caracteres de secuencia de escape.
x == y Muestra TRUE si x es igual que y.
x != y Muestra TRUE si x no es igual que y.
x + y El resultado es la string concatenada xy.
x && y El resultado es verdadero si tanto xcomo y son verdaderos.
x || y El resultado es verdadero si x, y, o ambos son verdaderos.
!x El resultado es verdadero si el valor booleano x es falso. En cambio, el resultado es falso si el valor booleano x es verdadero.
x.contains(y) El resultado es verdadero si la string x contiene la substring y.
x.startsWith(y) El resultado es verdadero si la string x comienza con la substring y.
x.endsWith(y) El resultado es verdadero si la string x termina con la substring y.
x.matches(y) El resultado es verdadero si la string x coincide con el patrón RE2 y especificado. El patrón RE2 se compila con la opción RE2::Latin1 que inhabilita las funciones de Unicode.
inIpRange(x, y) Muestra true si la dirección IP x está incluida en el rango de IP y. Las máscaras de subred para las direcciones IPv6 no pueden ser mayores que /64.
x.lower() Muestra el valor de la string x en minúsculas.
x.upper() Muestra el valor de la string x en mayúsculas.
x.base64Decode() Muestra el valor decodificado en Base64 de x. A los caracteres _ - se los reemplaza primero por / +, respectivamente. Muestra "" (string vacía) si x no es un valor en Base64 válido.
has(m['k']) El resultado es verdadero si la clave k está disponible en el mapa m.
m['k'] Muestra el valor de la clave k en el mapa de string a string m si k está disponible; de lo contrario, muestra un error. El enfoque recomendado es verificar primero la disponibilidad mediante "has(m['k'])==true".
int(x) Convierte el resultado de la string de x en un tipo de int. Luego, se puede usar con el fin de hacer una comparación de números enteros mediante operadores aritméticos estándar como “>” y “<=”. Esto funciona solo para valores que deben ser enteros.

Expresiones de ejemplo

Para cada una de estas expresiones, la acción que se realiza depende de si la expresión se incluye en una regla de denegación o de admisión.

Permite o deniega el acceso según un rango de direcciones IP en IPv4 o IPv6

  • La siguiente expresión coincide con las solicitudes del rango de direcciones IP 9.9.9.0/24:

    inIpRange(origin.ip, '9.9.9.0/24')
    
  • La siguiente expresión coincide con las solicitudes del rango de direcciones IP 2001:db8::/32:

    inIpRange(origin.ip, '2001:db8::/32')
    
  • La siguiente expresión coincide con las solicitudes que tienen una cookie que tiene 80=BLAH.

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

Permite o deniega el tráfico con un encabezado referer que no esté vacío

  • La siguiente expresión coincide con las solicitudes que tienen un encabezado referer que no está vacío.

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

Permite o deniega el tráfico desde una región específica

Si tu aplicación web no está disponible en la región AU, todas las solicitudes de esa región deben bloquearse.

  • En una regla de rechazo, usa la siguiente expresión, que coincide con las solicitudes de la región AU:

    origin.region_code == 'AU'
    

Como alternativa, si tu aplicación web solo está disponible en la región AU, se deben bloquear las solicitudes de todas las demás regiones.

  • En una regla de denegación, usa la siguiente expresión, que coincide con las solicitudes de todas las regiones que no sean AU:

    origin.region_code != 'AU'
    

Los códigos de región se basan en los códigos ISO 3166-1 alfa-2. En algunos casos, una región corresponde a un país, pero no siempre es así. Por ejemplo, el código US incluye todos los estados de Estados Unidos, un distrito y seis áreas periféricas.

Permite o deniega el tráfico desde un ASN específico

Si tu aplicación web debe bloquearse para los clientes a los que presta servicio un operador de red específico, puedes usar el número ASN del operador de red para realizar el bloqueo.

  • En una regla de denegación, usa la siguiente expresión, que coincide con las solicitudes de un ASN específico:

    origin.asn == 123
    

Como alternativa, si tu aplicación web está solo disponible para los clientes detrás de un operador de red específico, deben bloquearse las solicitudes de todos los demás operadores de red.

  • En una regla de denegación, usa la siguiente expresión, que coincide con todos los demás operadores de red, excepto el que te interesa permitir.

    origin.asn != 123
    

Expresiones múltiples

Para incluir varias condiciones en una sola regla, combina varias subexpresiones.

  • En el siguiente ejemplo, las solicitudes de 1.2.3.0/24 (como tus verificadores Alfa) en la región AU coinciden con la siguiente expresión:

    origin.region_code == "AU" && inIpRange(origin.ip, '1.2.3.0/24')
    
  • La siguiente expresión coincide con las solicitudes de 1.2.3.4 en las que un usuario-agente contiene la string WordPress:

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

Permite o deniega el tráfico para un URI de solicitud que coincida con una expresión regular

  • La siguiente expresión coincide con las solicitudes que contienen la string bad_path en el URI:

    request.path.matches('/bad_path/')
    
  • La siguiente expresión coincide con las solicitudes que tienen Chrome en el campo de encabezado User-Agent:

    request.headers['user-agent'].matches('Chrome')
    
  • En la siguiente expresión, se muestra la coincidencia que no distingue entre mayúsculas y minúsculas para el encabezado User-Agent que contiene wordpress. Coincide con User-Agent:WordPress/605.1.15, User-Agent:wordPress y otras variantes de wordpress:

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

Permite o deniega el tráfico que contiene un valor decodificado en Base64 específico

  • La siguiente expresión coincide con las solicitudes que tienen un valor decodificado en Base64 de myValue para el encabezado user-id:

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

Permite o deniega el tráfico que tiene una content-length de cero en el cuerpo HTTP

  • La siguiente expresión coincide con las solicitudes que tienen un content-length de cero en el cuerpo HTTP:

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

Reglas preconfiguradas

Las reglas preconfiguradas usan firmas estáticas preconfiguradas, expresiones regulares o ambas para coincidir con los encabezados de solicitud HTTP y los parámetros de consulta. Las reglas preconfiguradas disponibles se basan en el conjunto de reglas principales de Modsecurity de OWASP versión 3.0.2. Google Cloud Armor proporciona estos conjuntos de expresiones predefinidos:

  • xss-<version>: defiende contra ataques de secuencias de comandos entre sitios
  • sqli-<version>: Defiende contra ataques de inserción de SQL
  • lfi-<version>: defiende contra ataques de inclusión de archivos locales
  • rfi-<version>: defiende contra ataques de inclusión de archivos remotos
  • rce-<version>: defiende contra ataques de ejecución de código remoto

Para obtener una lista de todas las reglas preconfiguradas disponibles, consulta Obtén una lista de las reglas preconfiguradas disponibles.

Para obtener más información sobre las reglas preconfiguradas, consulta el caso de uso Mitiga los ataques de la capa de la aplicación mediante reglas preconfiguradas.

Nombres de conjuntos de expresiones

Los nombres de los conjuntos de expresiones tienen el formato <attack category>-<version field>. La categoría de ataque especifica el tipo de ataques de lo que te quieres proteger, como xss (secuencias de comandos entre sitios) o sqli (inyección de SQL).

Los campos de versiones compatibles son stable y canary. Las adiciones y modificaciones a las reglas se publican primero en la versión canary. Cuando las incorporaciones y modificaciones se consideran seguras y estables, se ascienden a la versión stable.

ID de miembros del conjunto de expresiones

Un conjunto de expresiones contiene varias expresiones, cada una con su propio ID de conjunto de reglas principales (CRS). Por ejemplo, el conjunto de expresiones xss-stable incluye una expresión llamada owasp-crs-v020901-id981136-xss, que corresponde al ID de regla 981136 para la version 2.9.1. Puedes usar los ID de CRS para excluir el uso de expresiones específicas, lo que es útil si una expresión en particular siempre activa un falso positivo. Para obtener más información, consulta la información sobre solución de problemas de falsos positivos.

Para obtener información sobre el conjunto de reglas principales y el ajuste en diferentes niveles de sensibilidad, consulta Ajusta las reglas de WAF de Google Cloud Armor.

Operador para reglas preconfiguradas

Expresiones Descripción
evaluatePreconfiguredExpr(string, LIST)

El resultado es verdadero si alguna de las expresiones dentro del conjunto de expresiones especificado es verdadera.

El primer argumento es el nombre del conjunto de expresiones, como xss-stable. El segundo argumento (opcional) es una lista de string separada por comas de los ID que se debe excluir de la evaluación. La lista de exclusiones es útil cuando un miembro determinado del conjunto de expresiones activa un falso positivo.

Ejemplos de reglas preconfiguradas

  • En la siguiente expresión, se usa la regla preconfigurada xss-stable para mitigar los ataques de XSS:

    evaluatePreconfiguredExpr('xss-stable')
    
  • En la siguiente expresión, se usan todas las expresiones de la regla preconfigurada xss-stable, excepto los ID de miembro 981136981138:

    evaluatePreconfiguredExpr('xss-stable', ['owasp-crs-v020901-id981136-xss',
    'owasp-crs-v020901-id981138-xss'])
    
  • En la siguiente expresión, se usa una regla preconfigurada para mitigar los ataques de SQLi desde el rango de direcciones IP 198.51.100.0/24:

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

¿Qué sigue?