--[ Apache et la gestion des modules : application à l'intégration Apache/Tomcat ]--
1. Introduction
Cette brève aborde la gestion des modules dans le serveur Apache, dans
les branches 1.3 et 2.0, et plus particulièrement sous l'angle des
interférences entre les modules agissant sur l'URI d'une requête simple
-- qu'il s'agisse de déterminer la ressource locale associée à cette
URI, ou encore d'effectuer des opérations de filtrage (mod_security), de
r[é]écriture (mod_rewrite) et, optionnellement, de relayage (mod_proxy,
mod_jk).
La configuration étudiée dans cette brève sera constituée d'un Apache
associé à un conteneur de servlets/JSP Tomcat, par l'intermédiaire d'un
connecteur AJP13 (mod_jk). Des opérations de réécriture et de filtrage
seront effectuées au niveau du serveur Apache -- dont le fonctionnement
sera, dans cette configuration, proche de celui d'un relais-inverse HTTP
filtrant.
2. Interactions entre modules (Apache 1.3)
2.1. Fonctionnement des modules
Le serveur HTTP Apache (http://httpd.apache.org) bénéficie d'une
architecture modulaire, et chaque module additionnel peut intervenir au
cours de la phase de traitement des requêtes transmises au serveur. Le
traitement d'une requête HTTP suit approximativement le cheminement
suivant :
· Lecture de la requête, des en-têtes
Détermination de l'hôte virtuel
· Interprétation de l'URI
Traduction en nom d'objet local : étape URI-to-Filename
· Contrôle d'accès utilisateur (mod_auth.c par exemple)
Authentification (AuthType)
Autorisation (Require)
· Contrôle d'accès (mod_access.c par exemple)
Allow, deny
· Détermination du type MIME de l'objet demandé
· Mises au point (Fixup)
· Envoi de la réponse au client
· Journalisation
Pour rappel, une requête HTTP prend la forme suivante :
GET / HTTP/1.1.
Host: localhost.
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031225 Firebird/0.7.
Accept: text/xml,application/xml,application/xhtml+xml [...]
Accept-Language: en-us,en;q=0.5.
Accept-Encoding: gzip,deflate.
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7.
Keep-Alive: 300.
Connection: keep-alive.
Le traitement s'effectue sur la base cette requête, de la socket TCP
sous-jacente (adresses IP, ports TCP) voire de la session SSL/TLS
négociée, le cas échéant (certificat client si présenté pour une
authentification au niveau SSL/TLS, SESSIONID, protocole, triplet
d'algorithmes etc.).
À chacune de ces étapes, les différents modules sont successivement
sollicités pour prendre en charge une étape du traitement d'une requête,
suivant l'algorithme simplifié ci-dessous (extrait de mod_rewrite.c) :
while(request or subrequest)
foreach(stage #0...#9)
foreach(module) (**)
try to run hook
Par défaut, l'ordre des modules est déterminé par leur ordre de
compilation (modifiable via la directive « --permute-module ») : leur
chargement est réalisé dans l'ordre inverse de l'ordre de compilation.
Prenons le binaire httpd suivant :
$ ./httpd -l
Compiled-in modules:
http_core.c
mod_env.c
mod_log_config.c
mod_mime.c
mod_status.c
mod_info.c
mod_dir.c
mod_cgi.c
mod_alias.c
mod_rewrite.c
mod_access.c
mod_auth.c
mod_proxy.c
mod_so.c
mod_setenvif.c
mod_ssl.c
mod_jk.c
Dans le cas présent, l'ordre est donc le suivant :
1: mod_jk.c, 2: mod_ssl.c, 3: mod_setenvif.c ... 8: mod_rewrite.c ...
Le module qui prend la main le premier est par conséquent mod_jk, et le
dernier module appelé est mod_env.c, qui laisse finalement la main à
http_core.c (qui ne peut d'ailleurs être compilé que de façon statique).
La liste des modules chargés peut être modifiée et augmentée à
l'exécution, via le fichier de configuration httpd.conf par la directive
LoadModule du module mod_so (compilé statiquement) qui permet de
déclarer les modules dynamiques (.so) disponibles.
Le module mod_gzip est, par exemple (il s'agira du seul module dynamique
présent dans cet exemple), ainsi chargé :
LoadModule gzip_module libexec/mod_gzip.so
Les modules sont, comme précédemment, chargés dans l'ordre inverse de
leur déclaration -- et les modules déclarés par LoadModule prennent la
main avant tout module compilé statiquement, par défaut. Ainsi, dans la
configuration prise pour exemple, les modules successivement sollicités
sont les suivants, après ajout de la directive LoadModule :
1. mod_gzip.c
2. mod_jk.c
3. mod_ssl.c
4. mod_setenvif.c
5. mod_so.c
6. mod_proxy.c
7. mod_auth.c
8. mod_access.c
9. mod_rewrite.c
[...]
Cette liste est vérifiable à l'aide du module server-info, autorisé
uniquement localement, permettant de connaître la configuration du
serveur à l'exécution :
SetHandler server-info
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
La recherche des modules chargés (indiqués par le nom « Module Name »)
est facilement obtenue, de même que leur ordre de chargement :
$ w3m -dump http://127.0.0.1/server-info | grep "Module Name"
Finalement, l'ordonnancement des modules statiques ou dynamiques (sans
distinction) peut être modifié à l'exécution par la directive AddModule.
Dans ce cas, le _dernier_ module ajouté est le _premier_ à prendre la
main.
La directive AddModule a pour fonction d'« empiler » les modules
(modules dynamiques déclarés par LoadModule + modules statiques du
binaire monolithique httpd). La directive AddModule doit être précédée
de la directive ClearModuleList.
Remarque : outre l'ordonnancement de modules, cette directive permet de
ne pas activer, à l'exécution, des modules compilés statiquement (afin
de ne pas recompiler le binaire httpd, typiquement).
En conservant l'ordonnancement actuel (qui sera rectifié
ultérieurement), la configuration à adopter serait par conséquent la
suivante :
8< --------------------------------------------------------
# Chargement du module dynamique mod_gzip par mod_so (compile
# statiquement pour initier le processus)
LoadModule gzip_module libexec/mod_gzip.so
# Reinitialisation de la liste des modules charges
ClearModuleList
# Empilement des modules a activer -- en commençant par le dernier
AddModule mod_env.c
AddModule mod_log_config.c
AddModule mod_mime.c
# AddModule mod_status.c
AddModule mod_info.c
AddModule mod_dir.c
AddModule mod_cgi.c
AddModule mod_alias.c
AddModule mod_rewrite.c
AddModule mod_access.c
AddModule mod_auth.c
AddModule mod_proxy.c
AddModule mod_so.c
AddModule mod_setenvif.c
AddModule mod_ssl.c
AddModule mod_jk.c
AddModule mod_gzip.c
8< --------------------------------------------------------
La bonne compréhension du chargement des modules est cruciale pour
obtenir une configuration exempte d'erreurs, le cas contraire pouvant
typiquement conduire à des attaques par déni de service ou encore
permettant d'accéder à des fichiers interprêtés en temps normal - dans
le cas de mod_rewrite notamment.
2.2. Interférences entre modules : mod_jk et mod_rewrite
Dans cette partie, on considère un serveur Apache communiquant avec un
serveur Tomcat en AJP13, par l'intermédiaire du module mod_jk (1.x).
Ce relais-inverse HTTP est susceptible d'effectuer une réécriture (voire
du filtrage) sur les paramètres qu'il transmet au conteneur de servlets
et JSP Tomcat -- typiquement pour éviter des URL du type "(%3f|?).jsp$".
Le choix d'un connecteur AJP13 offre, par rapport au relayage HTTP, la
possibilité de transmettre au serveur Tomcat les paramètres de session
SSL/TLS, l'adresse IP du client initial etc. ; de plus les requêtes AJP
sont effectuées sur des connexions TCP persistantes -- offrant un gain en
performances certain par rapport à un relayage HTTP plus traditionnel.
Pour résumer : il vaut mieux préférer la combinaison mod_jk + connecteur
AJP1x à la combinaison mod_proxy + connecteur HTTP, pour de multiples et
bonnes raisons.
2.2.1. Description du problème
Considérons l'hôte virtuel suivant, configuré au niveau du serveur
précédent (configuration respectant la syntaxe mod_jk 1.x) :
[...]
JkMount /appli/* ajp13
[...]
Toute requête destinée à l'URI correspondant au motif « /appli/* » est
transmise au serveur Tomcat, « directement », en AJP13.
Dans la configuration actuelle, avec l'ordonnancement des modules vu
précédemment, aucune réécriture n'est donc possible pour mod_rewrite :
mod_jk prend la main _avant_ mod_rewrite (il s'agit d'un module tier,
compilé a posteriori et par conséquent chargé en dernier lieu, car
ajouté en fin de liste dans le fichier de configuration httpd.conf).
Plus précisément, à l'examen des sources de ces modules, on constate une
interférence au niveau de la phase de traduction de l'URI vers un nom de
fichier (lors de l'étape dite de traduction « URI-to-Filename », d'après
ce qui a été précédemment décrit) :
Au niveau de mod_rewrite :
NULL /* [#0] post read-request */
hook_uri2file, /* [#1] URI to filename translation */
NULL, /* [#2] header parser */
NULL, /* [#3] check access by host address */
NULL, /* [#4] validate user id from request */
NULL, /* [#5] check if the user is ok _here_ */
hook_mimetype, /* [#6] determine MIME type */
hook_fixup, /* [#7] pre-run fixups */
handler_table, /* [#8] MIME-typed-dispatched handlers */
NULL, /* [#9] log a transaction */
Au niveau de mod_jk :
NULL /* [1] post read_request handling */
jserv_translate_handler, /* [2] filename-to-URI translation */
NULL, /* [3] header parser */
NULL, /* [4] check access by host address */
NULL, /* [5] check/validate user_id */
NULL, /* [6] check user_id is valid *here* */
jserv_type_match, /* [7] MIME type checker/setter */
NULL, /* [8] fixups */
NULL, /* [10] logger */
Les deux modules interviennent donc simultanément lors des phases « URI
to filename translation ».
Par défaut, si un des modules prend la main pour ce hook, aucun autre
module lors de la même étape de traitement ne pourra intervenir (sauf
artifice, qui sera abordé ultérieurement). Dans la configuration
actuelle, toute URI de type « /appli/* » sera donc interceptée et
traitée par mod_jk, et aucune réécriture ne sera dès lors envisageable
par la suite par mod_rewrite.
Il est recommandé par conséquent de charger le module mod_jk _avant_
mod_rewrite, via la directive AddModule, de sorte que mod_rewrite puisse
réécrire les URI à destination du serveur Tomcat. Néanmoins, en accord
avec ce qui a été vu précédemment, on comprend bien que mod_jk ne
prendra plus la main sur ces requêtes, ce qui est d'autant plus
gênant... Heureusement, une « astuce » de configuration permet de passer
outre, et de permettre la manipulation d'une requête à la fois par
mod_rewrite _puis_ par mod_jk.
Ce réordonnancement se fait ainsi :
8< --------------------------------------------------------
ClearModuleList
AddModule mod_env.c
AddModule mod_log_config.c
AddModule mod_mime.c
AddModule mod_dir.c
AddModule mod_cgi.c
AddModule mod_alias.c
AddModule mod_jk.c # <---
AddModule mod_rewrite.c # |
AddModule mod_access.c # |
AddModule mod_auth.c # |
AddModule mod_proxy.c # |
AddModule mod_so.c # |
AddModule mod_setenvif.c # |
AddModule mod_ssl.c # |
# AddModule mod_jk.c # ----
AddModule mod_gzip.c
8< --------------------------------------------------------
En pratique, l'ordonnancement des modules standards est le résultat du
travail de l'équipe de développement du projet Apache. Il est donc
recommandé de déplacer le module tier mod_jk, et non le module standard
mod_rewrite.
Deux scénarii sont alors envisageables, et se distinguent par les flags
mod_rewrite requis :
1. Interception d'un URI et réécriture par mod_rewrite, puis redirection
interne vers une URI locale (classique) ;
2. Interception d'une URI et réécriture par mod_rewrite, _puis_
interprétation par mod_jk -- et par Tomcat, par extension.
Ces cas sont traités dans les parties suivantes.
2.2.2. Exemple n°1 : indexation Tomcat
L'exemple abordé ici sera celui de la désactivation (au niveau du
serveur Apache) de l'indexation réalisée au niveau du serveur Tomcat :
-----------------------------------------------------------------------
Directory Listing For /
Filename Size Last Modified
[...]
Apache Tomcat/4.0.2
-----------------------------------------------------------------------
Cette page est générée par le serveur Tomcat. L'idée est donc
d'effectuer une redirection interne de « ^/appli/$ » vers l'URI locale «
/index.html » : ainsi, une requête sur https://192.168.0.1/appli/
aboutira sur la page index.html locale au serveur Apache, et non plus à
la page d'indexation générée par le serveur Tomcat.
La configuration peut se faire simplement de la façon suivante (après
modification de l'ordre de chargement des modules, comme précédemment
évoqué) :
8< --------------------------------------------------------
[...]
RewriteEngine On
RewriteLogLevel 3
RewriteLog /var/log/apache/rewrite.log
RewriteRule ^/appli/$ /index.html [L]
JkMount /appli/* ajp13
[...]
8< --------------------------------------------------------
Il est par ailleurs recommandé de privilégier les redirections internes
aux redirections « externes » (caractérisées par le flag [R]).
Dans les journaux, on obtiendrait alors :
(2) init rewrite engine with requested uri /appli/
(3) applying pattern '^/appli/$' to uri '/appli/'
(2) rewrite /appli/ -> /index.html
(2) local path result: /index.html
(2) prefixed with document_root to /appli/www/appli/htmldocs/index.html
(1) go-ahead with /appli/www/appli/htmldocs/index.html [OK]
Une ressource locale est servie pour /appli/. En revanche, les autres
URI préfixées par /appli/ sont effectivement transmises au serveur
Tomcat.
2.2.3. Exemple n°2 : filtrage sur la requête simple par mod_rewrite
Dans ce second cas, mod_rewrite doit prendre la main lors de la phase de
traduction « URI to filename », puis laisser la main à mod_jk sur l'URI
récrite pour une _nouvelle _ phase de traduction « URI to filename ».
Ce qui est problématique d'après ce qui a été précédemment vu : ce
fonctionnement n'est initialement pas prévu par Apache, un seul module
pouvant intervenir activement lors d'une étape donnée du traitement
d'une URI. Cependant mod_rewrite dispose d'un flag [PT] (Pass Through)
faisant que mod_rewrite répond par un DECLINED au noyau Apache
(http_core.c), et laisse la main au handler du module suivant : mod_jk
dans le cas qui nous intéresse.
La configuration peut se faire de la façon suivante :
8< --------------------------------------------------------
[...]
RewriteEngine On
RewriteLogLevel 3
RewriteLog /var/log/apache/rewrite.log
RewriteRule ^/appli/page1.html /appli/page2.html [PT]
JkMount /appli/* ajp13
[...]
8< --------------------------------------------------------
Le résultat produit est le suivant :
(2) init rewrite engine with requested uri /appli/page1.html
(3) applying pattern '^/appli/$' to uri '/appli/page1.html'
(3) applying pattern '^/appli/page1.html' to uri '/appli/page1.html'
(2) rewrite /appli/page1.html -> /appli/page2.html
(2) forcing '/appli/page2.html' to get passed through to next API URI-to-filename
handler
L'URI récrite « /appli/page2.html » est alors passée au handler «
URI-to-filename » du module suivant immédiatement, et actif pour cette
étape, autrement dit celui de mod_jk (qui va transmettre la requête
ainsi récrite au serveur Tomcat).
Cette réécriture pourrait consister en un filtrage de paramètres
minimaliste. Le filtrage de paramètres par mod_rewrite souffre néanmoins
d'une limitation : il peut uniquement être effectué sur la QUERY_STRING
et sur des requêtes qui ne sont pas des sous-requêtes (la structure de
sous-requête Apache, pour une sous-requête lancée suite à une
redirection interne par exemple, comporte un champ QUERY_STRING vide),
dans la mesure où mod_rewrite agit uniquement sur la requête simple et
ses entêtes.
Il n'est en particulier pas en mesure d'agir sur le corps des requêtes,
autrement dit sur les paramètres passés par la méthode POST.
Le module mod_security sera, à cet effet, évoqué dans la partie
suivante.
Un exemple de filtrage de paramètres est envisageable comme suit :
8< --------------------------------------------------------
[...]
RewriteEngine On
RewriteLogLevel 3
RewriteLog /var/log/apache/rewrite.log
RewriteCond %{REQUEST_URI} ^/appli/myservlet$
RewriteCond %{QUERY_STRING} !^param1=[0-9a-zA-Z]{1,5}\¶m2=[0-9]{1,3}$
RewriteRule .* - [F]
JkMount /appli/* ajp13
[...]
8< --------------------------------------------------------
Dans ce cas, les prototypes des paramètres sont explicitement définis
par les expressions régulières de la seconde condition déclenchant la
règle de réécriture. Si les paramètres passés ne respectent pas ce
paramètre, un « forbidden » sera envoyé en réponse par le serveur
Apache, dans cet exemple. Pour effectuer le test, on pourra par exemple
utiliser le wrapper GET du toolkit LWP, extrêmement pratique pour
réaliser ce type de test (de façon similaire, la commande POST permet de
générer des requêtes dont les paramètres sont soumis par le corps du
message, le calcul de la longueur des données envoyées étant géré par le
programme).
3. Combinaison mod_jk/mod_rewrite/mod_security
3.1. Installation
L'installation se fera sur la base de :
- Apache 1.3.19 + mod_ssl 2.8.16, avec mod_rewrite compilé
dynamiquement, et support du programme apxs(8) ;
- Installation de mod_jk 1.2 et mod_security 1.7.4 a posteriori avec
apxs(8) ;
Tous les modules compilés le seront dynamiquement.
- Installation du serveur Apache + mod_ssl :
/usr/local/src/build > tar zxvf ../archives/apache_1.3.29.tar.gz
/usr/local/src/build > tar zxvf ../archives/mod_ssl-2.8.16-1.3.29.tar.gz
/usr/local/src/build > cd mod_ssl-2.8.16-1.3.29/
/usr/local/src/build/mod_ssl-2.8.16-1.3.29 > ./configure --with-apache=../apache_1.3.29/
/usr/local/src/build/mod_ssl-2.8.16-1.3.29 > cd ../apache_1.3.29/
/usr/local/src/build/apache_1.3.29 > SSL_BASE=SYSTEM ./configure --disable-module=userdir \
--disable-module=autoindex \
--disable-module=include \
--disable-module=cgi \
--disable-module=actions \
--disable-module=imap \
--disable-module=env \
--disable-module=negotiation \
--disable-module=asis \
--disable-module=alias \
--enable-module=ssl \
--enable-module=rewrite \
--enable-module=proxy \
--enable-shared=max \
--prefix=/usr/local/stow/apache13/
/usr/local/src/build/apache_1.3.29 > make
/usr/local/src/build/apache_1.3.29 > make certificate
/usr/local/src/build/apache_1.3.29 > sudo make install
Au final, le binaire httpd comporte uniquement les modules http_core.c
et mod_so.c compilés statiquement (httpd -l), strictement nécessaires au
chargement des modules dynamiques.
Remarque : mod_jk a une dépendance sur mod_dir. Il ne faut donc _pas_
désactiver complètement le module mod_dir, et le déclarer (via
LoadModule) _avant_ mod_jk, sans pour autant l'activer via AddModule à
l'éxecution... Quant à mod_setenvif, il est nécessaire pour modifier le
comportement de mod_ssl suivant le navigateur utilisé (IE et les
messages d'alerte SSL/TLS...).
- Installation de mod_security 1.7.4 :
Le module est téléchargeable depuis l'adresse suivante :
http://www.modsecurity.org/
L'installation est réalisée avec apxs(8) :
/usr/local/src/build > tar zxvf ../archives/mod_security-1.7.4.tar.gz
/usr/local/src/build > cd mod_security-1.7.4
/usr/local/src/build/mod_security-1.7.4 > sudo /usr/local/stow/apache13/bin/apxs -cia apache1/mod_security.c
Le module mod_security est alors activé dans httpd.conf (en fin de liste
par défaut, ce qui n'est pas problématique, comme on le verra dans la
partie suivante).
- Installation de mod_jk (1.2) :
Le module est téléchargeable depuis l'adresse suivante :
http://jakarta.apache.org/site/sourceindex.cgi
La compilation (avec apxs(8)) suit le processus :
/usr/local/src/build > tar zxvf ../archives/jakarta-tomcat-connectors-jk-1.2-src-current.tar.gz
/usr/local/src/build > cd jakarta-tomcat-connectors-jk-1.2.5-src
..ld/jakarta-tomcat-connectors-jk-1.2.5-src > cd jk/native
..ta-tomcat-connectors-jk-1.2.5-src/jk/native > ./configure --with-apxs=/usr/local/stow/apache13/bin/apxs
..ta-tomcat-connectors-jk-1.2.5-src/jk/native > sudo cp apache-1.3/mod_jk.so /usr/local/stow/apache13/libexec
Au niveau de la configuration, s'appuyer sur ce qui a été vu dans les
parties précédentes, au niveau de la déclaration (LoadModule) et de
l'ordonnancement (AddModule).
3.2. Configuration
Au niveau de la configuration Apache à proprement parler, on prendra
soin de positionner les directives suivantes -- en tout premier lieu :
ServerTokens Prod
ServerSignature Off
Par rapport à la configuration mod_rewrite/mod_jk, peu de choses sont à
ajouter -- les étapes sur lesquelles le module mod_security intervient
sont en effet les suivantes :
module MODULE_VAR_EXPORT security_module = {
STANDARD_MODULE_STUFF,
sec_init, /* module initializer */
sec_create_dir_config, /* create per-dir config structures */
sec_merge_dir_config, /* merge per-dir config structures */
sec_create_srv_config, /* create per-server config structures */
NULL, /* merge per-server config structures */
sec_cmds, /* table of config file commands */
NULL, /* [#8] MIME-typed-dispatched handlers */
NULL, /* [#1] URI to filename translation */
NULL, /* [#4] validate user id from request */
NULL, /* [#5] check if the user is ok _here_ */
NULL, /* [#3] check access by host address */
NULL, /* [#6] determine MIME type */
sec_check_access, /* [#7] pre-run fixups */
sec_logger, /* [#9] log a transaction */
NULL, /* [#2] header parser */
sec_child_init, /* child_init */
NULL, /* child_exit */
NULL /* [#0] post read-request */
};
Autrement dit, mod_security intervient principalement lors de la phase
de fix-up, et non pas sur la phase de traduction URI vers nom de
fichier. Aucune interférence à déplorer par conséquent : toutes les URI,
manipulées par mod_rewrite aussi bien que mod_jk, seront filtrées.
La configuration des modules peut donc être la suivante :
8< ---------------------------------------------------
# Declaration des modules
LoadModule config_log_module libexec/mod_log_config.so
LoadModule mime_module libexec/mod_mime.so
# mod_status pour diagnostic : restriction sur 127.0.0.1
LoadModule status_module libexec/mod_status.so
# mod_info - avec restriction idem
LoadModule info_module libexec/mod_info.so
# Declaration de mod_dir (dependance mod_jk 1.2)
LoadModule dir_module libexec/mod_dir.so
LoadModule jk_module libexec/mod_jk.so
LoadModule rewrite_module libexec/mod_rewrite.so
LoadModule access_module libexec/mod_access.so
LoadModule auth_module libexec/mod_auth.so
LoadModule proxy_module libexec/libproxy.so
LoadModule setenvif_module libexec/mod_setenvif.so
LoadModule ssl_module libexec/libssl.so
LoadModule security_module libexec/mod_security.so
# Chargement et ordonnancement a l'execution
ClearModuleList
AddModule mod_log_config.c
AddModule mod_mime.c
AddModule mod_status.c
AddModule mod_info.c
# Pas necessaire d'activer mod_dir
# AddModule mod_dir.c
AddModule mod_jk.c
AddModule mod_rewrite.c
AddModule mod_access.c
AddModule mod_auth.c
AddModule mod_proxy.c
AddModule mod_so.c
AddModule mod_setenvif.c
AddModule mod_ssl.c
AddModule mod_security.c
8< ---------------------------------------------------
Un exemple de configuration minimaliste de mod_security suit, avec
filtrage sur le corps des requêtes (méthode POST) à destination de la
ressource /cgi-bin/printenv (des « sanity checks » sont également
effectués : XSS, SQL Injection, plage de caractères autorisés de %20 à
%FE -- cf ascii(7) et iso_8859_1(7) pour le détail) :
8< -------- à insérer au niveau global ---------------
SecFilterEngine On
SecAuditEngine On
SecAuditLog logs/audit_log
SecFilterScanPOST On
SecFilterCheckURLEncoding On
SecFilterCheckUnicodeEncoding On
SecFilterForceByteRange 32 254
SecFilter /etc/passwd
SecFilter "\.\./"
SecFilter "<[[:space:]]*script"
SecFilter "<(.|\n)+>"
SecFilter "delete[[:space:]]+from"
SecFilter "insert[[:space:]]+into"
SecFilter "select.+from"
SecFilterInheritance Off
SecFilterSelective POST_PAYLOAD "!^login=[a-zA-Z]{8}&password=[0-9]{1,8}$"
8< ---------------------------------------------------
La touche finale de cette installation sera sans aucun doute la mise en
cage du démon via chroot(8). Pour ce faire :
- Procéder manuellement. Cf le document de Denis Ducamp sur le sujet :
http://www.hsc.fr/ressources/breves/chroot.html
- Utiliser un programme type makejail(8), à titre d'exemple,
automatisant le processus et fonctionnant sur la base de modèles :
http://www.floc.net/makejail/
4. Notes sur Apache 2.0
Dans Apache 2.0, l'administrateur pourra noter que la direction AddModule a
disparu. L'ordonnancement des modules est défini dans le source même du
module, et offre une bien meilleure granularité que celle permise par
Apache 1.3 : l'ordonnancement n'est plus global (valable pour l'ensemble
des hooks d'un module), il peut être défini pour _chacun_ des hooks
posés par ce module.
La fonction permettant à un module d'enregistrer ses handlers est la
suivante :
ap_hook_phase_name(function_name, predecessors, successors, position);
Plus précisément :
- « function_name » correspond au handler ;
- « predecessors » et « successors » définissent respectivement les
modules qui doivent intervenir avant et après le module courant, pour
ce hook ;
- « position » est plus générique, et peut prendre les valeurs
HOOK_FIRST, HOOK_MIDDLE et HOOK_LAST.
En pratique, il s'agit donc de définir la position globalement (avec la
variable « position »), puis d'affiner avec les variables « predecessors
» et « successors ».
Dans une configuration type Apache 2.0/mod_jk2 (module tier),
l'interférence entre mod_jk2 et mod_rewrite a lieu au niveau du hook
translate_name, qui se disputent la priorité APR_HOOK_FIRST :
- mod_jk2 :
ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST);
- mod_rewrite :
ap_hook_translate_name(hook_uri2file,NULL,NULL,APR_HOOK_FIRST);
Dans la configuration par défaut, mod_jk2 prend la main avant
mod_rewrite. Il faut donc corriger mod_jk2 de la façon suivante :
--- mod_jk2.c.orig 2004-01-26 17:31:04.000000000 +0100
+++ mod_jk2.c 2004-01-26 17:30:48.000000000 +0100
@@ -808,11 +808,14 @@
static void jk2_register_hooks(apr_pool_t *p)
{
+ static const char * const aszPre[]={ "mod_rewrite.c",NULL };
+
ap_hook_handler(jk2_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(jk2_post_config,NULL,NULL,APR_HOOK_MIDDLE);
/* Force the mpm to run before us and set the
* scoreboard image */
ap_hook_child_init(jk2_child_init,NULL,NULL,APR_HOOK_LAST);
- ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST);
+ // ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST);
+ ap_hook_translate_name(jk2_translate, aszPre,NULL,APR_HOOK_FIRST);
ap_hook_map_to_storage(jk2_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE);
}
La technique du flag [PT] de mod_rewrite peut, dès lors, être employée
pour réécriture des URI qui seront transmises au Tomcat -- de même avec
le flag [L] pour le service au client des ressources locales.
* Remarque : il est également envisageable, pour ne pas avoir à modifier
mod_jk2.c, de jouer sur la directive LoadModule et de charger mod_jk2
_après_ (par opposition à Apache 1.3) mod_rewrite... :
# Include /etc/apache2/mods-enabled/*.load
[...]
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
[...]
LoadModule jk2_module /usr/lib/apache2/modules/mod_jk2.so
La facilité de configuration permettant de charger les modules par la
création de liens symboliques n'est en revanche plus exploitable. On
pourra donc préférer la première solution proposée.
Outre cette meilleure granularité (lorsqu'elle est exploitée), un des
avantages indéniables de l'utilisation d'Apache 2.0 est la possibilité
d'utiliser des filtres en sortie, permettant de faire de la réécriture
des URL (liens) renvoyées au client, dans le corps des réponses (et non
plus seulement dans l'entête 'Location:' des réponses -- comme le fait
mod_proxy via la directive ProxyPassReverse).
Un bon lien sur la question, qui n'aborde pas la problématique du
filtrage, néanmoins :
http://www.apacheweek.com/features/reverseproxies
5. Conclusion
La configuration d'un serveur Apache dans une optique de réécriture et
de filtrage d'URL n'est, finalement, pas immédiate (sans même entrer
dans le détail de l'écriture des règles de filtrage) -- compte-tenu des
interférences susceptibles de se produire entre les modules agissant
lors d'une même étape de traitement des URL. Si l'utilisation des
modules standards Apache (mod_proxy, mod_rewrite) est généralement sans
surprise, dans la mesure où leur intégration est pensée pour les usages
les plus communs, l'ajout de modules tiers demandera vraisemblablement
une réflexion quant à leur insertion parmi les modules déjà activés.
par Franck Davy (17/10/2003)