Wednesday, June 27, 2018

SSL basics in Nginx


Setting up an HTTPS Server
--------------------------

Standard settings
server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;  # public key (shared to others)
    ssl_certificate_key www.example.com.key;  # private key (must be kept private)
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

HTTPS Server Optimization
-------------------------

- SSL operations consume extra CPU resources
- the most CPU-intensive is SSL handshake
- ways to minimize number of operations per client
    a. enable keepalive connections to send several requests via one connection
    b. reuse SSL session parameters to avoid SSL handshakes for parallel and
       subsequent connections
- sessions are stored in the SSL session cache shared between worker
  processes and configured by the `ssl_session_cache` directive
- one megabyte of cache contains about 4000 sessions
- default cache timeout is 5 minutes
- timeout can be increased using the `ssl_session_timeout` directive

Sample config
worker_processes auto;

http {
    ssl_session_cache   shared:SSL:10m;  # 10 MB ssl cache size
    ssl_session_timeout 10m;  # 10 minute timeout

    server {
        listen              443 ssl;
        server_name         www.example.com;
        keepalive_timeout   70;

        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...
    }
}

Optimizing SSL Session Cache
----------------------------

- SSL session cache reduces number of SSL handshake (improves performance)
- It is set via `ssl_session_cache` directive
- By default, Nginx uses built-in type of session cache in your SSL library
    * not optimal
    * 1 worker process can use it
    * causes memory fragmentation
- `shared` can be added to `ssl_session_cache` to share cache among all worker
   processes
    * speeds up later connections
    * connection setup is already known
- 1 MB cache size can hold 4,000 sessions
- By default, Nginx retain cache session parameters for 5 minutes
    * can be changed using `ssl_session_timeout`
    * increase value reduces number of time-consuming handshakes
    * when increased, cache size needs also to be increased

simple setup
ssl_session_cache;
cache shared among workers
ssl_session_cache shared:SSL:1m;
4 hour SSL session timeout
ssl_session_timeout 4h;
combined config
server {
   
    ssl_session_cache   shared:SSL:20m;
    ssl_session_timeout 4h;
}

SSL Certificate Chains
----------------------

- collection of certificates inside a 1 certificate
- order is important, nginx will fail if incorrect
- certificate chain is used by `ssl_certificate` directive
- some certificate authorities sign server certificates using an intermediate
  certificate and in this case the CA provides a bundle of chained certificates
  that should be concatenated to the signed server certificate

creating a certificate chain
error message received when
certificate chain has wrong
ordering inside
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)
checks to see if your HTTP
server sends the complete
certificate chain to your
clients

NOTE: if a bundle cert has
      has not been added,
      only certificate #0
      will be shown
$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com

Setting up an HTTP/HTTPS server
-------------------------------

- Nginx can be setup to act both as a HTTP and HTTPS server
- config below can be done on version 0.17.14 and above

setup
server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

Name-based HTTP Server
----------------------

- if 2 or more HTTPS server is configured to listen on 1 IP address, the
  server_name used by Nginx is the name on the server certificate
- that happened because SSL handshake occurs before the client browser sends an
  HTTP request; thus, Nginx doesn't know the server_name requsted by the client
  so it uses the one in the server certificate

server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

- the best way to resolve that issue is to assign separate IPs

server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

SSL Certificate with Several names
----------------------------------

Ways of sharing a single IP:

1. certificate with several names in the `SubjectAltName` certificate field
    - e.g: www.example.com and www.example.org
    - the said field only have limited characters

2. certificate with wild card
    - e.g: *.example.org
    - that only matches one level higher
    - matches are: www.example.org
    - doesn't match: example.org or www.sub.example.org

3. Using TLS Server Name Indication (SNI, RFC 6066)
    - allows a browser to pass requested server name during SSL handshake
    - has limited browser support
        * Opera 8.0
        * MSIE 7.0 (only on Windows Vista or higher)
        * Firefox 2.0 and other browsers using Mozilla Platform rv:1.8.1
        * Safari 3.2 .1 (Windows version supports SNI on Vista or higher)
        * Chrome (Windows version supports SNI on Vista or higher, too)
    - only domain names can be passed
    - requirements:
        * OpenSSL 0.9.8f and lower configured with `--enable-tlsext`
        * OpenSSL 0.9.8j (SNI enabled by default)


It's better to place a certificate
w/ several names together with its
private key at the `http` level so
that the rest of the configuration
inherits the same copy
ssl_certificate     common.crt;
ssl_certificate_key common.key;

server {
    listen          443 ssl;
    server_name     www.example.com;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ...
}
Nginx w/ SNI support
$ nginx -V
...
TLS SNI support enabled
...
Nginx w/o SNI support
NGINX was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available
Other SNI compatibility notes
Compatibility Notes

- The SNI support status has been shown by the “-V” switch since versions 0.8.21 and 0.7.62.
- The ssl parameter of the listen directive has been supported since version 0.7.14. Prior to version 0.8.21 it
  could only be specified along with the default parameter.
- SNI has been supported since version 0.5.32.
- The shared SSL session cache has been supported since version 0.5.6.
- From version 0.7.65, 0.8.19 and later the default SSL protocols are SSLv3, TLSv1, TLSv1.1, and TLSv1.2 (if
  supported by the OpenSSL library).
- From version 0.7.64, 0.8.18 and earlier the default SSL protocols are SSLv2, SSLv3, and TLSv1.
- From version 1.0.5 and later the default SSL ciphers are HIGH:!aNULL:!MD5
- From version 0.7.65, 0.8.20 and later the default SSL ciphers are HIGH:!ADH:!MD5
- From version 0.8.19 the default SSL ciphers are ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM
- From version 0.7.64, 0.8.18 and earlier the default SSL ciphers are ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP

No comments:

Post a Comment