国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運營 > cdn怎么不暴露源站?

cdn怎么不暴露源站?

時間:2023-10-27 01:30:01 | 來源:網(wǎng)站運營

時間:2023-10-27 01:30:01 來源:網(wǎng)站運營

cdn怎么不暴露源站?:若是作為剛?cè)腴T的網(wǎng)站管理員,你或許知道使用 CDN 來避免暴露源站 IP。同時,你或許會采取一些常用措施,諸如:修改源站的 Hostname,對非法請求不返回或返回?zé)o關(guān)/迷惑類信息。
然而,有些東西容易被忽視,例如“證書信息”。我很確信大多數(shù)人在嘗試對非法請求返回空內(nèi)容時,沒有注意到證書信息是否也不會同時返回。還有一種容易被忽略的:忽略了默認返回塊的配置(在 Nginx 中,如果在客戶端請求時沒有攜帶 Hostname,則會返回第一個從配置文件中讀取的 server{} 塊)。
注:如果你像下面給出的示例那樣配置,你可能會覺得「服務(wù)端不會返回東西」。然而證書信息還是被返回了。

這是 nginx.conf 中僅存的 SSL 相關(guān)的塊:

server { listen 443 ssl; server_name localhost; ssl_certificate /root/cert.pem; ssl_certificate_key /root/cert.key; location / { return 444; }}然而證書信息依舊會被返回:

curl -k https://127.0.0.1 -v* Trying 127.0.0.1:443...* TCP_NODELAY set* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.2 (IN), TLS handshake, Certificate (11):* TLSv1.2 (IN), TLS handshake, Server key exchange (12):* TLSv1.2 (IN), TLS handshake, Server finished (14):* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):* TLSv1.2 (OUT), TLS handshake, Finished (20):* TLSv1.2 (IN), TLS handshake, Finished (20):* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384* ALPN, server accepted to use http/1.1* Server certificate:* subject: CN=127.0.0.1* start date: Feb 12 07:35:46 2020 GMT* expire date: Feb 13 07:35:46 2020 GMT* issuer: CN=127.0.0.1* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.> GET / HTTP/1.1> Host: 127.0.0.1> User-Agent: curl/7.58.0> Accept: */*> * Empty reply from server* Connection #0 to host 127.0.0.1 left intactcurl: (52) Empty reply from server
在開始回答前,首先要說明一下:這個回答我最初是以英文的形式發(fā)布在自己的博客中,同時也在 Stack Overflow 中做了存檔。你可能會覺得這個回答有點“翻譯腔”,但確實是原創(chuàng)回答,請不要誤會。如果你覺得本回答對你有所幫助,請幫忙 Upvote 一下,感謝。
另外,如果你需要完全地保護你的服務(wù)器 IP 不被泄露,僅僅是做我在本文中提到的部分是遠遠不夠的安全遵循短板理論[1]。任何疏忽都會導(dǎo)致不可預(yù)計的的損失。所以,你需要為自己的安全負責(zé)。我在此僅僅是介紹防止源站 IP 泄露的一些方法。如果出現(xiàn)諸如軟件設(shè)計錯誤導(dǎo)致的 IP 泄露,本文并不能幫你修正那些錯誤。

回到正題:如果你非常完全地、幸運地解決了其它任何可能會導(dǎo)致 IP 泄露的問題,那總的來說,攻擊者只能通過模仿普通用戶請求,掃描(請求)所有可能的 IP,并根據(jù)返回的結(jié)果進行判斷。在大多數(shù)情況下,你可以借由 IP 白名單來屏蔽它們的掃描,但這是要視情況而定的。你很可能不知道 CDN 用于請求你源站服務(wù)器的 IP 范圍,或者這 IP 范圍是在持續(xù)變化的。使用這種策略可能會導(dǎo)致服務(wù)中斷。

概要

如果你在閱讀過程中感到困惑,你可以先查看結(jié)論部分中的流程圖,然后再繼續(xù)閱讀。

策略

在下文闡述中,全部假定使用 Debian/Ubuntu 作為操作系統(tǒng),使用 Nginx 作為 Web 服務(wù)器。

IP 白名單

事實上,最直接、有效率阻止源站 IP 泄露的方法就是設(shè)置 IP 白名單。如果你能這么做,那就這么做。不過,請注意以下事項:

  1. 如果 CDN 服務(wù)商并沒有提供他們使用的 IP 列表,請不要使用此方案,不然可能會造成服務(wù)中斷。
  2. 如果你使用 HTTPS 作為回源協(xié)議,那么你應(yīng)當使用 iptables 而不是 Nginx 內(nèi)置的 access module,否則攻擊者依舊能通過探測證書 SNI 信息來找到你的源站服務(wù)器;
  3. 在使用 Cloudflare 作為 CDN 的情況下,僅僅通過使用 IP 白名單可能會給攻擊者機會繞過 Cloudflare 的保護找到源站服務(wù)器 IP。
如果你正在使用 iptables,請記得安裝 iptables-persistent,不然你可能會在重啟的時候丟失你的過濾規(guī)則:

apt-get install iptables-persistent
使用 iptables 對非白名單 IP 丟棄請求的示例

修改 Hostname/監(jiān)聽端口

通常來說,帶指向性的掃描器會對所有 IP 的常規(guī)端口進行帶 hostname(也是你的網(wǎng)站域名)的掃描(http/80, https/443)。所以你如果修改 Hostname 或修改監(jiān)聽端口,通常就能避免這些掃描。

通過自定義請求回源站時使用的 Hostname/域名,可以防止攻擊者通過 Hostname 找到你的源站 IP
一些 CDN 服務(wù)商支持設(shè)置自定義回源端口
然而,如果你不小心通過某種方式讓攻擊者知道了你回源用的 Hostname,或者你使用的 IP 范圍,你的源站 IP 還是有被發(fā)現(xiàn)的風(fēng)險的。所以請自行注意。

防止 SNI 信息泄露的補丁

阻止 SSL 握手的意圖是防止在非指向性掃描的情形下,證書 SNI 信息的泄露(也可以簡單認為是域名信息)。同時,在完成掃描后,攻擊者(發(fā)起非指向性掃描的人)可以建立一個基于「網(wǎng)站/域名—IP」關(guān)系的數(shù)據(jù)庫便于日后快捷檢索。

證書內(nèi)包括的域名信息,攻擊者可以據(jù)此獲知有什么網(wǎng)站正在運行(雖然不一定確實有在運行)
如果你的 Nginx 版本高于等于 1.19.4,你可以使用 ssl_reject_handshake 特性來防止 SNI 信息泄露。否則的話,你還是需要安裝 strict-sni 補丁。


注:這項措施僅當在你使用 HTTPS 作為回源協(xié)議時才有效。如果你只是想使用 HTTP 作為回源協(xié)議,你可以單純地在默認 server 塊中使用 return 444;,并且這一小段中的其它部分你可以直接跳過,或僅僅時略讀即可。

ssl_reject_handshake 的配置 (Nginx ≥ 1.19.4)

對于配置 ssl_reject_handshake,涉及兩個部分:默認塊、常規(guī)塊。

