×

不久前CloudFlare正式为CDN全面启用了ECH(Encrypted Client Hello)功能,搭配DoH可以实现加密真实的SNI(Server Name Indication),而明文显示Public Name。目前Nginx官方并没有推出ECH功能测试,但是openssl已经为ech添加了新的branchECH标准或不久将写入RFC中。

sftcdnginxopenssl添加了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功能正常
···

参考:

Quick set up guide for Encrypted Client Hello (ECH)

Setting Up ECH for a Website

编译支持ECH的nginx

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章