tid=12495& 本帖最後由 IT_man 於 2015-7-3 10:47 編輯 2 F8 H" c; @5 l/ h+ U7 G
G5 z. v, Q2 l2 B: e
很多網站都會有偵測使用者 IP 的功能,不管是判斷使用者來自哪邊,或者是記錄使用者的位置。但是你知道嗎?網路上大多數的教學全部都是「錯誤」的。正確的程式寫法可以確保知道訪客的 IP,但是錯誤的寫法卻可能讓網站管理者永遠不知道犯罪者的來源。
0 H! G1 |! c! S6 r; U+ q" B
3 b4 a8 r; Q+ C這次我們單就偵測 IP 的議題來探討各種錯誤的寫法。8 Q; L3 r& A* R! Z8 Q7 ^4 ?: \
' G, _% _1 K% R2 a4 \( ~; ^6 S5 p6 u# o
你知道網路上的教學是不安全的嗎?
1 }2 ~; o" g4 H, E0 s' h我們先來看一下網路上的教學,讓我們 Google 找一下「PHP 取得 IP」,就可以看到許多人熱心的教學,我們隨意挑一個常見的教學來看看。
2 r: x$ p( \/ ^" r3 A以 PHP 為例:
4 N8 \ c4 [5 G- G6 E& T- <?php) l4 G/ I6 v* |' d; C* x+ ~ m- ]
- if(!empty($_SERVER['HTTP_CLIENT_IP'])){
9 z+ ?' y5 I7 h5 z" V$ \ - $myip = $_SERVER['HTTP_CLIENT_IP'];
/ B* q& L/ w% M- M8 a. x; y9 O - }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
' g" {0 M6 u3 P! ~/ k2 `2 l2 t - $myip = $_SERVER['HTTP_X_FORWARDED_FOR'];
. ~9 Q7 A9 E, H: W a; Y* H - }else{% ?) E8 U* b/ n' P
- $myip= $_SERVER['REMOTE_ADDR'];, L1 r) K; r; S# D
- }) @! |2 Z9 M7 W& Q
- echo $myip;
0 X5 _, p( Q& q2 `+ _9 e' T - ?>
複製代碼
1 ]! K: X* I d2 b& \5 r4 W( f* S$ I, t f4 [7 }# P7 ]
這是一個很基本的寫法、很正確的想法,如果 HTTP Header 中包含「Client-IP」,就先以他當作真實 IP。若包含「X-Forwarded-For」,則取他當作真實 IP。若兩者都沒有,則取「REMOTE_ADDR」變數作為真實 IP。因為當使用者連線時透過代理伺服器時,REMOTE_ADDR 會顯示為代理伺服器 Proxy 的 IP。部分代理伺服器會將使用者的原始真實 IP 放在 Client-IP 或 X-Forwarded-For header 中傳遞,如果在變數中呼叫則可以取得真實 IP。 k9 f% m+ [8 T# Y! k5 b K
但是你知道嗎?網路上 80% 的教學寫法全部都是「錯誤」的。
, L. A6 X3 N& D2 ~3 O6 N; d( }5 K0 V$ Z z, ~$ o8 ?- I
為什麼這樣說呢?請大家記得一件事情:「任何從客戶端取得的資料都是不可信任的!」* j' N6 y, ]! Z1 _# c! i
+ P( x+ X4 L+ A; f7 h& z
竄改 HTTP Header「X-Forwarded-For」這個變數雖然「有機會」取得使用者的真實 IP,但是由於這個值是從客戶端傳送過來的,所以「有可能」被使用者竄改。: z6 @0 r, q) d% n
舉例來說,我寫了一個小程式,偵測這些常見的 HTTP Header 判斷 IP。並且使用 Burp Suite 這個工具來修改 HTTP Request。
$ { C% c1 I2 w( E3 P
6 u& S7 R9 n1 I, x' K, u
& t7 v; d! \) V/ U/ Q6 @: b& S頁面上顯示目前我目前的 IP「49.50.68.17」,並且其他的 header 是空的。但如果我今天使用 Burp Suite 之類的 Proxy 工具自行竄改封包,加上 X-Forwarded-For 或是 Client-IP header:5 b( j* f, L2 Z: b
( @3 i7 A, w+ T1 K7 E8 h
修改完畢之後,再到原本的顯示 IP 介面,會發現網頁錯將我竄改的 header 當作正確的資料填入。
3 L) z. A& V5 d. j! g
) O0 h, M. Q. i) E$ ~, ?6 ]4 ~% |9 y& N
3 L- d5 J8 A% z% y% t, x" o使用代理伺服器 Proxy 的情況使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。6 U4 p/ f7 v- r$ M! Z1 D6 m5 e7 E. C
直接連線 (沒有使用 Proxy)- t" v# T& l, N, Q
3 x% c" Q6 T h" W7 R) u - REMOTE_ADDR: 客戶端真實 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無
' \" f# o" D* F0 F Transparent Proxy6 [- i% i8 |, Q% m
5 M3 \+ L$ d8 m% G$ g0 Z - REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP
, G$ ?# e5 c- S0 t. q Anonymous Proxy# q% ]7 C0 o5 q9 ^( d: _0 i
& B) o9 Z7 L- w: r6 C) G/ c& Q
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP1 K8 C% L8 x1 S7 [ d
High Anonymity Proxy (Elite Proxy)$ P6 e! U5 l; z8 d( q
9 v# d6 b4 z: v# O3 R1 c - REMOTE_ADDR: 代理伺服器 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP); f+ V4 u$ \% @: u2 N
實際情況在我們測試的過程中,通常我們都會讓瀏覽器自帶 X-Forwarded-For,並且自行填入 IP。常常會發現有一些網站出現如下的警告…1 R1 j+ Q% y) J, j5 v
# j7 E2 Q+ S5 d0 [
有沒有搞錯?「上次登入位置 127.0.0.1」?沒錯,這個是知名論壇套件「Discuz!」的功能,抓取 IP 的功能也是不安全的寫法。也有這樣的經驗,之前開著 X-Forwarded-For 的 header 到一些網站,竟然直接出現管理者後台!
+ K& s4 V/ Y5 K2 ~4 N u你覺得只有一般人撰寫的程式會有這樣的問題嗎?其實大型網站也可能會有類似的問題:
% H- ^" X; T0 S$ B! F1 S' {. d* y" O/ u' z! E+ d; U
先不論為什麼 127.0.0.1 會在美國,這樣的寫法可能會讓管理者永遠抓不到犯罪者的真實 IP,甚至攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。; M" B# I% a, {3 x
' n3 t; p+ g0 C- Z) B9 j
正確又安全的方式「任何從客戶端取得的資料都是不可信任的!」/ |1 \& ?1 n1 c: f0 K6 C0 l
請各位開發者、管理者記住這個大原則,雖然這些 Request Header 可能含有真實 IP 的資訊,但是因為他的安全性不高,因此我們絕對不能完全信賴這個數值。: U" p1 X, Q: j, u. D9 x4 G3 ]
那我們該怎麼處理呢?我的建議是記錄所有相關的 header 欄位存入資料庫,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。
6 a4 p4 d2 n0 h- |0 Q2 n! g可以參考的 HTTP Header(依照可能存放真實 IP 的順序)* HTTP_CLIENT_IP* HTTP_X_FORWARDED_FOR* HTTP_X_FORWARDED* HTTP_X_CLUSTER_CLIENT_IP* HTTP_FORWARDED_FOR* HTTP_FORWARDED* REMOTE_ADDR (真實 IP 或是 Proxy IP)* HTTP_VIA (參考經過的 Proxy)
) \3 V( p7 ~, {$ v- ^「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的,不要再參考網路上錯誤的教學了!' c& N0 w' R: H* B3 K( w4 K
S* d7 l! S0 l! ]# \2 q*原文參考 CEO Allen Own 大作 http://devco.re/blog/2014/06/19/client-ip-detection// y% N6 Y- J8 ^. Y" u# _3 n6 l
|