server { # 如果使用了錯誤的 Hostname,SSL 握手會被拒絕 listen 443 ssl; ssl_reject_handshake on;}server { # 對于攜帶正確 Hostname 的請求,服務(wù)器會繼續(xù)做后續(xù)處理 listen 443 ssl; server_name example.com; ssl_certificate example.com.crt; ssl_certificate_key example.com.key;}這個方法僅適用于 Nginx 大于等于 1.19.4 的情況。否則要想達到阻止 SNI 信息泄露的目的,你需要安裝strict-sni 補丁。這個補丁是由來自南韓的 PHP 開發(fā)者 Hakase 開發(fā)的,該補丁可以使 Nginx 在 1.19.3 之前的實例針對非法請求真正地空返回。

安裝 strict-sni 補丁的步驟 (Nginx ≤ 1.19.3)

首先,安裝必要的安裝包:

apt-get install git curl gcc libpcre3-dev software-properties-common /build-essential libssl-dev zlib1g-dev libxslt1-dev libgd-dev libperl-dev然后,在 OpenSSL 的發(fā)布頁中下載你想使用的版本。

下載倉庫 openssl-patch:

git clone https://git.hakase.app/Hakase/openssl-patch.git基于你之前選擇的 OpenSSL 版本,先切換至 OpenSSL 源碼的目錄,然后為 OpenSSL 打上相應(yīng)版本的補?。?br>
cd opensslpatch -p1 < ../openssl-patch/openssl-equal-1.1.1d_ciphers.patch
來自開發(fā)者的備注:OpenSSL 3.x 版本有很多 API 上的改動,對于這些 OpenSSL 版本來說,這個補丁不再有用。(特指:Chacha20 和 Equal Preference 補?。┰跅l件允許的情況下,推薦使用 OpenSSL 1.1.x。
下載你所需版本的 Nginx 安裝包。
解壓 Nginx 安裝包,切換目錄至 Nginx,然后為其打上補?。?

cd nginx/curl https://raw.githubusercontent.com/hakasenyang/openssl-patch/master/nginx_strict-sni_1.15.10.patch | patch -p1在 Nginx 的配置指令中指定 OpenSSL 的目錄:

./configure --with-http_ssl_module --with-openssl=/root/openssl重要:在實際的實踐中,僅使用這些參數(shù)并不能真正使網(wǎng)站如預(yù)期一樣運行,你需要同時添加你想要和你需要的參數(shù)。例如:如果你想要你的網(wǎng)站支持 http/2 協(xié)議,則需要添加 --with-http_v2_module 參數(shù)。它不會主動自己把自己編譯進去。

如果你意圖針對非針對性掃描,相對于返回空信息,想要把自己的服務(wù)器偽裝成其它真實存在的網(wǎng)站,以達到給掃描工具假信息的目的,你可以再添加下述參數(shù):

./configure --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_ssl_module --with-openssl=/root/openssl注:這部分是指代概要部分中「通過偽造成其它真實存在的網(wǎng)站/CDN 節(jié)點來混淆視聽」的這一節(jié),目的僅僅是給予發(fā)起非指向性掃描的人假信息。對于指向性掃描,它很難很好地達到目的。如果你只是想要對非授權(quán)客戶端返回一個假網(wǎng)站,例如:手工制作的假網(wǎng)站、設(shè)置反向代理等等(同時也對非指向性掃描器返回空結(jié)果),你應(yīng)當跳過這個部分,或者僅僅將這些參數(shù)視作「以待后用」添加。

在完成配置后,編譯并安裝 Nginx。
make && make install

安裝到這里就結(jié)束了。
出于方便,我個人習(xí)慣會在安裝完畢后執(zhí)行以下參數(shù):

ln -s /usr/lib/nginx/modules/ /usr/share/nginxln -s /usr/share/nginx/sbin/nginx /usr/sbincat > /lib/systemd/system/nginx.service <<-EOF[Unit]Description=The NGINX HTTP and reverse proxy serverAfter=syslog.target network.target remote-fs.target nss-lookup.target[Service]Type=forkingPIDFile=/run/nginx.pidExecStartPre=/usr/sbin/nginx -tExecStart=/usr/sbin/nginxExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s QUIT $MAINPIDPrivateTmp=true[Install]WantedBy=multi-user.targetEOFsystemctl enable nginx

配置 strict-sni 補丁的步驟 (Nginx ≤ 1.19.3)

和之前提到的 ssl_reject_handshake 的配置類似,有三個元素需要被配置:

  1. 控制開關(guān)
  2. 假的(默認)server 塊
  3. 常規(guī) server 塊
http { # 控制開關(guān) strict_sni on; strict_sni_header on; # 假的(默認)server 塊 server { server_name localhost; listen 80; listen 443 ssl default_server; # "default_server" 需要被寫在這里 ssl_certificate /root/cert.crt; # 可以為任意證書 ssl_certificate_key /root/cert.key; # 可以為任意證書 location / { return 444; } } # 常規(guī) server 塊 server { server_name normal_domain.tld; listen 80; listen 443 ssl; ssl_certificate /root/cert.crt; # 你的真實證書 ssl_certificate_key /root/cert/cert.key; # 你的真實證書 location / { echo "Hello World!"; } }}現(xiàn)在,非指向性掃描器不再能獲知你在這臺服務(wù)器上運行什么網(wǎng)站了,除非是被指向性掃描,也就是對方知道你的 Hostname 的情況。

注:使用 return 444; 意味著在返回 HTTP(并非 HTTPS)請求時就是字面意義的什么都不返回。如果沒有打上 openssl-patch 補丁,當客戶端嘗試建立 TLS 鏈接時,證書信息仍會被返回。
重要:在設(shè)置 strict_sni on; 后,CDN 節(jié)點若在請求源站時不攜帶 SNI 信息,將會導(dǎo)致請求失敗。參見 proxy_ssl_name.

結(jié)果

在開啟對應(yīng)選項后,證書信息不再會被返回。
啟用前:

curl -v -k https://35.186.1.1* Rebuilt URL to: https://35.186.1.1/* Trying 35.186.1.1...* TCP_NODELAY set* Connected to 35.186.1.1 (35.186.1.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.2 (IN), TLS handshake, Certificate (11):* TLSv1.2 (IN), TLS handshake, Server key exchange (12):* TLSv1.2 (IN), TLS handshake, Server finished (14):* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):* TLSv1.2 (OUT), TLS change cipher, Client hello (1):* TLSv1.2 (OUT), TLS handshake, Finished (20):* TLSv1.2 (IN), TLS handshake, Finished (20):* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384* ALPN, server accepted to use http/1.1* Server certificate:* subject: CN=normal_domain.tld* start date: Nov 15 05:41:39 2019 GMT* expire date: Nov 14 05:41:39 2020 GMT* issuer: CN=normal_domain.tld* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.> GET / HTTP/1.1> Host: 35.186.1.1> User-Agent: curl/7.58.0> Accept: */*> * Empty reply from server* Connection #0 to host 35.186.1.1 left intactcurl: (52) Empty reply from server啟用后:

curl -v -k https://35.186.1.1* Rebuilt URL to: https://35.186.1.1/* Trying 35.186.1.1...* TCP_NODELAY set* Connected to 35.186.1.1 (35.186.1.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS alert, Server hello (2):* error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name* stopped the pause stream!* Closing connection 0curl: (35) error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name謹防不知道,你應(yīng)當了解:無論你后續(xù)怎么配置客戶端校驗規(guī)則(如 HTTP 頭信息校驗等),客戶端在請求時攜帶目標/部署在服務(wù)端的 Hostname 時,證書信息仍會被返回。這是因為它的作用僅僅是預(yù)防非指向性掃描:這是建立在攻擊者保護知道這臺服務(wù)器上運行著什么網(wǎng)站的前提上的。如需應(yīng)對指向性掃描,我強烈建議在條件允許的情況下修改在源站服務(wù)器上部署的 Hostname。

使用錯誤的 Hostname 請求時的結(jié)果:(證書信息不會在 Hostname 錯誤的情況下返回)

curl -v -k --resolve wrong_domain.tld:443:35.186.1.1 https://wrong_domain.tld* Added wrong_domain.tld:443:35.186.1.1 to DNS cache* Rebuilt URL to: https://wrong_domain.tld/* Hostname wrong_domain.tld was found in DNS cache* Trying 35.186.1.1...* TCP_NODELAY set* Connected to wrong_domain.tld (35.186.1.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS alert, Server hello (2):* error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name* stopped the pause stream!* Closing connection 0curl: (35) error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name使用正確的 Hostname 請求時的結(jié)果:(僅在 Hostname 正確的情況下,證書信息才會被返回)

curl -v -k --resolve normal_domain.tld:443:35.186.1.1 https://normal_domain.tld* Added normal_domain.tld:443:35.186.1.1 to DNS cache* Rebuilt URL to: https://normal_domain.tld/* Hostname normal_domain.tld was found in DNS cache* Trying 35.186.1.1...* TCP_NODELAY set* Connected to normal_domain.tld (35.186.1.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.2 (IN), TLS handshake, Certificate (11):* TLSv1.2 (IN), TLS handshake, Server key exchange (12):* TLSv1.2 (IN), TLS handshake, Server finished (14):* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):* TLSv1.2 (OUT), TLS change cipher, Client hello (1):* TLSv1.2 (OUT), TLS handshake, Finished (20):* TLSv1.2 (IN), TLS handshake, Finished (20):* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384* ALPN, server accepted to use http/1.1* Server certificate:* subject: CN=normal_domain.tld* start date: Nov 15 05:41:39 2019 GMT* expire date: Nov 14 05:41:39 2020 GMT* issuer: CN=normal_domain.tld* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.> GET / HTTP/1.1> Host: normal_domain.tld> User-Agent: curl/7.58.0> Accept: */*> < HTTP/1.1 200 OK< Server: nginx/1.17.5< Date: Fri, 15 Nov 2019 05:53:19 GMT< Content-Type: text/plain< Transfer-Encoding: chunked< Connection: keep-alive< abc* Connection #0 to host normal_domain.tld left intact注:如果你知道已知的非指向性掃描器的 IP 范圍,你可以將它們?nèi)繑r截,權(quán)當是再上一層保險。這里給出 Censys 掃描器的 IP 范圍:

192.35.168.0/2374.120.14.0/24167.248.133.0/24162.142.125.0/24

通過偽造成其它真實存在的網(wǎng)站/CDN 節(jié)點來混淆視聽

借由此策略,你可以通過傳遞假信息,以使得掃描者建立起存在錯誤信息的數(shù)據(jù)庫。你可能想欺騙非指向性的掃描器,使其認為你的服務(wù)器是 CDN 節(jié)點服務(wù)器;你也可能同時想將你的真實站點混入其中,使得存在指向性的掃描器無法區(qū)分你的服務(wù)器究竟是 CDN 節(jié)點還是源站服務(wù)器……

個人來說,我不是很想用這種策略,因為它需要我考慮很多因素:真正的 CDN 會使用的 IDC 服務(wù)商(并把我的網(wǎng)站部署在相同的服務(wù)商)、其使用的 IP 對應(yīng)的 AS 名稱、其開放的端口、附加的頭文件信息等等,以確保攻擊者對此困惑。這個過程是非常煩人的。

重要:如若可能,你應(yīng)當將 HTTPS 作為唯一的回源協(xié)議。如果不能,你需要注意 HTTP 端口的行為特征。例如:你想要偽裝的目標服務(wù)器/網(wǎng)站總是會把 http/80 端口的請求轉(zhuǎn)跳至 https/443,但你沒有對你的網(wǎng)站做相同的事情。

注:實際上,偽裝成 Cloudflare 的 CDN 服務(wù)器算是不上不下的選擇。因為就算我們能在官網(wǎng)找到 Cloudflare 的 IP 范圍,也是你可能會認為 Cloudflare 僅僅會使用這些 IP 的原因。然而,那些現(xiàn)存實際正在運行 Cloudflare 節(jié)點應(yīng)用,但并沒有使用 IP 列表中的 IP 地址的服務(wù)器是存在的(或者這些服務(wù)器只是在運行正向代理服務(wù),如我將在描述的做法一樣)。曾有一次,我執(zhí)行了一次掃描操作并找到了一些沒有使用 Cloudflare IP,但卻做著我上面所說事情的服務(wù)器。所以,偽裝成 Cloudflare CDN 服務(wù)器這個主意也算是個主意——因為你確實無需真的要擁有/使用 Cloudflare 的 IP 段。
然而,這么做也不是什么好的選項,這是因為你必須使用為你真實的網(wǎng)站部署自建(包括自簽和非自簽)的證書。然而我們知道,大多數(shù) Cloudflare 用戶都使用由 Cloudflare 簽發(fā)的證書。如果你想把自己的服務(wù)器偽裝成 Cloudflare 的 CDN 服務(wù)器,請想清楚你是出于什么目的要這么做。

配置

關(guān)于安裝 ngx_stream_module 的步驟已在之前安裝 strict-sni 的步驟里提到,如果你忘記了,可以回去看看。

在本配置文件中有 3 個要點:

  1. 在 http 塊中,為 http/80 端口配置的偽裝/默認塊;
  2. 在 stream 塊中,為 https/443 端口配置的偽裝/默認塊;
  3. 為你真實的域名/網(wǎng)站而設(shè)置的到后端的路由塊。
配置文件示例:

load_module "modules/ngx_stream_module.so";http{ # 給自己 DIY 下 http 塊 server { listen 80 default_server; server_name localhost; location / { proxy_pass http://104.27.184.146:80; # 偽裝成 Cloudflare CDN 節(jié)點服務(wù)器 proxy_set_header Host $host; } } server { listen 80; server_name yourwebsite.com; # 如果你設(shè)置 https 作為唯一的回源協(xié)議,你不應(yīng)該在 http{} 塊中配置關(guān)于你真實域名的塊,就像這里(除非你是監(jiān)聽在 localhost 而不是公網(wǎng) IP) location / { proxy_pass http://127.0.0.1:8080; # 你的后端地址 proxy_set_header Host $host; } }}stream{ map $ssl_preread_server_name $name { yourwebsite.com website-upstream; # 你的真實網(wǎng)站路由 default cloudflare; # 默認路由 } upstream cloudflare { server 104.27.184.146:443; # Cloudflare 的 IP } upstream website-upstream {server 127.0.0.1:8080;} # 你的真實網(wǎng)站后端 server { listen 443; proxy_pass $name; proxy_ssl_name $ssl_preread_server_name; proxy_ssl_protocols TLSv1.2 TLSv1.3; ssl_preread on; }}

結(jié)果

它將返回攜帶其它網(wǎng)站真實存在的證書的內(nèi)容:

curl -I -v --resolve www.cloudflare.com:443:127.0.0.1 https://www.cloudflare.com/* Expire in 0 ms for 6 (transfer 0x55f3f0ae0f50)* Added www.cloudflare.com:443:127.0.0.1 to DNS cache* Hostname www.cloudflare.com was found in DNS cache* Trying 127.0.0.1...* TCP_NODELAY set* Expire in 200 ms for 4 (transfer 0x55f3f0ae0f50)* Connected to www.cloudflare.com (127.0.0.1) port 443 (#0)* ALPN, offering h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: none CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):* TLSv1.3 (IN), TLS handshake, Certificate (11):* TLSv1.3 (IN), TLS handshake, CERT verify (15):* TLSv1.3 (IN), TLS handshake, Finished (20):* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):* TLSv1.3 (OUT), TLS handshake, Finished (20):* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384* ALPN, server accepted to use h2* ALPN, offering http/1.1* successfully set certificate verify locations:* CAfile: none CApath: /etc/ssl/certs* TLSv1.3 (OUT), TLS handshake, Client hello (1):* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):* TLSv1.3 (IN), TLS handshake, Certificate (11):* TLSv1.3 (IN), TLS handshake, CERT verify (15):* TLSv1.3 (IN), TLS handshake, Finished (20):* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):* TLSv1.3 (OUT), TLS handshake, Finished (20):* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384* ALPN, server accepted to use h2* Server certificate:* subject: businessCategory=Private Organization; jurisdictionC=US; jurisdictionST=Delaware; serialNumber=4710875; C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=cloudflare.com* start date: Oct 30 00:00:00 2018 GMT* expire date: Nov 3 12:00:00 2020 GMT* subjectAltName: host "www.cloudflare.com" matched cert's "www.cloudflare.com"* issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert ECC Extended Validation Server CA* SSL certificate verify ok.* Using HTTP2, server supports multi-use* Connection state changed (HTTP/2 confirmed)* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0* Using Stream ID: 1 (easy handle 0x55f3f0ae0f50)> HEAD / HTTP/2> Host: www.cloudflare.com> User-Agent: curl/7.64.0> Accept: */*> * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):* old SSL session ID is stale, removing* Connection state changed (MAX_CONCURRENT_STREAMS == 256)!< HTTP/2 200 HTTP/2 200 < date: Tue, 06 Oct 2020 06:26:50 GMT* Connection #0 to host www.cloudflare.com left intact(成功偽裝成其它網(wǎng)站,部分結(jié)果已省略)

通過偽裝成其它自制網(wǎng)站/返回空內(nèi)容來屏蔽非法請求

在開始本部分前,你應(yīng)當了解這個策略僅能在 CDN 節(jié)點可以返回區(qū)別魚正常用戶不同內(nèi)容的前提下才能進行。下面是個例子:


在 GCP 中的回源 HTTP 頭信息設(shè)置項
HTTP 頭信息校驗是一種常見的驗證請求是否來自 CDN 節(jié)點的方式。

注:GCP(Google Cloud Platform) 的 HTTP 負載均衡服務(wù)提供了一個選項,可設(shè)置在源站服務(wù)器向 GCP CDN 節(jié)點接收請求時,GCP CDN 節(jié)點應(yīng)額外給出的請求頭信息。[2]這使得源站可以根據(jù)將請求從普通/惡意客戶端中區(qū)分出來。

注:在部分產(chǎn)品中,有些工程師喜歡在節(jié)點服務(wù)器請求源站服務(wù)器時添加一些頭信息用于 debug。然而由于他們并非是出于添加特性而這么做的,所以這也不會出現(xiàn)在他們的產(chǎn)品文檔中(例如:http://CDN.net),客服也對此不知道。如果你想找尋在你使用的 CDN 產(chǎn)品中是否有什么特殊頭信息,好的做法是:寫一個簡單的腳本來導(dǎo)出收到的全部頭信息。這里就不具體展開了。

配置文件很直觀,無需解釋。

若想不作返回時的配置文件:

server { listen 80; server_name yourdomain.com; if ($http_auth_tag != "here_is_the_credential") { return 444; } location / { echo "Hello World!"; }}若想返回虛假的網(wǎng)站/后端時的配置文件:

server { listen 80; server_name yourdomain.com; if ($http_auth_tag != "here_is_the_credential") { return @fake; } location / { echo "Hello World!"; } location @fake { root /var/www/fakewebsite/; # 強烈建議自己 DIY 一個假站點 }}注:如果你傾向于在 https/443 端口上配置這些,我推薦你使用未知域名自簽證書。使用真實且域名為公共暴露的域名可能會讓攻擊者更容易找到你的源站。Nginx 允許你在 SNI 信息不匹配 server_name 的情況下使用證書。
重要:一些人可能會認為使用公共暴露域名的子域名的真實證書,而且還很可能使用 Let's Encrypt 來獲取免費證書。我希望你能留心一下證書透明度這個東西。它能獲知特定域名下你有哪些證書。特別地,Let's Encrypt 會遞交所有其簽發(fā)的證書至證書透明度日志(CT Log)。(參考:源信息, 存檔)
如果你想要知道你的證書是否被收入至證書透明度日志,你可以訪問crt.sh。
如果你無法確定你簽發(fā)證書所依賴的 CA 是否會遞交所有其簽發(fā)的證書至證書透明度日志,你最好還是自簽證書。

自簽證書的指令如下:(為 http://yeet.com 自簽證書的過程)

cat > csrconfig.txt <<-EOF[ req ]default_md = sha256prompt = noreq_extensions = req_extdistinguished_name = req_distinguished_name[ req_distinguished_name ]commonName = yeet.comcountryName = SG[ req_ext ]keyUsage=critical,digitalSignature,keyEnciphermentextendedKeyUsage=critical,serverAuth,clientAuthsubjectAltName = @alt_names[ alt_names ]DNS.0 = yeet.comEOFcat > certconfig.txt <<-EOF[ req ]default_md = sha256prompt = noreq_extensions = req_extdistinguished_name = req_distinguished_name[ req_distinguished_name ]commonName = yeet.comcountryName = SG[ req_ext ]subjectKeyIdentifier = hashauthorityKeyIdentifier = keyid:always,issuerkeyUsage=critical,digitalSignature,keyEnciphermentextendedKeyUsage=critical,serverAuth,clientAuthsubjectAltName = @alt_names[ alt_names ]DNS.0 = yeet.comEOFopenssl genpkey -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out cert.keyopenssl req -new -nodes -key cert.key -config csrconfig.txt -out cert.csropenssl req -x509 -nodes -in cert.csr -days 365 -key cert.key -config certconfig.txt -extensions req_ext -out cert.pem考慮到有人可能會拿這些指令生成 csr 用于申請真實證書,我保留了國家的字段(部分 CA 在接收 csr 文件時要求這個字段需要存在),如果不需要可以自行刪除。

重要:自簽證書可能會增加中間人攻擊的風(fēng)險,除非底層設(shè)施是可信的,或 CDN 服務(wù)商支持請求源站時攜帶客戶端證書,在 Cloudflare 中又稱經(jīng)過身份驗證的源服務(wù)器拉取(Authenticated Origin Pulls)。





在 Cloudflare 中啟用“經(jīng)過身份驗證的源服務(wù)器拉取”[3]

客戶端證書校驗也是一種驗證請求是否來自 CDN 節(jié)點的方式。只有少數(shù)的 CDN 服務(wù)商支持在回源請求時攜帶客戶端證書。無論是哪家服務(wù)商具有此特性,在你的服務(wù)器上的配置幾乎都是一樣的。下面是示例:

server { listen 443; ssl_certificate /etc/nginx/certs/cert.crt; ssl_certificate_key /etc/nginx/certs/cert.key; server_name yourdomain.com; ssl_client_certificate /etc/nginx/certs/cloudflare.crt; ssl_verify_client on; error_page 495 496 = @444; # 用于在出現(xiàn)客戶端證書校驗相關(guān)錯誤時,用自行指定的內(nèi)容替代默認的錯誤返回信息 location @444 {return 444;} location / { echo "Hello World!"; }}此配置將會在遇到客戶端證書錯誤時不作返回

注:偽裝成其它網(wǎng)站/后端也是可行的,只需簡單模仿“HTTP 頭信息校驗”部分中的配置文件即可。
重要:無論你使用何種方式,請注意“默認返回”。使“默認返回”和在遭遇非法請求時的返回一致。

使默認和針對非法請求的返回一樣都是不作返回:

server { listen 80 default_server; listen 443 ssl default_server; ssl_certificate /etc/nginx/certs/cert.crt; ssl_certificate_key /etc/nginx/certs/cert.key; server_name localhost; location / { return 444; }}

結(jié)果

curl http://127.0.0.1:80curl: (52) Empty reply from servercurl -k https://127.0.0.1:443 curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)

結(jié)論

簡單來說,要防止你的源站 IP 不被探測到,你可以:

  1. 在可能的情況下,設(shè)置 IP 白名單
  2. 盡可能地修改源站 Hostname 和監(jiān)聽端口
  3. 為不匹配的 Hostname 設(shè)置默認返回
  4. 為匹配的 Hostname 設(shè)置驗證方式
  5. 放下身段去設(shè)想掃描器的視角,觀察服務(wù)器的行為
整個過程可粗略地畫作下方的流程圖:


用在本回答中介紹過的各種策略組成的流程圖

這篇文章和其中所有原創(chuàng)制圖/作品以 CC BY-SA 4.0 的形式授權(quán)。轉(zhuǎn)載請保留英文版本的鏈接,如需轉(zhuǎn)載中文版需同時保留英文版本和中文版本(掘金/本站)鏈接。
我在以中文重寫的過程中已經(jīng)盡量規(guī)范用詞和避免雙語歧義,并盡可能使用中文語言的網(wǎng)頁作為外鏈,但如果依舊存在沖突,請以英文描述為準。
作者:風(fēng)間詩音(Sion Kazama)

參考

  1. ^這里的外鏈沒有使用 Google 搜索「短板理論/木桶原理」之類關(guān)鍵詞出來的中文結(jié)果,是因為在相關(guān)結(jié)果中,幾乎找不到一篇可以直接使用、有嚴謹依據(jù)的文章。甚至找到一篇質(zhì)疑這個理論在中文范疇內(nèi)的詮釋合理/適度性的文章,故直接使用了英文 Wikipedia 的結(jié)果。?https://zhuanlan.zhihu.com/p/59649346
  2. ^即便 GCP 負載均衡/CDN 服務(wù)僅接受 GCP 虛擬機器的實例作為后端,但原理都是相同的。
  3. ^最早我是把“Authenticated Origin Pulls”翻譯成“源站拉取驗證”的,看了官方翻譯后果斷切回英文了=_=

關(guān)鍵詞:暴露

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關(guān)閉