Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Protection options for HTTPS Apache servers UNIX
This tip describes how to configure an Apache 2.x SSL server in a manner that is unusually resilient to attack. It assumes that you already have a working SSL server, and know how to use the various Apache configuration contexts (server config, virtual host, directory, etc.). Note: I did not test the syntax of the commands in this tip explicitly on a test server. There may be mistakes, but getting it to work should be fairly straightforward.

First, some best-practices for your server configuration:
  ServerTokens Prod
  ServerSignature Off
Read the rest of the hint for the interesting part.

Reading the documentation for mod_ssl will help understand what's going on. Looking at the SSLCipherSuite directive, it tells us that the Apache default ciphers' list is:
  SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
So the first thing we do is disable ciphers at the server context with:
  SSLCipherSuite -ALL
This, of course, makes the server refuse to talk to anything! Very secure, but probably not what you want. Reading the docs for SSLCipherSuite more carefully, we see:
Notice that this directive can be used both in per-server and per-directory context. In per-server context, it applies to the standard SSL handshake when a connection is established. In per-directory context, it forces a SSL renegotation with the reconfigured Cipher Suite after the HTTP request was read, but before the HTTP response is sent.
So now we go in and enable a select set of ciphers for a particular area with say:
<Directory "/disc2/htdocs/mysecretplace/">
  SSLCipherSuite HIGH
  SSLRequireSSL
</Directory>
Then restart Apache and test your configuration with openssl s_client:
  echo -e 'GET / HTTP/1.0nn' | openssl s_client -state –connect server:443
  echo -e 'GET /mysecretplace/ HTTP/1.0nn' | openssl s_client -state –connect server:443
The first request should fail with a nasty looking SSL error. If you read the output, you'll see that the server is requesting a "change cipher spec� and then failing. The second request should work OK. How is this better than configuring my server to use user credentials through AuthType Basic and require valid-user?
  • Attackers looking for SSL web servers on port 443 will probably miss you. nmap -sV, for instance, doesn't figure out that it's an SSL service. Even if they do figure it out, they won't get back a Server: header unless their request is one of your exposed URL paths.

  • Web server attack tools (Nikto, etc.) fall on their face terribly when things fail at the SSL layer. The output of curl –visk https://server/, after applying the above changes, shows how non-communicative the server is. Tools that attempt to guess valid URLs or test for specific vulnerabilities will fail in an equally severe fashion.

  • You can publish HTTPS URLs and users won't have to authenticate. A good example is if you have an SSL server that handles form transactions via POST. You need only expose say https://server/secure/process/ through a Directory directive, and the user is unaware of the SSL defense. Yet if someone wants to poke at your server to any extent, they will have to know or discover which URLs you are exposing.
What other cool tricks are possible?
  • Use client side SSL certificates.
  • Have a more complex SSLRequire
    • Require that REQUEST_METHOD be say POST
    • Require a particular HTTP_REFERER so that only links from particular sites are valid
    • Require HTTP_HOST to be your DNS name so that requests issued by IP address alone are rejected
    • Require HTTP_HOST to be some unusual value, and have your users put an entry for this name into their hosts file with your IP address
  • It should be possible to use either of the last two techniques above on your document root and get an OK level of protection, but remember that an attacker can generally get your DNS name from the Common Name in your SSL certificate.
[robg adds: This hint assumes a relatively high level of Apache configuration experience. A recent hint explained how to get HTTPS working with OS X's webserver, which is necessary before using any of this hint, obviously.]
    •    
  • Currently 3.25 / 5
  You rated: 4 / 5 (4 votes cast)
 
[10,575 views]  

Protection options for HTTPS Apache servers | 2 comments | Create New Account
Click here to return to the 'Protection options for HTTPS Apache servers' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Protection options for HTTPS Apache servers
Authored by: cp on Dec 07, '04 06:30:02PM
Well, I tried this, without success. I have Complete Apache 2.0.52 installed. SSL is configured within a
 <VirtualHost _default_:443> </VirtualHost> 
block. It seems that you can indeed remove ciphers with:
 SSLCipherSuite -ALL 
on a per server/virtual host basis, as described in the hint and official docs, but Apache seems to stop you from adding ciphers back in per directory within a
 <DIRECTORY> ... </DIRECTORY> 
notwithstanding this hint or official apache documentation. You can, however, further remove ciphers within a
 <DIRECTORY> ... </DIRECTORY> 
All in all, quite confusing.
cp

[ Reply to This | # ]
Ooops.. Use Location instead of Directory
Authored by: MartySells on Dec 14, '04 01:19:27AM
Sorry this didn't work for you. It's a very slick trick so I would like to see others able to get it working.

As I noted, I didn't test the configs that I posted in the original hint and in checking one of my config files where I'm doing something slightly different (overriding SSLVerifyClient and setting it to None for a particular subspace where I don't want to require a client side certificate) I noticed that I'm using a Location rather than Directory directive. When I posted I checked the Apache doc which seemed to say that both were supported so I posted an my hint using Directory.

In testing I found that a Directory section did not work as you found. Using Location instead worked just fine. So the config should read:
# This is all inside a VirtualHost tag

Location /
SSLVerifyClient None
SSLCipherSuite -ALL
SSLRequireSSL
/Location

Location /books/
SSLCipherSuite HIGH
SSLRequireSSL
/Location
So try it in a Location block and please let me/us know if it works. My WAG (wild a$$ guess) is that Apache isn't properly taking the URL from the request and figuring out which Directory block(s) apply and what the SSL settings are. Using a Location block probably makes it easier for Apache to do the right thing.

-m

[ Reply to This | # ]