Opened 10 years ago

Closed 10 years ago

Last modified 2 years ago

#676 closed defect (wontfix)

Different ssl_protocols per server won`t work

Reported by: Roman Pavlík Owned by:
Priority: major Milestone:
Component: nginx-core Version: 1.6.x
Keywords: Cc:
uname -a: Linux office-server 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.6.2
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt=-Wl,-z,relro --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_spdy_module --with-http_sub_module --with-http_xslt_module --with-mail --with-mail_ssl_module --add-module=/tmp/buildd/nginx-1.6.2/debian/modules/nginx-auth-pam --add-module=/tmp/buildd/nginx-1.6.2/debian/modules/nginx-dav-ext-module --add-module=/tmp/buildd/nginx-1.6.2/debian/modules/nginx-echo --add-module=/tmp/buildd/nginx-1.6.2/debian/modules/nginx-upstream-fair --add-module=/tmp/buildd/nginx-1.6.2/debian/modules/ngx_http_substitutions_filter_module

Description

I configured Nginx for two TLS virtualhost 'example.one' and 'example.two' with two different certficates.

I need to setup TLS1.0+ for the first one and only TLS1.2 for the second one. However the second one (example.two) configuration ignores ssl_protocols directive and takes ssl_procolols from first server directive.

So both server directive uses the first configured ssl_protocols directive.

server {
    listen          443 default_server ssl spdy;
    server_name     example.one;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    ssl_certificate         /certs/cert-for-example.one.pem;
    ssl_certificate_key     /certs/privkey-for-example.one.pem;


    # another ssl_* directives ...
}


server {
    listen          443 ssl spdy;
    server_name     example.two;

    ssl_protocols TLSv1.2;

    ssl_certificate         /certs/cert-for-example.two.pem;
    ssl_certificate_key     /certs/privkey-for-example.two.pem;

    # another ssl_* directives ...
}


I don't want to use SSL3 so the TLS SNI should work fine and I believe Nginx can decide which ssl_protocols directive to use based on server name provided in client Hello packet.

Change History (9)

comment:1 by Maxim Dounin, 10 years ago

Resolution: wontfix
Status: newclosed

This is per OpenSSL behaviour, and there isn't much nginx can do to fix this. See detailed explanation and previous discussion in this thread.

comment:2 by norstbox@…, 9 years ago

As a workaround, there are a possible to restrict TLS protocol version using "ssl_ciphers" directive. Supplying TLSv1.2 specific cipher suites will effectively prevent handshake for lower TLS versions. So, for above example,

ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256';

instead "ssl_protocols TLSv1.2;" will do the trick.

comment:3 by Maxim Dounin, 8 years ago

See also #844.

comment:4 by Maxim Dounin, 5 years ago

See also #1948.

comment:5 by Maxim Dounin, 5 years ago

See also #1967, #1968.

comment:6 by Maxim Dounin, 4 years ago

See also #2015.

comment:7 by Maxim Dounin, 3 years ago

See also #2352.

comment:8 by Thomas Spear, 2 years ago

Hi, I was trying to get something working similar to the OP using current configuration best practices and I wanted to share my findings.

Due to what Maxim mentioned 8 years ago, whatever value is specified for ssl_protocols in the default server { } block is going to be set across all endpoints even if you try to override it in a specific non-default server { } block.

If you need to require only TLSv1.3 for some endpoints and allow TLSv1.2 for some other endpoints, then you will need to have a second instance of nginx, or offload your SSL termination before traffic gets to the nginx instance, or some other method.

That being said, this is the most secure configuration I could come up with in 2022 using a single nginx instance. It's not perfect due to this issue but it's close.

In the default server configuration:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
ssl_prefer_server_ciphers on;

Normally with TLSv1.3 I read that it's best to set ssl_prefer_server_ciphers to off, because all ciphers are considered secure, and so that devices not supporting AES hardware acceleration can choose the Chacha20 cipher instead of being forced to use
AES even without the acceleration, but here since you are allowing TLSv1.2, you need to prefer server ciphers for security reasons.

Therefore, this config may not pass SSL Labs more modern test checks because of preferring server ciphers and allowing TLSv1.2.

Again, I'll reiterate that if you remove TLSv1.2 from the above in the default server, then TLSv1.2 will be disabled across all endpoints. Even if a specific server other than the default one has TLSv1.2 listed in the ssl_protocols it will not accept TLSv1.2.

You must handle SSL termination elsewhere outside of your nginx instance or have more than one instance configured, in order to have different ssl_protocols configurations for the different endpoints.

Version 5, edited 2 years ago by Thomas Spear (previous) (next) (diff)

comment:9 by Maxim Dounin, 2 years ago

If you need to require only TLSv1.3 for some endpoints and allow TLSv1.2 for some other endpoints, then you will need to have a second instance of nginx, or offload your SSL termination before traffic gets to the nginx instance, or some other method.

No, you don't need a second instance of nginx. You can easily configure nginx with different SSL settings for different listening sockets, for example:

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

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

The ticket is about not being able to configure different SSL protocols for different name-based virtual servers on a single listening socket. This is, unfortunately, not possible due to OpenSSL limitations.

For more information about configuring server blocks in nginx, as well as configuring HTTPS servers, consider the How nginx processes a request and Configuring HTTPS servers articles.

Note: See TracTickets for help on using tickets.