在
不久前CloudFlare正式为CDN全面启用了ECH(Encrypted Client Hello)功能,搭配DoH可以实现加密真实的SNI(Server Name Indication),而明文显示Public Name。目前Nginx官方并没有推出ECH功能测试,但是openssl已经为ech添加了新的branch,ECH标准或不久将写入RFC中。
sftcd为nginx和openssl添加了ECH测试功能,貌似它的nginx/ECH-experimental
只能搭配他的openssl/ECH-draft-13c
sudo apt update sudo apt install -y build-essential ca-certificates zlib1g-dev libpcre3 libpcre3-dev tar unzip libssl-dev wget git cmake mercurial libunwind-dev pkg-config git clone https://github.com/sftcd/openssl.git git clone https://github.com/sftcd/nginx.git cd openssl git checkout ECH-draft-13c cd ../nginx git checkout ECH-experimental ./auto/configure --with-debug --prefix=/opt/ech --with-http_ssl_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=./openssl --with-openssl-opt="--debug '-Wl,--enable-new-dtags,-rpath,$(LIBRPATH)'" --with-http_v2_module make && make install
这里的配置仅用于测试ECH。然后我们需要生成一个ech公私钥对,放入指定的文件夹(由ssl_echkeydir定义)中,文件名随意,-public_name 为外层不加密的SNI,你可以自由选择
mkdir /opt/ech/conf/ech_keys ../openssl/.openssl/bin/openssl ech -public_name cloudflare-ech.com -pemout /opt/ech/conf/ech_keys/config.ech ../openssl/.openssl/bin/openssl ech -pemin /opt/ech/conf/ech_keys/config.ech #查看相关信息 tail -2 /opt/ech/conf/ech_keys/config.ech | head -1
这样我们就得到了base64编码后的ECH公钥,然后需要将这个公钥添加到域名https记录,格式如下
1 . alpn="h2" ech=公钥填在这里
如果你使用bind9自建域名解析服务器,那么你可以使用nsupdate添加https记录,注意如果网站不在443端口上会导致ECH异常,这里的https记录默认为443端口!
nsupdate -l -k /var/cache/bind/acme.key > zone domain.com > update add domain.com. 300 HTTPS 1 . alpn="h2" ech=公钥填在这里 > send > quit
以下为nginx配置(/opt/ech/conf/nginx.conf)http部分参考,当然你需要对应的证书,参考使用acme.sh签发证书
http { include mime.types; default_type application/octet-stream; ssl_echkeydir ech_keys; sendfile on; keepalive_timeout 65; server { listen 443 ssl default_server; http2 on; ssl_reject_handshake on; } server { listen 443 ssl; server_name ech.domain.com; #http2 on; ssl_certificate cert/ech.domain.com.cer; ssl_certificate_key cert/ech.domain.com.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root html; ssi on; index index.html index.htm; keepalive_timeout 0; # Force non-cache add_header Last-Modified $date_gmt; add_header Cache-Control 'no-store, no-cache'; if_modified_since off; expires off; etag off; } } }
改写html/index.html
<!DOCTYPE html> <html> <head> <title>ECH test!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <pre> HTTP host: <!--# echo var="http_host" --> ALPN protocol: <!--# echo var="ssl_alpn_protocol" --> SSL cipher: <!--# echo var="ssl_cipher" --> SSL protocol: <!--# echo var="ssl_protocol" --> SNI: <!--# echo var="ssl_server_name" --> ECH status: <!--# echo var="ssl_ech_status" --> Outer SNI (public name): <!--# echo var="ssl_ech_outer_sni" --> Inner SNI: <!--# echo var="ssl_ech_inner_sni" --> </pre> </body> </html>
使用编译好的启用ECH功能的Curl或浏览器进行测试
curl -vv --ech true --doh-url https://doh.opendns.com/dns-query https://ech.domain.com ··· ECH status: success #代表ECH功能正常 ···
参考: