Condiciones lógicas OR y AND de Apache con SetEnvIf.

Escrito el 2023-04-09 por Alberto Ferrer
Tiempo de lectura: 4 minuto(s)
Etiquetas: apache mod_setenvif

Desafortunadamente, el módulo Apache SetEnvIf no admite condiciones lógicas, como OR y AND. Específicamente, no es posible establecer una variable solo si se verifican condition1 Y/O condition2.

Por ejemplo, para registrar todas las consultas POST realizadas desde la interfaz de bucle local en un archivo de registro separado, no se puede hacer esto:

    CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
    SetEnvIf Remote_Addr "^127\.0\.0\.1$" AND Request_Method "POST" posting_myself

La primera línea es válida, solicita al servidor que registre todas las solicitudes en el archivo mencionado, solo si la variable de entorno posting_myself está establecida. La segunda línea intenta establecer la variable posting_myself si se cumplen dos condiciones (uso de un AND lógico), lo cual no es una sintaxis admitida.

En un primer intento de solucionar este problema, se me ocurrió esto (esto no funciona):

    CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
    SetEnv loopback_ip 0
    SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
    SetEnvIf Request_Method "POST" posting_myself
    SetEnvIf loopback_ip 0 !posting_myself
  1. La primera línea no cambia.
  2. La segunda línea establece incondicionalmente la variable loopback_ip en cero (lo que significa: falso).
  3. La tercera línea establece la misma variable en uno ("verdadero") si la solicitud realmente proviene de la dirección IP de bucle local.
  4. La cuarta línea establece la variable posting_myself en verdadero si el método de solicitud es POST.

Tenga en cuenta que en este punto, la variable posting_myself puede ser verdadera, incluso si alguien más hizo la solicitud. Esto se soluciona en la última línea, donde se anula posting_myself si la variable posting_myself es igual a cero (falso).

Después de la última línea, tendremos la variable posting_myself establecida solo si la solicitud proviene de la dirección IP de bucle local y si la solicitud es un POST. Desafortunadamente, esto tampoco funciona, por una razón sutil: según la documentación de Apache, la directiva SetEnv se ejecuta después de las directivas SetEnvIf. Esto significa que cuando SetEnv establece loopback_ip en cero, ya es demasiado tarde.

Por lo tanto, se me ocurrió esta otra versión para emular un AND lógico de SetEnvIf:

    CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
    SetEnvIf Remote_Addr "^" loopback_ip=0
    SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
    SetEnvIf Request_Method "POST" posting_myself
    SetEnvIf loopback_ip 0 !posting_myself

Esto es similar al intento anterior, solo que la segunda línea cambia: tengo que usar SetEnIfv para establecer artificialmente loopback_ip en cero, incondicionalmente. Para hacer esto, uso una expresión regular que siempre coincidirá con "^". Tenga en cuenta que usé Remote_Addr, pero también podría haber usado Request_Protocol, Request_URI o cualquier otra cosa: lo único importante es que siempre coincida y establezca loopback_ip en cero.

Ahora, para emular un SetEnvIf OR lógico, esto es mucho más fácil:

    SetEnvIf Remote_Addr "^192\.168\.0\." my_networks
    SetEnvIf Remote_Addr "^127\.0\.0\.1$" my_networks

Aquí, la variable my_networks se establecerá si la dirección remota comienza con "192.168.0." o es "127.0.0.1". Es así de simple. Bueno, podría haber utilizado una expresión regular más inteligente para hacer esto en una sola línea, ¡pero habría arruinado mi ejemplo de OR lógico! :)

Traducción fiel del artículo original escrito por Stéphane Lesimple.

Y aquí un extra escrito por su servidor:

Con el módulo SetEnvIf de Apache, las condiciones lógicas OR y AND se traducen como sigue:

OR (o): se usa el carácter "|" (pipe) para separar las expresiones. La variable se establece si se cumple al menos una de las expresiones. Por ejemplo:

      SetEnvIf Request_URI "^/admin" from_admin=1
      SetEnvIf Remote_Addr "192\.168\.0\." from_local=1
      SetEnvIf from_admin\|from_local "1" from_internal

En este ejemplo, la variable "from_admin" se establecerá si la solicitud tiene una URI que comienza con "/admin", y la variable "from_local" se establecerá si la dirección IP del cliente comienza con "192.168.0.". La variable "from_internal" se establecerá si alguna de las variables "from_admin" o "from_local" es igual a 1.

AND (y): se pueden utilizar múltiples directivas SetEnvIf para establecer varias variables y luego combinarlas con una expresión regular en una directiva SetEnvIfNoCase. Por ejemplo:

      SetEnvIf Request_URI "^/admin" from_admin=1
      SetEnvIf Remote_Addr "192\.168\.0\." from_local=1
      SetEnvIfNoCase from_admin from_local from_internal

En este ejemplo, se establece la variable "from_admin" si la solicitud tiene una URI que comienza con "/admin", y se establece la variable "from_local" si la dirección IP del cliente comienza con "192.168.0.". La variable "from_internal" se establece solo si ambas variables "from_admin" y "from_local" son iguales a 1.