Strict SNI validator for Nginx
The ngx_http_ssl_strict_sni module is a validator of the integrity of SNI and the Host header. This blocks "SNI spoofing" to virtual hosts. Without ssl, this module has no effects.
Nginx doesn't and won't check the integrity of SNI and Host header, resulting to allowing "SNI spoofing" between virtual hosts.
Reproduction: let two virtual host aaa.com
and bbb.com
listen on 443 as https servers with their names.
nginx.conf
:
server{
server_name aaa.com;
...
root /srv/www/com.aaa;
}
server{
server_name bbb.com;
...
root /srv/www/com.bbb;
strict_sni: on; # here we enable this module
}
/srv/www/com.aaa/foo.txt
:
Here is aaa.com.
/srv/www/com.bbb/foo.txt
:
Here is bbb.com.
With normal requests, we get /foo.txt
in the server specified in the domain:
$ curl https://aaa.com/foo.txt
Here is aaa.com.
$ curl https://bbb.com/foo.txt
Here is bbb.com.
However, we cat get aaa.com/foo.txt
with URL bbb.com/foo.txt
, by adding false Host
header:
$ curl -H "Host: aaa.com" https://bbb.com/foo.txt
Here is aaa.com. # <-- intruded!
This module adds the validation step of SNI and Host header, and when the request violate the rule, it immediately return Status 421 Misdirected Request:
$ curl -H "Host: bbb.com" https://aaa.com/foo.txt
<html>
<head><title>421 Misdirected Request</title></head>
<body>
<center><h1>421 Misdirected Request</h1></center>
<hr><center>nginx</center>
</body>
</html>
This explanation is written based on the article below:
NGINXリバースプロキシでTLS Server Name Indication (SNI)と異なるドメイン名のバックエンドホストへルーティングできちゃう件について
Currently, only the Debian repository for Debian is available. The package name is changed to libnginx-mod-http-ssl-strict-sni
following the standard name style of Nginx modules.
Supported Codename: bullseye
, bookworm
Supported Architecture: arm64
, amd64
Important
2024/03/28: PGP repository signature added! Existing user should update their apt configuration.
Important
2024/04/13: Repository URL changed! Existing user should update the URL written in ngx-strict-sni.list
.
curl -fsSL https://jyjyjcr.github.io/ngx-strict-sni/publish/gpg.key.asc | sudo gpg --dearmor -o /etc/apt/keyrings/ngx-strict-sni.gpg
sudo echo "deb [signed-by=/etc/apt/keyrings/ngx-strict-sni.gpg] https://jyjyjcr.github.io/ngx-strict-sni/publish/deb $(cat /etc/os-release|grep VERSION_CODENAME|sed -e 's/^.*=//g') main" > "/etc/apt/sources.list.d/ngx-strict-sni.list"
sudo apt update
sudo apt install libnginx-mod-http-ssl-strict-sni
Syntax: strict_sni on | off;
Default: strict_sni off;
Context: http
, server
, location
http {
...
strict_sni on; # enable the validator for any https request
...
server{
server_name strict.com;
...
}
server{
server_name loose.com;
...
strict_sni off; # but disable for any https request aimed (not by SNI but Host header) to loose.com
...
location /strict/ {
strict_sni on; # and re-enable for any to loose.com/strict/
...
}
}
}
This module is written in Rust using ngx crate. The original repository is here, and the modified one is here.