Nous allons voir dans cet article comment installer et configurer un reverse proxy Apache de manière sécurisé en intégrant notamment des fonctionnalités de WAF (Web Application Firewall) via le module ModSecurity.

Sommaire

  1. Sommaire
    1.1. Liens utiles
  2. Installation et configuration
    2.1. Installation
    2.2. Configuration
  3. Gestion des Vhosts
    3.1. Gestion des certificats
    3.2. Créer les vhosts
  4. Gérer Apache
    4.1 ModSecurity

Liens utiles

Installation et configuration

Installation

Le serveur Apache

aptitude install apache2  

Les modules complémentaires

aptitude install libapache2-mod-evasive  
aptitude install -t wheezy-backports libapache2-modsecurity  
a2enmod cache  
a2enmod disk_cache  
a2enmod file_cache  
a2enmod headers  
a2enmod mem_cache  
a2enmod proxy_balancer  
a2enmod proxy  
a2enmod proxy_connect  
a2enmod proxy_http  
a2enmod rewrite  
a2enmod status  
a2enmod ssl  

Configuration

Apache

nano /etc/apache2/apache2.conf  

Éditez les valeurs suivantes:

Timeout 300  
KeepAlive On  
MaxKeepAliveRequests 150  
KeepAliveTimeout 2

<IfModule mpm_prefork_module>  
    StartServers          10
    MinSpareServers       40
    MaxSpareServers       100
    MaxClients            200
    MaxRequestsPerChild   0
</IfModule>

<IfModule mpm_worker_module>  
    StartServers          10
    MinSpareServers       40
    MaxSpareServers       100
    MaxClients            200
    MaxRequestsPerChild   0
</IfModule>

HostnameLookups Off  
LogLevel warn  

Ensuite, activez la sécurité dans Apache

nano /etc/apache2/conf.d/security  

Insérez les valeurs suivantes :

ServerTokens Full  
ServerSignature Off  

Puis relancez Apache :

/etc/init.d/apache2 reload

Les modules complémentaires

ModSecurity

Exécutez les commandes suivantes:

