[vpsFree.cz: community-list] Fixing Nginx 101

Petr Kutalek petr at kutalek.cz
Sun Jun 14 22:56:35 CEST 2020


TL;DR něco k nastavení Nginx

Ahoj,

když se tady poslední dobou probírá dost Nginx, tak jsem si říkal, že 
zkusím napsat nějaké poznámky, které jsem jinde uceleně nenašel, k 
věcem, co mi přišly špatné. Snad to někomu pomůže. Přeci jen je prima, 
pokud ty služby máme nastaveny správně. Omlouvám se všem, pro které to 
byly sovy v Aténách.

Předně musím říct, že já mám Nginx nesmírně rád; myslím si, že Igor 
Sysojev odvedl výbornou práci a trošku mu závidím.
Již jsem nějaký ten Nginx nastavil (včetně vlastních modulů), takže vím, 
co mne také na něm hněvá.

1) tip: dejte si pozor na to, že Nginx v upstreamu nepoužívá při HTTPS 
SNI. `proxy_ssl_server_name on`, defaultně je to off;

2) Nginx neumí ještě ani v roce 2020 volbu ekvivalentní `strict-sni` v 
HAProxy, bug je na to veden 8 let a z vývojářů je cítit lehká arogance a 
nepochopení stavu věci [https://trac.nginx.org/nginx/ticket/195]. 
Někteří to řeší tak, že dávají HAProxy před Nginx, což je IMO overkill.
Pokud mi na HTTPS přistupuje klient a neuvede SNI pole v TLS, Nginx 
použije defaultně první TLS certifikát, který má v konfiguraci uvedený. 
Mi se to nelíbí a nedává mi to smysl. Je radost se podívat, jak mají 
weby vedené u Cloudflare ve Qualys SSL reportu pouze jeden certifikát.
(Tady je vidět rozdíl: nějaký náhodný Cloudflare hostovaný web: 
https://www.ssllabs.com/ssltest/analyze.html?d=oops.ml&s=2606%3a4700%3a3037%3a0%3a0%3a0%3aac43%3ac0d7 
a tady se omlouvám Janovi, že jsem vzal jeho web, ale nic jiného mne 
nenapadlo: 
https://www.ssllabs.com/ssltest/analyze.html?d=www.zazen-nudu.cz&s=37.205.10.48 
(certificate 2 pro No SNI))
Z vlastních zkušeností mohu říci, že bez SNI a s chybným SNI, mám 
výhradně závadný provoz z Ruska a Číny a takový, kde si jakýsi člen 
vpsFree, co měl "mé" IPv4 a IPv6 adresy předemnou, zapomenul zrušit 
záznamy v DNS u svých klientů.
Možnost je snadno opatchovat Nginx, nebo trochu zneužít nastavení TLS. 
Pokud nepoužijeme TLSv1.3, nýbrž pouze TLSv1.2(!), je možné Nginx jako 
první TLS http/server nastavit tak, že bude podporovat pouze aNULL 
cipher suite (tj. bez autentizace, takže nebude nabízet certifikát pro 
Server Hello) a takovéto spojení budeme zavírat bez odpovědi:
```
$ less /etc/nginx/nginx.conf


http {
     ssl_protocols TLSv1.2;  # we do not want TLSv1.3 because of "strict 
sni" workaround
     ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256";
     ssl_ecdh_curve "prime256v1";

# aka "strict sni" workaround
# https://trac.nginx.org/nginx/ticket/195
server {
     listen *:443 ssl http2;
     listen [::]:443 ssl http2;
     server_name --;
     ssl_ciphers "ADH-AES128-SHA256";  # aNULL cipher, no authentication, 
no cert :)
     ssl_stapling off;
     ssl_certificate certs/dummy.pem;  # it could be sneak-oil etc.
     ssl_certificate_key certs/dummy.key;

     return 444;  # non-standard code that closes the connection
}

server {
     listen *:443 ssl http2;
     listen [::]:443 ssl http2;
     server_name example.com;
     root /srv/http/example.com;
     index index.txt index.html;
     ssl_certificate certs/example.com.pem;
     ssl_certificate_key certs/example.com.key;

     // …
}

server {
     listen *:443 ssl http2;
     listen [::]:443 ssl http2;
     server_name sample.cz;
     root /srv/http/sample.cz;
     index index.txt index.html;
     ssl_certificate certs/sample.cz.pem;
     ssl_certificate_key certs/sample.cz.key;

     // …
}
}
```
OK, funguje to pěkně, funguje to dokonce správně, ale s použitím TLSv1.3 
to padá. Ovšem zdá se, že to vývojáři nakonec řešit budou. :)

