×

不久前CloudFlare正式为CDN全面启用了ECH(Encrypted Client Hello)功能,搭配DoH可以实现加密真实的SNI(Server Name Indication),而明文显示Public Name。如经过CloudFlare CDN 并启用ECH后,明文SNI为cloudflare-ech.com

加密后的真实SNI至少在客户端和CloudFlare CDN之间是无法被第三方获知的,从而提供更强的隐私保障,并且由于不显示真实的SNI,根据SNI进行阻断连接的方法更加受到限制,除非将所有SNI为cloudflare-ech.com的连接一同阻断。

我们可以使用 Curl 作为测试ECH和HTTP/3连接的工具,目前这些功能依然还处于测试过程中,并且实现了HTTP/3的ssl库非常多(如openssl/openssl, quictls/openssl, cloudflare/quiche等,官方编译指南),但是貌似只有cloudflare/quiche同时支持ECH和HTTP/3。

编译quiche需要使用到rust,并且有版本要求

sudo apt install git net-tools cmake build-essential libssl-dev zlib1g-dev libbrotli-dev libzstd-dev autoconf automake libtool libpsl-dev libnghttp2-dev pkg-config 
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"
git clone --recursive -b 0.22.0 https://github.com/cloudflare/quiche
git clone https://github.com/curl/curl
cd quiche
cargo build --package quiche --release --features ffi,pkg-config-meta,qlog
ln -s libquiche.so target/release/libquiche.so.0
mkdir quiche/deps/boringssl/src/lib
ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/
cd ../curl
autoreconf -fi
./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release --enable-ech --with-zlib --with-brotli --with-zstd --enable-versioned-symbols
make

编译完后程序在./src/curl,以下是版本信息和测试示例,可选--http3代替--http2,可以发现sni=encrypted