mkdir /data  
mkdir /data/src  
mkdir /data/mod-security  
mkdir /data/mod-security/audit  
mkdir /data/mod-security/msa  
mkdir /data/mod-security/rules  
mkdir /data/mod-security/suspicious  
chown -R www-data:www-data /data/mod-security  
cd /data/src  
wget http://updates.atomicorp.com/channels/rules/delayed/modsec-2.7-free-latest.tar.gz  
tar -xvzf modsec-2.7-free-latest.tar.gz  
cp -a /data/src/modsec/* /data/mod-security/rules  
mv /data/mod-security/rules/15_asl_paranoid_rules.conf /data/mod-security/rules/15_asl_paranoid_rules.conf.disable  
mv /data/mod-security/rules/70_asl_csrf_experimental.conf /data/mod-security/rules/70_asl_csrf_experimental.conf.disable  

Puis éditez le fichier suivant :

<syntaxhighlight lang="bash">  
<IfModule mod_security2.c>  
SecRuleEngine on  
SecRequestBodyAccess On  
SecResponseBodyAccess On  
SecResponseBodyMimeType (null) text/html text/plain text/xml  
SecResponseBodyLimit  2621440  
SecComponentSignature 201208081438  
SecUploadDir /data/mod-security/suspicious  
SecUploadKeepFiles off  
SecAuditEngine RelevantOnly  
SecAuditLogRelevantStatus "^(?:5|4(?!04))"  
SecAuditLogType Concurrent  
SecAuditLogParts ABIFHZ  
SecArgumentSeparator "&"  
SecCookieFormat 0  
SecRequestBodyInMemoryLimit 131072  
SecDataDir /data/mod-security/msa  
SecTmpDir /tmp  
SecAuditLogStorageDir /data/mod-security/audit  
SecRequestBodyLimit 134217728  
SecResponseBodyLimitAction ProcessPartial  
SecReadStateLimit 1024  
SecRequestBodyNoFilesLimit 1048576  
SecRequestBodyInMemoryLimit 131072  
SecAuditLogDirMode 0770  
SecPcreMatchLimit 150000  
SecPcreMatchLimitRecursion 150000  
SecRequestBodyLimit 1310720000  
SecServerSignature " "  
SecDebugLog /var/log/apache2/modsec_debug.log  
SecAuditLog /var/log/apache2/modsec_audit.log

Include /data/mod-security/rules/*.conf  
</IfModule>  

Puis enfin, suivez l'étape 9 (Step 9: Install the rules) du guide

Pour finir, relancez Apache :

/etc/init.d/apache2 restart

ModeEvasive

Exécutez les commandes suivantes:

ln -s /usr/bin/mail /bin/mail  

Puis éditez le fichier suivant :

nano /etc/apache2/conf.d/mod-evasive.conf  

Insérez le contenu suivant :

<ifmodule mod_evasive20.c>  
DOSHashTableSize 3097  
DOSPageCount 3  
DOSSiteCount 50  
DOSPageInterval 2  
DOSSiteInterval 2  
DOSBlockingPeriod 300  
DOSLogDir /var/log/apache2/mod_evasive  
DOSEmailNotify admin@webcenter.fr  
DOSWhitelist 127.0.0.1  
</ifmodule>  

Voici un extrait de l'aide pour mieux comprendre les paramètres :

  • DOSSiteCount / DOSSiteInterval: Le nombre maximal de requêtes qu'une adresse IP peut faire sur le site pendant l'intervalle de temps. DOSSiteInterval (en secondes).
  • DOSPageCount / DOSPageInterval: Le nombre maximal de requêtes qu'une adresse IP peut faire sur la même URL pendant une unité de temps * DOSPageInterval (en secondes). Notez que l'URL ne contient pas les paramètres : http://monHost/monurl?param=1 est la même page que http://monHost/monurl?param=2, ce qui correspond bien à mon besoin qui est de limiter l'accès à un webservice REST.
  • DOSBlockingPeriod :Durée pendant laquelle une adresses IP en liste noire sera refusée. un ip refusée se verra retourner une erreur 403. Par défaut, cette durée est de 10 secondes. Il peut ere utile de personnaliser la page 403 pour expliquer la raison du 'Forbidden'.
  • DOSEmailNotify : Adresse email à laquelle envoyer une notification lorsqu'une adresse IP est ajoutée en liste noire.
  • DOSSystemCommand : Commande appelé lorsqu'une ip est bloquée. On peut, par exemple, utiliser iptable et rejeter tout les requêtes provenant de cette IP. l'utilisateur n'aura alors plus d'erreur 403 mais ce verra refusé l'accès au niveau socket
  • DOSWhiteList : Spécifie une ou plusieurs adresse IP à ne jamais positionner en liste noire.

Pour finir, relancez Apache :

/etc/init.d/apache2 restart

Gestion des Vhosts

Gestion des certificats

Créer un certificat autosigné

mkdir /etc/apache2/keystore  
openssl genrsa -out /etc/apache2/keystore/blog.webcenter.fr.key 2048  
openssl req -new -x509 -days 365000 -key /etc/apache2/keystore/blog.webcenter.fr.key -out /etc/apache2/keystore/blog.webcenter.fr.crt  

Génerer un CSR

Si vous souhaitez faire signer votre certificat par une autorité de certification comme StartSSL, voici la procédure :

mkdir /etc/apache2/keystore  
openssl genrsa -out /etc/apache2/keystore/blog.webcenter.fr.key 2048  
openssl req -new -key /etc/apache2/keystore/blog.webcenter.fr.key -out /etc/apache2/keystore/blog.webcenter.csr  

Voici un exemple de réponse :

You are about to be asked to enter information that will be incorporated  
into your certificate request.  
What you are about to enter is what is called a Distinguished Name or a DN.  
There are quite a few fields but you can leave some blank  
For some fields there will be a default value,  
If you enter '.', the field will be left blank.  
-----
Country Name (2 letter code) [AU]:FR  
State or Province Name (full name) [Some-State]:Ile-de-France  
Locality Name (eg, city) []:Paris  
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Webcenter  
Organizational Unit Name (eg, section) []:Service informatique  
Common Name (eg, YOUR name) []:blog.webcenter.fr  
Email Address []:admin@webcenter.fr

Please enter the following 'extra' attributes  
to be sent with your certificate request  
A challenge password []:  
An optional company name []:  

Créer les vhosts

Mise en forme des sites par défault

Exécutez les commandes suivantes:

a2dissite default  
a2dissite default-ssl  
cd /etc/apache2/sites-available  
mv default 00-default  
mv default-ssl 00-default-ssl  

Puis éditez le fichier suivant:

nano /etc/apache2/sites-available/00-default  

Et mettez le contenue suivant :

NameVirtualHost *:80

<VirtualHost *:80>  
        ServerAdmin admin@webcenter.fr

        DocumentRoot /var/www
        <Directory />
                Deny from all
        </Directory>
        <Directory /var/www/>
                Deny from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                Deny from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>  

Puis éditez le fichier suivant :

nano /etc/apache2/sites-available/00-default-ssl  

Mettez le contenu suivant :

<IfModule mod_ssl.c>

NameVirtualHost *:443

<VirtualHost _default_:443>  
        ServerAdmin admin@webcenter.fr

        DocumentRoot /var/www
        <Directory />
                Deny from all
        </Directory>
        <Directory /var/www/>
                Deny from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                Deny from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined

        #   SSL Engine Switch:
        #   Enable/Disable SSL for this virtual host.
        SSLEngine on

        #   A self-signed (snakeoil) certificate can be created by installing
        #   the ssl-cert package. See
        #   /usr/share/doc/apache2.2-common/README.Debian.gz for more info.
        #   If both key and certificate are stored in the same file, only the
        #   SSLCertificateFile directive is needed.
        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

        #   Server Certificate Chain:
        #   Point SSLCertificateChainFile at a file containing the
        #   concatenation of PEM encoded CA certificates which form the
        #   certificate chain for the server certificate. Alternatively
        #   the referenced file can be the same as SSLCertificateFile
        #   when the CA certificates are directly appended to the server
        #   certificate for convinience.
        #SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

        #   Certificate Authority (CA):
        #   Set the CA certificate verification path where to find CA
        #   certificates for client authentication or alternatively one
        #   huge file containing all of them (file must be PEM encoded)
        #   Note: Inside SSLCACertificatePath you need hash symlinks
        #         to point to the certificate files. Use the provided
        #         Makefile to update the hash symlinks after changes.
        #SSLCACertificatePath /etc/ssl/certs/
        #SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt

        #   Certificate Revocation Lists (CRL):
        #   Set the CA revocation path where to find CA CRLs for client
        #   authentication or alternatively one huge file containing all
        #   of them (file must be PEM encoded)
        #   Note: Inside SSLCARevocationPath you need hash symlinks
        #         to point to the certificate files. Use the provided
        #         Makefile to update the hash symlinks after changes.
        #SSLCARevocationPath /etc/apache2/ssl.crl/
        #SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl

        #   Client Authentication (Type):
        #   Client certificate verification type and depth.  Types are
        #   none, optional, require and optional_no_ca.  Depth is a
        #   number which specifies how deeply to verify the certificate
        #   issuer chain before deciding the certificate is not valid.
        #SSLVerifyClient require
        #SSLVerifyDepth  10

        #   Access Control:
        #   With SSLRequire you can do per-directory access control based
        #   on arbitrary complex boolean expressions containing server
        #   variable checks and other lookup directives.  The syntax is a
        #   mixture between C and Perl.  See the mod_ssl documentation
        #   for more details.
        #<Location />
        #SSLRequire (    %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
        #            and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
        #            and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
        #            and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
        #            and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20       ) \
        #           or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
        #</Location>

        #   SSL Engine Options:
        #   Set various options for the SSL engine.
        #   o FakeBasicAuth:
        #     Translate the client X.509 into a Basic Authorisation.  This means that
        #     the standard Auth/DBMAuth methods can be used for access control.  The
        #     user name is the `one line' version of the client's X.509 certificate.
        #     Note that no password is obtained from the user. Every entry in the user
        #     file needs this password: `xxj31ZMTZzkVA'.
        #   o ExportCertData:
        #     This exports two additional environment variables: SSL_CLIENT_CERT and
        #     SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
        #     server (always existing) and the client (only existing when client
        #     authentication is used). This can be used to import the certificates
        #     into CGI scripts.
        #   o StdEnvVars:
        #     This exports the standard SSL/TLS related `SSL_*' environment variables.
        #     Per default this exportation is switched off for performance reasons,
        #     because the extraction step is an expensive operation and is usually
        #     useless for serving static content. So one usually enables the
        #     exportation for CGI and SSI requests only.
        #   o StrictRequire:
        #     This denies access when "SSLRequireSSL" or "SSLRequire" applied even
        #     under a "Satisfy any" situation, i.e. when it applies access is denied
        #     and no other module can change it.
        #   o OptRenegotiate:
        #     This enables optimized SSL connection renegotiation handling when SSL
        #     directives are used in per-directory context.
        #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
        <FilesMatch "\.(cgi|shtml|phtml|php)$">
                SSLOptions +StdEnvVars
        </FilesMatch>
        <Directory /usr/lib/cgi-bin>
                SSLOptions +StdEnvVars
        </Directory>

        #   SSL Protocol Adjustments:
        #   The safe and default but still SSL/TLS standard compliant shutdown
        #   approach is that mod_ssl sends the close notify alert but doesn't wait for
        #   the close notify alert from client. When you need a different shutdown
        #   approach you can use one of the following variables:
        #   o ssl-unclean-shutdown:
        #     This forces an unclean shutdown when the connection is closed, i.e. no
        #     SSL close notify alert is send or allowed to received.  This violates
        #     the SSL/TLS standard but is needed for some brain-dead browsers. Use
        #     this when you receive I/O errors because of the standard approach where
        #     mod_ssl sends the close notify alert.
        #   o ssl-accurate-shutdown:
        #     This forces an accurate shutdown when the connection is closed, i.e. a
        #     SSL close notify alert is send and mod_ssl waits for the close notify
        #     alert of the client. This is 100% SSL/TLS standard compliant, but in
        #     practice often causes hanging connections with brain-dead browsers. Use
        #     this only for browsers where you know that their SSL implementation
        #     works correctly.
        #   Notice: Most problems of broken clients are also related to the HTTP
        #   keep-alive facility, so you usually additionally want to disable
        #   keep-alive for those clients, too. Use variable "nokeepalive" for this.
        #   Similarly, one has to force some clients to use HTTP/1.0 to workaround
        #   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
        #   "force-response-1.0" for this.
        BrowserMatch "MSIE [2-6]" \
                nokeepalive ssl-unclean-shutdown \
                downgrade-1.0 force-response-1.0
        # MSIE 7 and newer should be able to use keepalive
        BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</VirtualHost>  
</IfModule>  

Activez les modifications :

a2ensite 00-default  
a2ensite 00-default-ssl  
/etc/init.d/apache2 restart

Création d'un vhost HTTP pour forcer le https

nano /etc/apache2/sites-available/01-blog.webcenter.fr  

Mettez le contenu suivant

<virtualhost *:80>  
        ServerName blog.webcenter.fr
        ServerAdmin admin@webcenter.fr

        RewriteEngine On
        RewriteCond %{SERVER_PORT} !443
        RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</virtualhost>  
</syntaxhighlight>  

Puis activez la configuration :

a2ensite 01-blog.webcenter.fr  
/etc/init.d/apache2 restart

Configuration du vhost https

nano /etc/apache2/sites-available/01-blog.webcenter.fr-ssl  

Mettez le contenu suivant :

<IfModule mod_ssl.c>

<VirtualHost *:443>  
        ServerName blog.webcenter.fr
        ServerAdmin admin@webcenter.fr

        # Options
        Options -Indexes -FollowSymLinks -MultiViews                                                                                                                                                     

        ### Start SSL                                                                                                                                
        SSLEngine On                                                                                                                                 
        SSLVerifyClient none                                                                                                                         

        ### Certificates
        #SSLCACertificateFile /etc/apache2/keystore/startSSL_root.pem
        #SSLCertificateChainFile /etc/apache2/keystore/startSSL_intermediate.pem                                                                                                                             
        SSLCertificateFile /etc/apache2/keystore/blog.webcenter.fr.crt                                                                              
        SSLCertificateKeyFile /etc/apache2/keystore/blog.webcenter.fr.key                                                                                                                                                           

        ### Only allow SSLv3 and TLSv1 and HIGH/MED encryption.                                                                                      
        SSLCipherSuite TLSv1:+HIGH:+MEDIUM                                                      
        SSLProtocol -all +TLSv1                                                                                                               


        ErrorLog /var/log/apache2/blog.webcenter.fr_error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        LogLevel warn

        CustomLog /var/log/apache2/blog.webcenter.fr_access.log combined

        ############################################
        # Header
        ###########################################
        Header set Server " "
        RequestHeader set X-Forwarded-Proto "https"

        ##########################################
        # Reverse Proxy
        ##########################################
        ServerSignature Off
        ProxyRequests Off
        SSLProxyEngine On 

        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>

        ProxyPass / http://192.168.1.1:8080/
        ProxyPassReverse / http://192.168.1.1:8080/

        ###########################################
        # Le cache
        ##########################################
        CacheEnable disk /
        CacheDefaultExpire 86400
        CacheRoot /var/apache/cache
        CacheIgnoreHeaders Set-Cookie 
        CacheDirLevels 2
        CacheMaxFileSize 300000000

        CacheEnable mem /
        MCacheSize 512000


        ###########################################
        # Secure site
        ###########################################
        SetEnv REGISTER_GLOBALS 0

        # Disable DEL PUT ...
        RewriteEngine on
        RewriteCond %{THE_REQUEST} !^(POST|GET)\ /.*\ HTTP/1\.1$ 
        RewriteRule .* - [F]

        # Empêcher les attaques par include de fichier externe
        RewriteCond %{QUERY_STRING} =//
        RewriteRule .* - [F,L]

        # Bloquer l'accès au site pour libwww-perl
        RewriteCond %{HTTP_USER_AGENT} libwww [NC]
        RewriteRule .* - [F,L]

         ##########################################
        # Cache header configuration
        #########################################
        ExpiresActive On
        ExpiresByType image/png "access plus 1 day"
        ExpiresByType image/jpg "access plus 1 day"
        ExpiresByType image/gif "access plus 1 day"
        ExpiresByType text/css "access plus 1 day"
        ExpiresByType text/javascript "access plus 1 day"


</VirtualHost>

</IfModule>  

Puis activez la configuration :

a2ensite 01-blog.webcenter.fr-ssl  
/etc/init.d/apache2 restart

Gérer Apache

ModSecurity

Désactiver ModSecurity pour un vhost

Ajouter dans la configuration de votre vhost les lignes suivantes :

<IfModule mod_security2.c>  
SecRuleEngine Off  
</IfModule>