0x01 先查個問題
測試環境微信支付通道提示網路環境未能通過安全驗證,請稍後再試
,出現這種情況一般首要
想到可能是雙方網路互動中微信方驗參與我們出現不一致,翻了下手冊確定是這類問題開始排查環節
-
可能獲取真實IP方式錯誤
getenv('HTTP_CLIENT_IP')
getenv('HTTP_X_FORWARDED_FOR')
getenv('REMOTE_ADDR')
filter_var($remote_ip, FILTER_VALIDATE_IP)
- 已經依次獲取並過濾
- 固程式沒有任何問題,往上發散
-
是否反向代理
經過反向代理後,由於在客戶端和
web
伺服器之間增加了中間層,因此web伺服器無法直接拿到客戶端的ip
,只能通過$remote_addr
變數拿到的將是反向代理伺服器的ip地址,檢查不存在此類問題,再往上,擅長網路通訊工程的同學表示絕不認輸 -
可能
NAT
分配出口IP
,或負載均衡服務分發出現異常- 先拿到我本地內網外網IP 方便之後問題排查
# 本機IP ifconfig | grep -A 1 "en" | grep broadcast | cut -d " " -f 2 # 外網IP curl --silent http://icanhazip.com 複製程式碼
- 檢查與80埠建立連線目標都有誰
netstat -tn|grep 80|akw '{print $5}'|awk -F '{print $1}' | grep [本地IP] 複製程式碼
這裡出現問題,竟然沒有我的
IP
,再以nginx $remote_addr
拿到的IP作為參考,這是nginx
最後一次握手的IP
,$remote_addr = 10.168.0.0/16
段在
nginx
處列印$remote_addr
,並在server_name
新增當前機器ip
,分別以負載均衡IP與本地IP做測試,最終確定問題出現在負載均衡伺服器出現異常
0x02 LNMP棧拿真實IP
LNMP
棧內PHP
所有獲得到的TCP
操作資訊都是由前面Nginx
通過fastcgi
傳遞給它的,就比如$_SERVER['REMOTE_ADDR']
由include fastcgi.conf;
引進,其等於nginx
的$remote_addr
Nginx
中的幾個變數:
-
$remote_addr
代表客戶端的
IP
,但它的值不是由客戶端提供的,而是服務端根據客戶端的ip指定的,icanhazip
的原理也是這樣, 當你的瀏覽器訪問某個網站時,假設中間沒有任何代理,那麼網站的web伺服器就會把remote_addr
設為你在公網暴露的IP,如果你用了某個代理,那麼你的瀏覽器會先訪問這個代理,然後再由這個代理轉發到網站,這樣web
伺服器就會把remote_addr
設為這臺代理機器的IP, 除非代理將你的IP附在請求header
中一起轉交給web
伺服器。 -
$proxy_add_x_forwarded_for
$proxy_add_x_forwarded_for
變數包含客戶端請求頭中的"X-Forwarded-For
",與$remote_addr
兩部分,他們之間用逗號分開。X-Forwarded-For
(簡稱XFF),X-Forwarded-For
是一個 HTTP 擴充套件頭部。RFC 2616 協議並沒有對它的定義,它最開始是由Squid
這個快取代理軟體引入,用來表示HTTP
請求端真實 IP。如今它已經成為事實上的標準,被各大HTTP
代理、負載均衡等轉發服務廣泛使用,並被寫入 RFC 7239(Forwarded HTTP Extension` 標準之中。 -
$proxy_set_header
已在排查問題中說明,可設定代理後 header
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; 複製程式碼
-
X-Real-IP
一般比如
X-Real-IP
這一個自定義頭部欄位,通常被HTTP
代理用來表示與它產生TCP
連線的裝置IP
,這個裝置可能是其他代理,也可能是真正的請求端,這個要看經過代理的層級次數或是是否始終將真實IP
一路傳下來。(牢記:任何客戶端傳上來的東西都是不可信的)
當多層代理或使用CDN時,如果代理伺服器不把使用者的真實IP傳遞下去,那麼伺服器將永遠不可能獲取到使用者的真實IP。
0x03 使用者的真實IP從何而來
-
寬頻供應商提供獨立IP 比如家裡電信寬頻上網,電信給分配了公網ip,那麼一個請求經過的ip路徑如下:
這種情況下,119.147.19.234
會把得到的116.1.2.3
附加到頭資訊中傳給10.168.0.0/32
,因此這種情況下,我們取得的使用者ip則為:116.1.2.3
。 如果119.110.0.0/16
沒有把116.1.2.3
附加到頭資訊中傳給業務伺服器,業務伺服器就只能取上上一級ip地址 -
寬頻供應商不能提供獨立IP
寬頻提供商沒有足夠的公網
ip
,分配的是個內網ip
,比如長寬等小的isp。請求路徑則可能如下:這種情況下得到的使用者ip,就是
211.162.78.1
。 這種情況下,就可能出現一個ip對應有數十上百個使用者的情況了 -
手機2g上網
網路提供商沒法直接提供ip給單個使用者終端,以中國移動cmwap
上網為例,因此請求路徑可能為:
202.96.75.1
。2008年的時候整個廣東聯通就三個手機上網的公網ip,因此這種情況下,同一ip出現數十萬使用者也是正常的。
-
有幾萬或數十萬員工的公司
這種也會出現來自同一
ip
的超多使用者,可能達到幾萬人,但出口IP可能就那麼幾個。
0x04 NAT [Network Address Translation]
中文意思是網路地址轉換
,它允許一個整體機構以一個公用IP
地址出現在Internet
上。
NAT
在 OSI參考模型
的網路層 (第3層), 它是一種把內部私有網路地址(IP地址)翻譯成合法網路IP地址的技術。NAT
可以讓那些使用私有地址的內部網路連線到Internet
或其它IP
網路上。NAT
路由器在將內部網路的資料包傳送到公用網路時,在IP
包的報頭把私有地址轉換成合法的IP
地址。
RFC1918 規定了三塊專有的地址,作為私有的內部組網使用
- A類:10.0.0.0 — 10.255.255.255 10.0.0.0/8
- B類:172.16.0.0 — 172.31.255.255 172.16.0.0/12
- C類:192.168.0.0 — 192.168.255.255 192.168.0.0/16
這三塊私有地址本身是可路由的,只是公網上的路由器不會轉發這三塊私有地址的流量;當一個公司內部配置了這些私有地址後,內部的計算機在和外網通訊時,公司的邊界路由會通過NAT
或者PAT
技術,將內部的私有地址轉換成外網IP,外部看到的源地址是公司邊界路由轉換過的公網IP
地址,這在某種意義上也增加了內部網路的安全性
這個過程是通過NAT
中的本地址與全域性地址對映條目來實現的,所以事先要在NAT
路由器上配置這樣的對映條目。
公網 IP
底下可以發私有的 IP
地址。
0x05 IPV6 來了?
寫這篇文章的時候看到有個推送,表示阿里全面應用IPV6
,這件事的意義還挺重大的
我們知道,一段 IPv4
標準的 IP
地址,一共由 4 X 8 = 32
位二進位制數字組成,理論上存在 2^32
個 IP 地址。等於 4,294,967,296
, 42
億多個 IPv4
的地址。
參考世界網際網路使用者統計報告,全球現在大概有4,208,571,287
人在上網,也就是說已經快到ipv4
地址設計的最大IP
數了
不過不用擔心,前面提到的 NAT
,讓 IPv4
公網 IP
哪怕用完了也能湊合過。
到了 IPv6
,相比 IPv4
最大的提升,就是位數大大增加,變成了 8 個 4 位的十六進位制數字。也就是說有 2^128
個 IPv6
地址。地球上的每粒沙子都分一個也管夠
儲存2^128
位元組理論上什麼概念呢,在當今的量子水平下,假設計算裝置能夠操作在原子一級,每公斤質量可儲存大約10的25次方bits,儲存2的128次方的位元組大約需要272 trillion = 2720000億公斤
。
最後,週末愉快,北京聯通已經支援ipv6
了,我在望京測試,可以拿到 ipv6
地址