Most secure SSL/TLS configuration for Apache, Nginx, Postfix, Dovecot, HAProxy and other

What is a cipher suite?


Cipher suites decide how secure, compatible and fast your HTTPS website is. A cipher suite is a set of information that helps determine how your web server will communicate secure data over HTTPS. A web server uses certain protocols and algorithms to determine how it will secure your web traffic. These are the ingredients of a secure connection. A cipher suite is essentially a list of those ingredients.

Here is an example of a cipher suite:

cipher suite elements

Using the above cipher suite, let’s see what those ingredients are.

  • ECDHE is the key exchange algorithm
  • ECDSA is the authentication algorithm
  • AES128 is the bulk encryption algorithm
  • SHA256 is the MAC algorithm

These algorithms are part of what is used to create and secure your HTTPS traffic. Your web server has a list of cipher suites if it is using HTTPS. The list will look something like this:

ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

If you look closely, you will see that this is simply a list of cipher suites separated by colons (:).

What do cipher suites do?


Cipher suites are an integral part of how your website functions over HTTPS. They list the various algorithms that cover the spectrum of the data security process (key exchange, authentication, encryption, etc.).

Since there are so many computers with different versions of operating systems, using different versions of different browsers, there needs to be a way to accommodate all possible combinations.

This is where cipher suites come to the rescue. When making a connection, a web server and browser can compare their lists of cipher suites, see if they are compatible, and if so determine which cipher suite to use. This is an important part of the “handshake” that happens when a server and browser make a connection.

Strong Ciphers for Apache, nginx and Lighttpd


Apache


SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder On

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff

# Requires Apache >= 2.4
SSLCompression off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"

# Requires Apache >= 2.4.11
SSLSessionTickets Off

Nginx


ssl_protocols TLSv1.3;# Requires nginx >= 1.13.0 else use TLSv1.2
ssl_prefer_server_ciphers on; 
ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0

ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9

ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7

resolver $DNS-IP-1 $DNS-IP-2 valid=300s;
resolver_timeout 5s; 

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

Lighttpd


ssl.honor-cipher-order = "enable"
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
ssl.use-compression = "disable"
setenv.add-response-header = (
    "Strict-Transport-Security" => "max-age=63072000; includeSubDomains; preload",
    "X-Frame-Options" => "DENY",
    "X-Content-Type-Options" => "nosniff"
)
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"

Other Software


HaProxy


global
   ssl-default-bind-options no-sslv3 no-tls-tickets force-tlsv12
   ssl-default-bind-ciphers AES128+EECDH:AES128+EDH

frontend http-in
      mode http
      option httplog
      option forwardfor
      option http-server-close
      option httpclose
      bind 192.0.2.10:80
      redirect scheme https code 301 if !{ ssl_fc }

frontend https-in
    option httplog
    option forwardfor
    option http-server-close
    option httpclose
    rspadd Strict-Transport-Security:\ max-age=31536000;\ includeSubDomains;\ preload
    rspadd X-Frame-Options:\ DENY
    bind 192.0.2.10:443 ssl crt /etc/haproxy/haproxy.pem ciphers AES128+EECDH:AES128+EDH force-tlsv12 no-sslv3

Postfix


smtpd_use_tls=yes
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_cert_file=/etc/ssl/postfix.cert
smtpd_tls_key_file=/etc/ssl/postfix.key
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_mandatory_ciphers = medium
tls_medium_cipherlist = AES128+EECDH:AES128+EDH

Exim


tls_certificate = /etc/exim.cert
tls_privatekey = /etc/exim.key
tls_advertise_hosts = *
tls_require_ciphers = AES128+EECDH:AES128+EDH
openssl_options = +no_sslv2 +no_sslv3

Dovecot


ssl = yes
ssl_cert = </etc/dovecot.cert
ssl_key = </etc/dovecot.key
ssl_protocols = !SSLv2 !SSLv3
ssl_cipher_list = AES128+EECDH:AES128+EDH
ssl_prefer_server_ciphers = yes # >Dovecot 2.2.6
ssl_dh_parameters_length = 4096 # >Dovecot 2.2

ProFTPd


TLSEngine on
TLSLog /var/ftpd/tls.log
TLSProtocol TLSv1.2
TLSRequired on
TLSCipherSuite AES128+EECDH:AES128+EDH
TLSRSACertificateFile /etc/proftpd.cert
TLSRSACertificateKeyFile /etc/proftpd.key

MySQL


[mysqld]
ssl-ca=/etc/mysql-ssl/ca-cert.pem
ssl-cert=/etc/mysql-ssl/server-cert.pem
ssl-key=/etc/mysql-ssl/server-key.pem
ssl-cipher=AES128+EECDH:AES128+EDH
# replication:
GRANT REPLICATION SLAVE ON *.* to ‘repl’@’%’ REQUIRE SSL;
STOP SLAVE;
CHANGE MASTER MASTER_SSL=1,
MASTER_SSL_CA=’/etc/mysql-ssl/ca-cert.pem’,
MASTER_SSL_CERT=’/etc/mysql-ssl/client-cert.pem’,
MASTER_SSL_KEY=’/etc/mysql-ssl/client-key.pem';
SHOW SLAVE STATUS\G;
START SLAVE;
SHOW SLAVE STATUS\G;

PostgreSQL


ssl = on
ssl_ciphers = 'AES128+EECDH:AES128+EDH'
password_encryption = on

OpenSSH Server


Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com

OpenSSH Client


HashKnownHosts yes
Host github.com
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512
Host *
  ConnectTimeout 30
  KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
  MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
  Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
  ServerAliveInterval 10
  ControlMaster auto
  ControlPersist yes
  ControlPath ~/.ssh/socket-%r@%h:%p

Golang Server


package main

import (
    "crypto/tls"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
        w.Write([]byte("This is an example server.\n"))
    })
    cfg := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
        },
    }
    srv := &http.Server{
        Addr:         ":443",
        Handler:      mux,
        TLSConfig:    cfg,
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
    }
    log.Fatal(srv.ListenAndServeTLS("tls.crt", "tls.key"))
}

UniFi Controller


unifi.https.ciphers=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
unifi.https.sslEnabledProtocols=TLSv1.2

Sources


[https://cipherli.st/] [https://gist.github.com/gavinhungry/7a67174c18085f4a23eb] [https://michael.lustfield.net/nginx/getting-a-perfect-ssl-labs-score]

[https://www.nginx.com/blog/nginx-https-101-ssl-basics-getting-started/] [https://outspokenmedia.com/https/cipher-suites/]

Share Comments
comments powered by Disqus