(Dalo by se to asi i řešit přes iptables, 
https://github.com/Lochnair/xt_tls, ale do toho jsem se pouštět 
nechtěl.)

3) Nginx chybně pracuje s OCSP Must-Staple certifikáty:
Pokud máte v certifikátu "OCSP Must-Staple" assertion (OID 
1.3.6.1.5.5.7.1.24), což tedy doporučuji, podporuje je i Let's Encrypt, 
Nginx jako první odpověď po restartu OCSP nepošle(!), teprve si jej 
získá a bude jej již běžně posílat až s druhou a další odpovědí. Ovšem 
to není košér, protože první odpověď je bez OCSP, ovšem s cert. 
příznakem Must-Staple.
Vyřešil jsem to tak, že jsem si na nginx.service v systemd (protože jej 
mám rád) nabindoval druhou service (spouštěnou/zastavenou automaticky 
spolu s nginx), která mi provede první dotazy přes s_client v openssl:
```
$ less /etc/systemd/system/nginx-ocspfix.service


[Unit]
Description=nginx OCSP fix
Wants=network-online.target
After=network-online.target
BindsTo=nginx.service
After=nginx.service

[Service]
Type=oneshot
User=nobody
Group=nobody
ExecStart=/usr/local/bin/nginx-ocspfix.sh
RemainAfterExit=true

[Install]
WantedBy=nginx.service
```

a

```
$ less /usr/local/bin/nginx-ocspfix.sh


#!/bin/bash

for c in /etc/nginx/certs/*.pem; do
     domains=$(openssl x509 -noout -text -in $c | grep DNS: | perl -l 
-0777 -ne '@names=/\bDNS:([^\s,]+)/g; print join("\n", sort @names);' | 
sort -u)
     for d in $domains; do
         openssl s_client -connect 127.0.0.1:443 -servername $d -status < 
/dev/null > /dev/null 2> /dev/null
     done
done
```

4) Pikoška – malé tiskací "P", které mne stálo hromadu času, ale spolu s 
Googlem jsem to dohromady dal (vize přílohu):
Ve své konfiguraci preferuji své pořadí cipher suites (AES-GCM), ovšem s 
tím, že umožňuji využít CHACHA20-POLY1305, pokud klient preferuje ji, 
protože je energeticky méně náročná, typicky nemá-li klient v CPU 
akcelerované AES-GCM (AES-NI instrukce pro AES a PCLMULQDQ pro Galois 
Field operace v x86), jedná se většinou o nějaké Androidy.
Nginx to nastavit umožňuje s novým openssl, ovšem je mu trošku pomoci s 
konfigurací. Opět využívám systemd – v proměnných prostředí mu předávám 
vlastní konfiguraci openssl.conf:

```$ less /etc/nginx/openssl.conf


openssl_conf = default_conf

[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
Options = ServerPreference,PrioritizeChaCha
```

a

```
$ less /etc/systemd/system/nginx.service.d/override.conf


[Unit]
Wants=network-online.target
After=network-online.target

[Service]
Environment=OPENSSL_CONF=/etc/nginx/openssl.conf
```

A jde to! :)

5) QUIC (HTTP/3) netřeba ani vzpomínat, Cloudflare dokonce připravilo 
patche a nic…

OK, dost stesku nad Nginx, přeji všem pěkně nastavený Nginx, ať už dělá 
proxy nebo servíruje obsah! :)

Petr
-------------- next part --------------
A non-text attachment was scrubbed...
Name: screenshot_20200614_222405_cutout.png
Type: image/png
Size: 136563 bytes
Desc: not available
URL: <http://lists.vpsfree.cz/pipermail/community-list/attachments/20200614/0594650d/attachment-0001.png>


More information about the Community-list mailing list