tid=12495& 本帖最後由 IT_man 於 2015-7-3 10:47 編輯
9 w& Q6 e a: G2 ^: f, Q4 m! X/ b& h% f* ~3 y' C9 j, N
很多網站都會有偵測使用者 IP 的功能,不管是判斷使用者來自哪邊,或者是記錄使用者的位置。但是你知道嗎?網路上大多數的教學全部都是「錯誤」的。正確的程式寫法可以確保知道訪客的 IP,但是錯誤的寫法卻可能讓網站管理者永遠不知道犯罪者的來源。' c! B4 L+ F* F+ @7 d
: H, m/ q9 _4 `
這次我們單就偵測 IP 的議題來探討各種錯誤的寫法。
" c: K6 {/ W P9 C P, s, x: B$ t+ v
! ?: u( W- ~) i
你知道網路上的教學是不安全的嗎?: H2 b% r: B! g% z- e
我們先來看一下網路上的教學,讓我們 Google 找一下「PHP 取得 IP」,就可以看到許多人熱心的教學,我們隨意挑一個常見的教學來看看。
* y6 r" s8 R/ [3 p! c! a以 PHP 為例:
1 m3 X8 [) Q4 w8 u- <?php
# X) ?" v( ]4 i" @' f6 m% N5 T" n - if(!empty($_SERVER['HTTP_CLIENT_IP'])){7 X2 X K4 L9 g& S; g+ w
- $myip = $_SERVER['HTTP_CLIENT_IP'];% R% t3 u1 T) w6 m
- }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){1 k4 d m: {% G* l
- $myip = $_SERVER['HTTP_X_FORWARDED_FOR'];9 }0 F! a T4 n4 D, o1 k
- }else{, _( O7 m1 _; D F: M: u$ E) F7 k
- $myip= $_SERVER['REMOTE_ADDR'];
N% Q3 D! s f - }) H& a1 L) N W4 o0 I) t
- echo $myip;+ v, M% ~2 d: `% `/ E! Y$ N
- ?>
複製代碼 F) @4 A9 C' E" y, E% u- ?
& v/ ?$ m; U4 b" H) 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。
. A4 b7 H; y! S. F0 s- t$ m但是你知道嗎?網路上 80% 的教學寫法全部都是「錯誤」的。
! R$ _+ ~, H0 D; W; V* U* Q
* d8 S9 F6 m% |* [為什麼這樣說呢?請大家記得一件事情:「任何從客戶端取得的資料都是不可信任的!」6 \7 r1 S9 u* J% L, c( W+ U2 E1 x
/ s, w- `3 Y0 d) z竄改 HTTP Header「X-Forwarded-For」這個變數雖然「有機會」取得使用者的真實 IP,但是由於這個值是從客戶端傳送過來的,所以「有可能」被使用者竄改。
' @+ P& \7 }. I: N舉例來說,我寫了一個小程式,偵測這些常見的 HTTP Header 判斷 IP。並且使用 Burp Suite 這個工具來修改 HTTP Request。
+ Q& [5 h/ a2 s# i ^& F
! f) k% X4 c+ r* k6 a) L* Y- P v! V7 w' J5 b
頁面上顯示目前我目前的 IP「49.50.68.17」,並且其他的 header 是空的。但如果我今天使用 Burp Suite 之類的 Proxy 工具自行竄改封包,加上 X-Forwarded-For 或是 Client-IP header:% Y' g( ^8 N l& |* t

8 t0 M3 T/ S, S7 t8 r8 q2 j修改完畢之後,再到原本的顯示 IP 介面,會發現網頁錯將我竄改的 header 當作正確的資料填入。
8 |! T7 b" J U$ W7 a5 U9 X9 G 3 D3 k$ D k1 q- [4 L9 F
2 Q; W; A3 s4 q) J& d0 k+ O
使用代理伺服器 Proxy 的情況使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。" J, \* f* j$ t5 t( J6 h
直接連線 (沒有使用 Proxy)4 f8 f Q% M; n/ N% a4 o5 i( I) W
: C" T! W: I3 g: ]. c
- REMOTE_ADDR: 客戶端真實 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無
. d$ i) h4 v0 S/ ^- s$ P& N: R0 P Transparent Proxy
" L3 g" t# \" | q' ?
) b4 M ?# X) N, h9 ?$ h3 N0 y- L - REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP
# _& t: f2 [" c1 w' R Anonymous Proxy8 G6 S7 B8 k1 D1 Z
4 _+ Z$ p# @+ l7 `; {
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP
5 _$ Y' x4 l4 @6 [) \# p High Anonymity Proxy (Elite Proxy)
1 D* u- [+ b, B! P% T( x( Y f; U) y" f3 i. h4 p
- REMOTE_ADDR: 代理伺服器 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP)/ U, g/ g! G% W0 M
實際情況在我們測試的過程中,通常我們都會讓瀏覽器自帶 X-Forwarded-For,並且自行填入 IP。常常會發現有一些網站出現如下的警告…
% j2 V: Q5 C2 G; o; a# R% y% L9 R
% O/ } j5 x( e% |. Q H有沒有搞錯?「上次登入位置 127.0.0.1」?沒錯,這個是知名論壇套件「Discuz!」的功能,抓取 IP 的功能也是不安全的寫法。也有這樣的經驗,之前開著 X-Forwarded-For 的 header 到一些網站,竟然直接出現管理者後台!
) i5 J, i8 _5 _; L& ?; a! ]: `你覺得只有一般人撰寫的程式會有這樣的問題嗎?其實大型網站也可能會有類似的問題:3 F" [% ~# c9 V* b
; G4 H* \) G/ x/ e8 a
先不論為什麼 127.0.0.1 會在美國,這樣的寫法可能會讓管理者永遠抓不到犯罪者的真實 IP,甚至攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。
: C% J) r8 v9 @, q' @; d7 D' u) @2 n4 W7 `2 g9 i5 N4 _5 z. |
正確又安全的方式「任何從客戶端取得的資料都是不可信任的!」
" G" R# Z5 |9 Z4 b請各位開發者、管理者記住這個大原則,雖然這些 Request Header 可能含有真實 IP 的資訊,但是因為他的安全性不高,因此我們絕對不能完全信賴這個數值。' j8 m: E; N; {5 i9 S1 V T6 A
那我們該怎麼處理呢?我的建議是記錄所有相關的 header 欄位存入資料庫,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。
% D$ P3 w( [: j; D6 o可以參考的 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+ \1 o. @) p7 w$ h! E4 Q* |! C「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的,不要再參考網路上錯誤的教學了!
+ y3 S/ {0 v B) b9 d; q
' U' k) k0 W3 I! _" [; z& L*原文參考 CEO Allen Own 大作 http://devco.re/blog/2014/06/19/client-ip-detection/' U$ t$ @$ @. Q+ \. s- b, y2 Z
|