I recently had a need to setup a private directory on my web server that could only be accessed by a handful of selected people. The content also needed to be encrypted in transit. This article details how I did this on a Debian GNU/Linux system running Apache (2.0.40) server using mod_ssl and OpenSSL (0.9.6b and higher). Here are the goals of this project:
- Require HIGH or MEDIUM level SSL/TLS encryption at the transport (TCP) layer
- Browser must use SSLv3 or TLSv1, not SSLv2
- Require username/password authentication for some subdirectories
- Be a mini-CA (Certificate Authority)
- Use a non-standard port to keep most of the port-scanning riffraff away
The key to this whole system is the SSL/TLS protocol. SSL stands for Secure Sockets Layer, and it was developed by Netscape to enable secure transactions over the Web. It operates between the TCP layer and the HTTP application layer. TLSv1 is the IETF standard implementation, based on SSLv3. TLS stands for Transport Layer Security.
Assumptions
First and foremost, this document assumes that you are using some flavor of Linux, Apache 2.0.x and that you have OpenSSL installed. Other assumptions:
- This will be used over the Internet
- Your DNS configuration is correct (hostname=FQDN, PTR records O.K., etc.)
- Your firewall is setup to allow connections on the chosen https:// port
- You have a second machine with a modern web browser for testing purposes
- In these examples, my FQDN and hostname is: mycompany.com
Step 1: Setup your own CA (Certificate Authority)
In order to run a secure (SSL/TLS encrypted) web server, you have to have a private key and a certificate for the server. For a commercial web site, you will probably want to purchase a certificate signed by a well-known root CA. For Intranet or special-purpose uses like this, you can be your own CA. This is done with the OpenSSL tools.
Here, we will make a private CA key and a private CA X.509 certificate. We will also make a directory for the certs and keys:
[root]# mkdir /root/CA [root]# chmod 0770 /root/CA [root]# cd /root/CA [root]# openssl genrsa -des3 -out my-ca.key 2048 Generating RSA private key, 2048 bit long modulus .....................................................+++ ...................................................+++ e is 65537 (0x10001) Enter PEM pass phrase: Verifying password - Enter PEM pass phrase: [root]# openssl req -new -x509 -days 3650 -key my-ca.key -out my-ca.crt Using configuration from /usr/share/ssl/openssl.cnf Enter PEM pass phrase: 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) []:LK State or Province Name (full name) []:Western Locality Name (eg, city) []:Colombo Organization Name (eg, company) [My Company Ltd]:MyCompany.Com Organizational Unit Name (eg, section) []:Certificate Authority Common Name (eg, your name or your server's hostname) []:mycompany.com CA Email Address []:user@mycompany.com [root]# openssl x509 -in my-ca.crt -text -noout
Notes: The first OpenSSL command makes the key. The second command makes the X.509 certificate with a 10-year lifetime. The third command lets you view the completed certificate. Make sure that you keep the password in a safe place, you will need this every time you sign another certificate! You will probably also want to make backups of the cert and key and lock them in a safe place.
Step 2: Make a key and a certificate for the web server:
Now, we have to make an X.509 certificate and corresponding private key for the web server. Rather than creating a certificate directly, we will create a key and a certificate request, then “sign” the certificate request with the CA key we made in Step 1. You can make keys for multiple web servers this way. One thing to note is that SSL/TLS private keys for web servers need to be either 512 or 1024 bits. Any other key size may be incompatible with certain browsers.
[root]# openssl genrsa -des3 -out server.key 1024
Generating RSA private key, 1024 bit long modulus
....++++++
.++++++
e is 65537 (0x10001)
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
[root]# openssl req -new -key server.key -out server.csr
Using configuration from /usr/share/ssl/openssl.cnf
Enter PEM pass phrase:
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) []:LK
State or Province Name (full name) []:Western
Locality Name (eg, city) []:Colombo
Organization Name (eg, company) [My Company Ltd]:mycompany.Com
Organizational Unit Name (eg, section) []:TechStaff
Common Name (eg, your name or your server's hostname) []:mycompany.com <=== This must be the real FQDN of your server!!!
Email Address []:user@mycompany.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl x509 -req -in server.csr -out server.crt -sha1 -CA my-ca.crt -CAkey my-ca.key -CAcreateserial -days 3650
Signature ok
subject=/C=LK/ST=Western/L=Colombo/O=mycompany.Com/OU=TechStaff/CN=mycompany.com/Email=user@mycompany.com
Getting CA Private Key
Enter PEM pass phrase:
[root]# openssl x509 -in server.crt -text -noout
Make sure that your server name is the same as the FQDN that your clients will use when connecting to your site. Also, let’s get in the habit of protecting our keys with appropriate permissions:
[root]# chmod 0400 *.key
Now, we need to move the new keys and certs into the proper directories in the /etc/apache2 hierarchy:
[root]# cp server.crt /etc/apache2/ssl.crt [root]# cp server.key /etc/apache2/ssl.key [root]# cp my-ca.crt /etc/apache2/ssl.crt
Step 3: Create directories and files for the secure web service
I do not want the secure branch of my webserver directory tree to be part of my “insecure” branch that serves unencrypted files. My normal web root directory is /var/www/ . The document root for the secure web server will be located at /var/www/SSL.
[root]# mkdir /var/www/SSL [root]# chmod 0775 /var/www/SSL [root]# cd /var/www/SSL [root]# mkdir Passneeded
For testing purposes, create a simple HTML file in /var/www/SSL to print “Apache rocks with SSL”
Step 4: Configure the Apache web server
Create a file, let’s say https.mycompany.com in /etc/apache2/sites-enabled/ to define your HTTPS virtualhost and include the following lines.
NameVirtualHost mycompany.com:443
<VirtualHost mycompany.com:443>
DocumentRoot "/var/www/SSL"
# Note that the FQDN and server hostname must go here - clients will not be able to connect, otherwise!
ServerName mars.mycompany.com:443
ServerAdmin webmaster@mycompany.com
#Turning-on the SSL engine
SSLEngine On
# Here, I am allowing only "high" and "medium" security key lengths.
SSLCipherSuite HIGH:MEDIUM
# Here I am allowing SSLv3 and TLSv1, I am NOT allowing the old SSLv2.
SSLProtocol all -SSLv2
# Server Certificate:
SSLCertificateFile /etc/apache2/ssl.crt/server.crt
# Server Private Key:
SSLCertificateKeyFile /etc/apache2/ssl.key/server.key
# Server Certificate Chain:
SSLCertificateChainFile /etc/apache2/ssl.crt/my-ca.crt
# Certificate Authority (CA):
SSLCACertificateFile /etc/apache2/ssl.crt/my-ca.crt
# This is needed so that you can use auto-indexing for some directories in the
# /var/www/SSL directory branch. This can be handy if you would like to have
# a list of sensitive files for people to download.
<Directory "/var/www/SSL">
Options Indexes
AllowOverride None
Allow from from all
Order allow,deny
</Directory>
Also you have to tell Apache, for all HTTPS requests use the port 443. For that append the following lines to /etc/apache2/ports.conf
<IfModule mod_ssl.c>
Listen "443"
</IfModule>
Step 5: Start the web server and test
Run the following commands to start the the Apache web server:
[root]# /etc/init.d/apache2 start Starting web server: apache2. Server mycompany.com:443 (RSA) Enter pass phrase:
Note that you will have to enter the password for your server key in order to start the server. You will also have to do this during boot if you have httpd configured to start automatically.
Make sure that the web server is now listening on the SSL/TLS port, TCP port 443:
[root]# netstat -tna Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN
In order to test that your SSL/TLS web server is running, you will now need to connect to it with a browser. The URL you use should be https://mycompany.com. You will probably get a warning prompt about the Certificate Authority (CA) being unknown. You can view the certificate properties, which will look familiar because you created the cert yourself. You can save the cert in your browser, or import the my-ca.crt file into your browser as a new CA. How you do this will depend on which browser you are using.
Step 6: Require simple username/password auth for one of the directories:
We want to require a valid username and password for the /var/www/SSL/Passneeded directory. The username and password will be encrypted in transit as part of the TCP stream. We will need to setup the access control directives, as well as use the htpasswd command to add the username/password pairs.
[root]# htpasswd -c -m /etc/apache2/.htpasswd test_user1 New password: Re-type new password: Adding password for user test_user1 [root]# htpasswd -m /etc/apache2/.htpasswd test_user2 New password: Re-type new password: Adding password for user test_user2 [root]# chown apache.root /etc/apache2/.htpasswd [root]# chmod 0460 /etc/apache2/.htpasswd
Now, we need to tell Apache to require a username/password to access the Passneeded directory. Here is what we will add to /etc/apache2/sites-enabled/https.mycompany.com file:
<Directory "/var/www/SSL/Passneeded"> AuthType Basic AuthName "Username and Password Required" AuthUserFile /etc/apache2/.htpasswd Require valid-user </Directory>
Now, restart the webserver with /etc/init.d/apache2 restart. When you try to access the Passneeded directory from a web browser, you should be prompted for a username and password. If you enter incorrect information, you should be denied access.
Step 7: Change the TCP port that Apache SSL/TLS listens on:
Since this is a private, special-purpose secure web server, you may want to change the TCP port from 443 to something else. This will make it just a little more difficult for crackers to locate via automated network scans. For this excercise, we will change the port to TCP 444 by editing the ports.conf configuration file and /etc/apache2/sites-enabled/https.mycompany.com. Make the following changes to the ports.conf:
<IfModule mod_ssl.c>
Listen "444"
</IfModule>
And make the following changes in /etc/apache2/sites-enabled/https.mycompany.com:
NameVirtualHost mycompany.com:444 <VirtualHost mycompany.com:444>
Now, restart Apache and look at the listening ports:
[root]# /etc/init.d/apache2 restart [root]# netstat -tna Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:444 0.0.0.0:* LISTEN
Now, you should be able to connect to the server with this URL:
https://mycompany.com:444
Web Server Key Password:
You have probably noticed by now that every time you restart Apache or boot your server, you are forced to enter the password for the server key. This is a security measure, but it can be inconvenient. If you would like to make an insecure server key that will allow Apache to start automatically at boot time, then there is a way to do this. The choice is yours…
Here is how you do it:
[root]# cd /etc/apache2/ssl.key [root]# cp server.key server.key.orig [root]# openssl rsa -in server.key.orig -out server.key [root]# chmod 0400 server*
Now, you should be able to restart Apache or boot your server without having to input the password. This may also be a very good time to copy all the keys and certificates that you made to floppy or CD. You can imagine what a pain it would be if you lost all of your keys and certs due to a disk failure. You may even want to make paper copies of the PEM encoded certificates and keys, which use ASCII text. Lock them in a secure place, along with any passwords.
Conclusion/Final Comments
As you can see, setting up a secure web server for some specific function is not that difficult. All the tools are included with a standard GNU/Linux distribution. OpenSSL is a fantastic Open Source toolkit that can be used in a number of applications. For example, you can use it to run files through different hashing functions, handle S/MIME encrypted mail, or encrypt & decrypt files.
In order to use Apache as a high-volume e-commerce server with SSL/TLS, you will probably need to do more configuration and hardware tuning. You may need to buy and configure a hardware crypto accelerator card. You will almost certainly want to purchase a “real” server certificate signed by Entrust, Thawte, or one of the other root-level CAs.
In any event, you now have a good feel for all the pieces, parts, and protocols that make it work!
Resources
- Apache 2.0 Documentation
- mod_ssl home page
- OpenSSL home page
- IETF TLS Charter
- The following man pages:
- man openssl
- man genrsa
- man req
- man x509
- man pkcs12
- man htpasswd
[quote]
[root]# cp server.crt /etc/apache2/ssl.crt
[root]# cp server.key /etc/apache2/ssl.key
[root]# cp my-ca.crt /etc/apache2/ssl.crt
[/quote]
this result in a overwrite between 1st file and 3rd file. I bet there’s something wrong.