# /root/curl/src/curl --version
curl 8.11.0-DEV (x86_64-pc-linux-gnu) libcurl/8.11.0-DEV BoringSSL zlib/1.2.13 brotli/1.0.9 zstd/1.5.4 libidn2/2.3.3 libpsl/0.21.2 nghttp2/1.52.0 quiche/0.22.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli ECH HSTS HTTP2 HTTP3 HTTPS-proxy IDN IPv6 Largefile libz NTLM PSL SSL threadsafe UnixSockets zstd
# /root/curl/src/curl -vv --ech true --http2 --doh-url https://one.one.one.one/dns-query https://v2ex.com/cdn-cgi/trace
07:38:45.515882 [0-0] * Some HTTPS RR to process
07:38:45.516165 [0-0] * Host v2ex.com:443 was resolved.
07:38:45.516217 [0-0] * IPv6: 2606:4700:10::6814:30b4, 2606:4700:10::ac43:23d3, 2606:4700:10::6814:2fb4
07:38:45.516265 [0-0] * IPv4: 172.67.35.211, 104.20.48.180, 104.20.47.180
07:38:45.516323 [0-0] * [HTTPS-CONNECT] added
07:38:45.516378 [0-0] * [HTTPS-CONNECT] connect, init
07:38:45.516430 [0-0] * [HTTPS-CONNECT] connect, check h21
07:38:45.516509 [0-0] *   Trying [2606:4700:10::6814:30b4]:443...
07:38:45.516606 [0-0] * Immediate connect fail for 2606:4700:10::6814:30b4: Network is unreachable
07:38:45.516693 [0-0] * [HTTPS-CONNECT] connect -> 0, done=0
07:38:45.516746 [0-0] * [HTTPS-CONNECT] adjust_pollset -> 0 socks
07:38:45.516802 [0-0] * [HTTPS-CONNECT] connect, check h21
07:38:45.516865 [0-0] *   Trying [2606:4700:10::ac43:23d3]:443...
07:38:45.516928 [0-0] * Immediate connect fail for 2606:4700:10::ac43:23d3: Network is unreachable
07:38:45.516989 [0-0] * [HTTPS-CONNECT] connect -> 0, done=0
07:38:45.517081 [0-0] * [HTTPS-CONNECT] adjust_pollset -> 0 socks
07:38:45.517152 [0-0] * [HTTPS-CONNECT] connect, check h21
07:38:45.517212 [0-0] *   Trying [2606:4700:10::6814:2fb4]:443...
07:38:45.517284 [0-0] * Immediate connect fail for 2606:4700:10::6814:2fb4: Network is unreachable
07:38:45.517353 [0-0] *   Trying 172.67.35.211:443...
07:38:45.517459 [0-0] * [HTTPS-CONNECT] connect -> 0, done=0
07:38:45.517508 [0-0] * [HTTPS-CONNECT] adjust_pollset -> 1 socks
07:38:45.519573 [0-0] * [HTTPS-CONNECT] connect, check h21
07:38:45.519672 [0-0] * ECH: ECHConfig from DoH HTTPS RR
07:38:45.519733 [0-0] * ECH: imported ECHConfigList of length 71
07:38:45.519782 [0-0] * ALPN: curl offers h2,http/1.1
07:38:45.519996 [0-0] * TLSv1.2 (OUT), TLS handshake, Client hello (1):
07:38:45.526047 [0-0] *  CAfile: /etc/ssl/certs/ca-certificates.crt
07:38:45.526104 [0-0] *  CApath: /etc/ssl/certs
07:38:45.526135 [0-0] * [HTTPS-CONNECT] connect -> 0, done=0
07:38:45.526187 [0-0] * [HTTPS-CONNECT] adjust_pollset -> 1 socks
07:38:45.526244 [0-0] * [HTTPS-CONNECT] connect, check h21
07:38:45.526319 [0-0] * TLSv1.2 (IN), TLS handshake, Server hello (2):
07:38:45.526378 [0-0] * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
07:38:45.526627 [0-0] * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
07:38:45.526680 [0-0] * TLSv1.3 (IN), TLS handshake, Certificate (11):
07:38:45.526833 [0-0] * TLSv1.3 (IN), TLS handshake, CERT verify (15):
07:38:45.527941 [0-0] * TLSv1.3 (IN), TLS handshake, Finished (20):
07:38:45.528020 [0-0] * TLSv1.3 (OUT), TLS handshake, Finished (20):
07:38:45.528129 [0-0] * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / [blank] / UNDEF
07:38:45.528162 [0-0] * ALPN: server accepted h2
07:38:45.528201 [0-0] * Server certificate:
07:38:45.528234 [0-0] *  subject: CN=v2ex.com
07:38:45.528260 [0-0] *  start date: Oct 22 23:27:50 2024 GMT
07:38:45.528291 [0-0] *  expire date: Jan 20 23:27:49 2025 GMT
07:38:45.528332 [0-0] *  subjectAltName: host "v2ex.com" matched cert's "v2ex.com"
07:38:45.528367 [0-0] *  issuer: C=US; O=Let's Encrypt; CN=E5
07:38:45.528404 [0-0] *  SSL certificate verify ok.
07:38:45.528442 [0-0] * [HTTPS-CONNECT] connect+handshake h21: 12ms, 1st data: 8ms
07:38:45.528497 [0-0] * [HTTP/2] [0] created h2 session
07:38:45.528539 [0-0] * [HTTP/2] [0] -> FRAME[SETTINGS, len=18]
07:38:45.528577 [0-0] * [HTTP/2] [0] -> FRAME[WINDOW_UPDATE, incr=1048510465]
07:38:45.528610 [0-0] * [HTTP/2] cf_connect() -> 0, 1,
07:38:45.528632 [0-0] * [HTTPS-CONNECT] connect -> 0, done=1
07:38:45.528654 [0-0] * Connected to v2ex.com (172.67.35.211) port 443
07:38:45.528678 [0-0] * using HTTP/2
07:38:45.528735 [0-0] * [HTTP/2] [1] OPENED stream for https://v2ex.com/cdn-cgi/trace
07:38:45.528759 [0-0] * [HTTP/2] [1] [:method: GET]
07:38:45.528786 [0-0] * [HTTP/2] [1] [:scheme: https]
07:38:45.528815 [0-0] * [HTTP/2] [1] [:authority: v2ex.com]
07:38:45.528847 [0-0] * [HTTP/2] [1] [:path: /cdn-cgi/trace]
07:38:45.528897 [0-0] * [HTTP/2] [1] [user-agent: curl/8.11.0-DEV]
07:38:45.528955 [0-0] * [HTTP/2] [1] [accept: */*]
07:38:45.528995 [0-0] * [HTTP/2] [1] submit -> 87, 0
07:38:45.529055 [0-0] * [HTTP/2] [1] -> FRAME[HEADERS, len=41, hend=1, eos=1]
07:38:45.529095 [0-0] * [HTTP/2] [0] egress: wrote 114 bytes
07:38:45.529134 [0-0] * [HTTP/2] [1] cf_send(len=87) -> 87, 0, eos=1, h2 windows 65535-65535 (stream-conn), buffers 0-0 (stream-conn)
07:38:45.529196 [0-0] > GET /cdn-cgi/trace HTTP/2
07:38:45.529196 [0-0] > Host: v2ex.com
07:38:45.529196 [0-0] > User-Agent: curl/8.11.0-DEV
07:38:45.529196 [0-0] > Accept: */*
07:38:45.529196 [0-0] >
07:38:45.529468 [0-0] * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
07:38:45.529503 [0-0] * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
07:38:45.529579 [0-0] * [HTTP/2] [0] ingress: read 40 bytes
07:38:45.529614 [0-0] * [HTTP/2] [0] <- FRAME[SETTINGS, len=18]
07:38:45.529656 [0-0] * [HTTP/2] [0] MAX_CONCURRENT_STREAMS: 100
07:38:45.529709 [0-0] * [HTTP/2] [0] ENABLE_PUSH: TRUE
07:38:45.529752 [0-0] * [HTTP/2] [1] DRAIN select_bits=1
07:38:45.529811 [0-0] * [HTTP/2] [0] <- FRAME[WINDOW_UPDATE, incr=2147418112]
07:38:45.529853 [0-0] * [HTTP/2] [0] progress ingress: inbufg=0
07:38:45.529901 [0-0] * [HTTP/2] [0] progress ingress: done
07:38:45.529944 [0-0] * [HTTP/2] [0] -> FRAME[SETTINGS, ack=1]
07:38:45.530005 [0-0] * [HTTP/2] [0] egress: wrote 9 bytes
07:38:45.530024 [0-0] * [HTTP/2] [1] cf_recv(len=102400) -> -1 81, window=0/65535, connection 1048576000/1048576000
07:38:45.530056 [0-0] * Request completely sent off
07:38:45.530096 [0-0] * [HTTP/2] [0] progress ingress: done
07:38:45.530131 [0-0] * [HTTP/2] [1] cf_recv(len=102400) -> -1 81, window=0/65535, connection 1048576000/1048576000
07:38:45.530354 [0-0] * [HTTP/2] [0] ingress: read 9 bytes
07:38:45.530399 [0-0] * [HTTP/2] [0] <- FRAME[SETTINGS, ack=1]
07:38:45.530433 [0-0] * [HTTP/2] [0] progress ingress: inbufg=0
07:38:45.530472 [0-0] * [HTTP/2] [0] progress ingress: done
07:38:45.530504 [0-0] * [HTTP/2] [1] cf_recv(len=102400) -> -1 81, window=0/65536, connection 1048576000/1048576000
07:38:45.532209 [0-0] * [HTTP/2] [0] ingress: read 152 bytes
07:38:45.532238 [0-0] < HTTP/2 200
07:38:45.532281 [0-0] * [HTTP/2] [1] local window update by 10420224
07:38:45.532310 [0-0] * [HTTP/2] [1] status: HTTP/2 200
07:38:45.532353 [0-0] < date: Fri, 25 Oct 2024 07:38:45 GMT
07:38:45.532374 [0-0] * [HTTP/2] [1] header: date: Fri, 25 Oct 2024 07:38:45 GMT
07:38:45.532432 [0-0] < content-type: text/plain
07:38:45.532483 [0-0] * [HTTP/2] [1] header: content-type: text/plain
07:38:45.532525 [0-0] < access-control-allow-origin: *
07:38:45.532551 [0-0] * [HTTP/2] [1] header: access-control-allow-origin: *
07:38:45.532582 [0-0] < server: cloudflare
07:38:45.532609 [0-0] * [HTTP/2] [1] header: server: cloudflare
07:38:45.532664 [0-0] < cf-ray: 8d808c846f57cf0a-SJC
07:38:45.532705 [0-0] * [HTTP/2] [1] header: cf-ray: 8d808c846f57cf0a-SJC
07:38:45.532731 [0-0] < x-frame-options: DENY
07:38:45.532764 [0-0] * [HTTP/2] [1] header: x-frame-options: DENY
07:38:45.532800 [0-0] < x-content-type-options: nosniff
07:38:45.532827 [0-0] * [HTTP/2] [1] header: x-content-type-options: nosniff
07:38:45.532860 [0-0] < expires: Thu, 01 Jan 1970 00:00:01 GMT
07:38:45.532893 [0-0] * [HTTP/2] [1] header: expires: Thu, 01 Jan 1970 00:00:01 GMT
07:38:45.532919 [0-0] < cache-control: no-cache
07:38:45.532957 [0-0] * [HTTP/2] [1] header: cache-control: no-cache
07:38:45.532982 [0-0] * [HTTP/2] [1] <- FRAME[HEADERS, len=143, hend=1, eos=0]
07:38:45.533022 [0-0] <
07:38:45.533091 [0-0] * [HTTP/2] [1] DRAIN select_bits=1
07:38:45.533138 [0-0] * [HTTP/2] [0] progress ingress: inbufg=0
07:38:45.533179 [0-0] * [HTTP/2] [0] ingress: read 212 bytes
fl=464f176
h=v2ex.com
ip=143.198.50.203
ts=1729841925.826
visit_scheme=https
uag=curl/8.11.0-DEV
colo=SJC
sliver=none
http=http/2
loc=US
tls=TLSv1.3
sni=encrypted
warp=off
gateway=off
rbi=off
kex=X25519
07:38:45.533249 [0-0] * [HTTP/2] [1] <- FRAME[DATA, len=203, eos=0, padlen=0]
07:38:45.533280 [0-0] * [HTTP/2] [1] DATA, window=203/10485760
07:38:45.533308 [0-0] * [HTTP/2] [0] progress ingress: inbufg=0
07:38:45.533365 [0-0] * [HTTP/2] [0] ingress: read 9 bytes
07:38:45.533402 [0-0] * [HTTP/2] [1] <- FRAME[DATA, len=0, eos=1, padlen=0]
07:38:45.533435 [0-0] * [HTTP/2] [1] DATA, window=203/10485760
07:38:45.533463 [0-0] * [HTTP/2] [1] CLOSED
07:38:45.533496 [0-0] * [HTTP/2] [1] DRAIN select_bits=1
07:38:45.533539 [0-0] * [HTTP/2] [0] progress ingress: inbufg=0
07:38:45.533579 [0-0] * [HTTP/2] [1] DRAIN select_bits=1
07:38:45.533617 [0-0] * [HTTP/2] [0] progress ingress: done
07:38:45.533651 [0-0] * [HTTP/2] [1] returning CLOSE
07:38:45.533672 [0-0] * [HTTP/2] handle_stream_close -> 0, 0
07:38:45.533707 [0-0] * [HTTP/2] [1] cf_recv(len=102400) -> 0 0, window=-1/-1, connection 1048575797/1048576000
07:38:45.533751 [0-0] * Connection #0 to host v2ex.com left intact

不建议安装测试版curl,比较麻烦,一种方法是添加alias(推荐),在.zshrc.bashrc末尾添加

alias curl='/root/src/curl/src/curl' 注意修改为你的文件位置

再 source .zshrc.bashrc

发表回复

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

相关文章

Canokey固件

编译好的适用于nRF52840 dongle...

读出全部

注册claude账号

注册claude需要进行短信验证,可以使用5...

读出全部

Adobe分流规则

Adobe软件通过与下列服务器通信检测是否为...

读出全部

Github Copilot 解封记录

使用copilot被封禁,可以开工单让客服帮...

读出全部

如何订阅ChatGPT Plus

由于openai的限制,无法直接使用中国大陆...

读出全部