本帖最後由 IT_man 於 2015-7-3 10:47 編輯
0 {7 d) [6 s+ w! }
. z$ ~* w) w! D# S6 o很多網站都會有偵測使用者 IP 的功能,不管是判斷使用者來自哪邊,或者是記錄使用者的位置。但是你知道嗎?網路上大多數的教學全部都是「錯誤」的。正確的程式寫法可以確保知道訪客的 IP,但是錯誤的寫法卻可能讓網站管理者永遠不知道犯罪者的來源。
1 J2 E( H: s" k3 S8 u
% L# e% u# o; i2 i ]這次我們單就偵測 IP 的議題來探討各種錯誤的寫法。
/ O" T" c- D# D# R
/ @1 f1 q, X9 o7 U/ U. J* X
8 b4 X6 t* f% T+ o/ a- A1 x9 X你知道網路上的教學是不安全的嗎?
! E9 y5 M- W2 x9 J- d6 a" p( a我們先來看一下網路上的教學,讓我們 Google 找一下「PHP 取得 IP」,就可以看到許多人熱心的教學,我們隨意挑一個常見的教學來看看。
3 k$ S! s. J) i/ h$ R2 _0 Q以 PHP 為例:
0 m: ]* a8 b7 y4 J$ o- <?php$ d4 b$ @+ g+ b! P/ i
- if(!empty($_SERVER['HTTP_CLIENT_IP'])){
$ K& p D G; W6 v9 S& V8 v - $myip = $_SERVER['HTTP_CLIENT_IP'];
# ]3 S) V+ k# ` - }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
; z. S, r8 X: M" J4 \ - $myip = $_SERVER['HTTP_X_FORWARDED_FOR'];
; Q0 _- i8 Q3 v2 x/ a+ p# l( l - }else{
. u) ~8 a# x: v - $myip= $_SERVER['REMOTE_ADDR'];
, n6 c. C* F4 C$ D6 E! R4 _ - }
6 p9 B* `- H! \' | - echo $myip;
6 K1 ^0 [ V8 @: @: M/ ^& |# u - ?>
複製代碼
- ^1 D( ^% z; c0 A; r2 A3 K9 U v3 D7 q) Z, b2 G+ S& T
這是一個很基本的寫法、很正確的想法,如果 HTTP Header 中包含「Client-IP」,就先以他當作真實 IP。若包含「X-Forwarded-For」,則取他當作真實 IP。若兩者都沒有,則取「REMOTE_ADDR」變數作為真實 IP。因為當使用者連線時透過代理伺服器時,REMOTE_ADDR 會顯示為代理伺服器 Proxy 的 IP。部分代理伺服器會將使用者的原始真實 IP 放在 Client-IP 或 X-Forwarded-For header 中傳遞,如果在變數中呼叫則可以取得真實 IP。
! }, s0 B+ U5 |) D/ \; `但是你知道嗎?網路上 80% 的教學寫法全部都是「錯誤」的。( B" n* d* _9 {( `% \
3 o" |9 S0 M- O) ], O4 x
為什麼這樣說呢?請大家記得一件事情:「任何從客戶端取得的資料都是不可信任的!」
3 ?5 @" n2 d c; `! C7 m$ |; o9 h5 D$ e9 x5 \4 {' @
竄改 HTTP Header「X-Forwarded-For」這個變數雖然「有機會」取得使用者的真實 IP,但是由於這個值是從客戶端傳送過來的,所以「有可能」被使用者竄改。
3 X5 k$ O% w: h8 t舉例來說,我寫了一個小程式,偵測這些常見的 HTTP Header 判斷 IP。並且使用 Burp Suite 這個工具來修改 HTTP Request。
/ o" i' y" [& Z
' Y4 `; k, a7 Y( c3 c
7 q0 m( A7 g ^, L頁面上顯示目前我目前的 IP「49.50.68.17」,並且其他的 header 是空的。但如果我今天使用 Burp Suite 之類的 Proxy 工具自行竄改封包,加上 X-Forwarded-For 或是 Client-IP header:
. c, r, k, q9 M ' ~( C' B7 Z1 C/ S1 \+ S
修改完畢之後,再到原本的顯示 IP 介面,會發現網頁錯將我竄改的 header 當作正確的資料填入。. b' d9 G2 n" @% I! D
* v5 ]9 c0 v3 @1 ~0 V& m
# z2 R |+ y/ h. O. A, y使用代理伺服器 Proxy 的情況使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。7 K- W2 r/ ~0 y0 W* N
直接連線 (沒有使用 Proxy)) ~( y1 B$ \5 M. c# y2 x6 m
2 @ y# o9 t4 `" \+ `2 p& e - REMOTE_ADDR: 客戶端真實 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無
* P2 ~8 l- [5 ]- r0 @2 h" a Transparent Proxy
* p! l1 L1 c) l; o. z* M& Y4 _8 Z5 i/ z
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP/ ~4 H P; B. o7 b
Anonymous Proxy8 b$ I# C0 q4 ?
- e) ~$ h8 w' V- o' E* E1 }3 e9 f
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP
4 J3 z- M }" D" n; Q High Anonymity Proxy (Elite Proxy)
+ B, [* K6 X( Z+ [+ s/ F, _4 W3 P( u* d4 c
- REMOTE_ADDR: 代理伺服器 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP)7 P' E- V9 R! A
實際情況在我們測試的過程中,通常我們都會讓瀏覽器自帶 X-Forwarded-For,並且自行填入 IP。常常會發現有一些網站出現如下的警告…
7 m- w! H' ^$ C0 m9 {3 n% F% z- n
2 S! k( E: l) R4 q: c, @% b; S有沒有搞錯?「上次登入位置 127.0.0.1」?沒錯,這個是知名論壇套件「Discuz!」的功能,抓取 IP 的功能也是不安全的寫法。也有這樣的經驗,之前開著 X-Forwarded-For 的 header 到一些網站,竟然直接出現管理者後台!
8 l+ V6 X" K" G4 [+ v, j你覺得只有一般人撰寫的程式會有這樣的問題嗎?其實大型網站也可能會有類似的問題:* _0 n* X O y) C) N

9 d" x O1 N4 z+ e( U先不論為什麼 127.0.0.1 會在美國,這樣的寫法可能會讓管理者永遠抓不到犯罪者的真實 IP,甚至攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。
, Q% i$ n% o1 [) t U5 c# T- @, ]3 e' _$ C, _$ \! d% @
正確又安全的方式「任何從客戶端取得的資料都是不可信任的!」8 [( h) _, S+ f% E+ N% q7 {
請各位開發者、管理者記住這個大原則,雖然這些 Request Header 可能含有真實 IP 的資訊,但是因為他的安全性不高,因此我們絕對不能完全信賴這個數值。
* p4 x% x. T/ T' A9 J那我們該怎麼處理呢?我的建議是記錄所有相關的 header 欄位存入資料庫,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。
/ z0 q2 }$ n/ {( E$ Z可以參考的 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)/ G( j/ C& u, v6 A
「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的,不要再參考網路上錯誤的教學了!7 x8 H2 W' j1 G% A+ b
* S% I5 y8 E3 B
*原文參考 CEO Allen Own 大作 http://devco.re/blog/2014/06/19/client-ip-detection/- ]1 B3 e3 c& j* b0 r1 T; G
|
|