Best Practice for Securing 52°North Web Services
Using HTTPS as the schema for our services should be considered as the default
nowadays. We have documented some best practices on how to set up a Tomcat
and place a Proxy server (nginx or apache2) in front of it. The Tomcat is only available
on localhost and the Proxy server takes care of all HTTPS related tasks.
This guide focusses on Debian installations. For Windows-based systems, a similar
approach might work, but most likely different configurations, SSL Certificate setups
and installation guides need to be followed. So, better go for Linux
Requirements
- SSL Certificate
- Proxy web server, e.g. nginx or apache2
- java servlet container, e.g. tomcat
Workflow
The following workflow describes how to set-up a secure web server proxy and link it with tomcat. It looks like the following:
- Set-Up proxy web server
- Configure SSL and proxy module
- Optional: Add redirect all or context only to ssl for http (port 80) requests
- Set-Up servlet container
- Limit to localhost
- Set-Up SSL cert
- Validate set-up
- Set-Up proxy web server
- Configure SSL and proxy module
- nginx
- an nginx binary with these modules is required
- if
sudo nginx -V | grep "ngx_http_proxy_module" | grep "http_ssl_module"
generates output, the modules are available
- if not, get an nginx build with these modules
- apache2
- Check the list of active modules for mod_ssl and mod_proxy_http via
sudo apache2ctl -M | egrep "ssl|proxy"
- If you see just
Syntax OK
: run the following command to enable the required modules: sudo a2enmod ssl ; sudo a2enmod proxy_http
. If you need to rewrite the HTML output, activate proxy_http
, too.
- Configure proxy context for web app and manager. This provides the possibility to add additional security layers like IP filter on proxy level for each webapp differently. In addition, the server landingpage can be served by the web server and not the servlet container.
- nginx:
- Prepare
ssl_param
: user@host:~$ cd /etc/ssl/certs; sudo openssl dhparam -out dhparam.pem 4096; cd -
- To enable these site configs, you need to link them into
/etc/nginx/sites-enabled/
and force-reload your nginx instance.
SSL configuration in /etc/nginx/sites-available/
: upstream tomcat {
server 127.0.0.1:8080 fail_timeout=0;
}
server {
listen 443;
server_name www.example.com;
ssl on;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
ssl_certificate /etc/ssl/certs/nexos.demo.52north.org.crt;
ssl_certificate_key /etc/ssl/private/nexos.demo.52north.org.key;
index index.html index.htm;
location = /50x.html { root /usr/share/nginx/html; }
location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }
location ~ /\. { return 404; }
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
location /manager {
client_max_body_size 128m;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
# this is the important setting for SSL:
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_connect_timeout 240;
proxy_send_timeout 240;
proxy_read_timeout 240;
proxy_pass http://tomcat;
allow your.allowed.v4.ip;
deny all;
}
# location /52n-supervisor {
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $http_host;
# this is the important setting for SSL:
# proxy_set_header X-Forwarded-Proto https;
# proxy_redirect off;
# proxy_connect_timeout 240;
# proxy_send_timeout 240;
# proxy_read_timeout 240;
# proxy_pass http://tomcat;
# allow your.allowed.v4.ip;
# deny all;
# }
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
# this is the important setting for SSL:
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_connect_timeout 240;
proxy_send_timeout 240;
proxy_read_timeout 240;
proxy_pass http://tomcat;
}
}
Sync with mozilla ssl configuration recommendations to ensure best security set-up.
- apache2: To enable these site configs, you need to link them into
/etc/nginx/sites-enabled/
and force-reload your nginx instance.
This is the SSL site configuration in /etc/apache2/sites-enabled/
: <IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster@example.com
ServerName www.example.com
ServerAlias example.com
#
# DOCUMENT ROOT
#
DocumentRoot /srv/example.com/htdocs/
<Directory /srv/example.com/htdocs/>
Options Indexes MultiViews
AllowOverride all
Order allow,deny
allow from all
</Directory>
<Location "/manager">
Order deny,allow
deny from all
allow from your.allowed.v4.ip
</Location>
#
ServerSignature Off
#
#
ErrorLog /var/log/apache2/ssl_error.log
#
LogLevel warn
CustomLog /var/log/apache2/ssl_access.log combined
CustomLog /var/log/apache2/ssl_access_log_time.log common-time
#
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.pem
SSLCertificateChainFile /etc/ssl/certs/ca_chain.crt
SSLCACertificateFile /etc/ssl/certs/ca_root.crt
# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLHonorCipherOrder on
</VirtualHost>
</IfModule>
Sync with mozilla ssl configuration recommendations to ensure best security set-up.
In contrast to nginx, apache2 requires the proxy configuration to be placed in /etc/apache2/mods-enabled/proxy.conf
: <IfModule mod_proxy.c>
ProxyAddHeaders On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass /manager http://127.0.0.1:8080/manager
ProxyPassReverse /manager https://www.example.com/manager
ProxyPreserveHost On
</IfModule>
- Optional: Add redirect all or context only to ssl for http (port 80) requests
- nginx: Redirect http to https site in
/etc/nginx/sites-available/
: server {
listen 80;
if ($remote_addr != 127.0.0.1) {
return 301 https://$host$request_uri;
}
if ($request_uri != /nginx_status) {
return 301 https://$host$request_uri;
}
server_name www.example.com;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
This example contains the optional redirect all to HTTPS config with /nginx_status
context for local monitoring systems.
- apache2: This configuration pushes all requests to SSL in
/etc/apache2/sites-enabled/
: NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.example.com Redirect permanent / https://www.example.com/
</VirtualHost>
- Set-Up servlet container (e.g. apache tomcat 8)
- Limit to localhost in
/etc/tomcat8/server.xml
: <?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
URIEncoding="UTF-8"
redirectPort="8443"
<!-- <=== The next line limits to localhost -->
address="127.0.0.1" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
- Set-Up SSL cert (e.g. Debian based linuxes)
Abstract steps are the following:
- Optional: create certificate signing request (CSR) on the server.
- Request certificate from your authority (CA) with or without CSR.
- Install CA root and optional chain certificates on your server.
- Install your certificate on your server.
- Install en-/decrypted private key for your certificate on your server.
- Configure your webserver (see steps above).
- Reload/-start your server and perform the next step. Detailed steps are available from e.g. http://tcsoftware.net/blog/2012/02/installing-class-1-startssl-certificate-on-debian/
- Validate set-up e.g. https://ssllabs.com/ssltest/analyze.html?d=your.newly.secured.host.example.com
Issues
External References