tid=12495& 本帖最後由 IT_man 於 2015-7-3 10:47 編輯
6 @6 u6 B- Y$ C( d. ?# i* U) ^$ o) ?; c) V7 x7 V5 U
很多網站都會有偵測使用者 IP 的功能,不管是判斷使用者來自哪邊,或者是記錄使用者的位置。但是你知道嗎?網路上大多數的教學全部都是「錯誤」的。正確的程式寫法可以確保知道訪客的 IP,但是錯誤的寫法卻可能讓網站管理者永遠不知道犯罪者的來源。- g( a7 S, q" S9 G" S( e1 Q8 k: j+ h
1 j0 G+ C8 p& m. |8 ^
這次我們單就偵測 IP 的議題來探討各種錯誤的寫法。% \8 X7 @4 N3 M6 x
# p& f* }' x3 B' i2 q
4 M1 l: W& C( ]4 c你知道網路上的教學是不安全的嗎?
% a7 L$ _, o* h5 ^2 M' L我們先來看一下網路上的教學,讓我們 Google 找一下「PHP 取得 IP」,就可以看到許多人熱心的教學,我們隨意挑一個常見的教學來看看。% c" |' J5 v' C( }) w, O" q* o
以 PHP 為例:7 [5 V! E/ l3 h4 I9 t" h) i2 ?
- <?php2 P6 H) C9 q0 e& Y! u
- if(!empty($_SERVER['HTTP_CLIENT_IP'])){
# m( K& D9 A( v* ?& V5 i+ i" A - $myip = $_SERVER['HTTP_CLIENT_IP'];7 B) l4 [1 I0 d# w1 M
- }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){" f* P' r' o' o4 G6 E" |
- $myip = $_SERVER['HTTP_X_FORWARDED_FOR'];, G2 v" h1 H+ U' o( M( G) U; q7 Z0 ]
- }else{! ]% O: Q8 u9 M% s9 q6 Z1 m* V) A; g
- $myip= $_SERVER['REMOTE_ADDR'];( f! G! G7 E! F2 {/ D0 p. y
- }* ?7 F6 {2 K7 z7 ^9 r+ n
- echo $myip;' F* W9 Y. r/ w# J5 O/ \. w8 m
- ?>
複製代碼
! }% L, Q* p) n+ B7 L: u9 o0 @
& V; `- V" r+ X u/ P- J3 k4 E這是一個很基本的寫法、很正確的想法,如果 HTTP Header 中包含「Client-IP」,就先以他當作真實 IP。若包含「X-Forwarded-For」,則取他當作真實 IP。若兩者都沒有,則取「REMOTE_ADDR」變數作為真實 IP。因為當使用者連線時透過代理伺服器時,REMOTE_ADDR 會顯示為代理伺服器 Proxy 的 IP。部分代理伺服器會將使用者的原始真實 IP 放在 Client-IP 或 X-Forwarded-For header 中傳遞,如果在變數中呼叫則可以取得真實 IP。
2 \- w: M9 S4 h( Z( {但是你知道嗎?網路上 80% 的教學寫法全部都是「錯誤」的。
0 x! K4 Z6 G$ u4 R' ]; W2 J, M1 k. {7 g# M/ w. T% _
為什麼這樣說呢?請大家記得一件事情:「任何從客戶端取得的資料都是不可信任的!」
$ R! R6 O, {& ~6 |, v% {" q4 k$ |1 |4 \. L, B6 P
竄改 HTTP Header「X-Forwarded-For」這個變數雖然「有機會」取得使用者的真實 IP,但是由於這個值是從客戶端傳送過來的,所以「有可能」被使用者竄改。
6 J& V+ {4 a# Q% ^舉例來說,我寫了一個小程式,偵測這些常見的 HTTP Header 判斷 IP。並且使用 Burp Suite 這個工具來修改 HTTP Request。3 u$ A& R7 }, L4 t- l' j! v1 b
& h! d6 @* y6 c9 n! _0 V9 H3 J+ ? u& |- p
頁面上顯示目前我目前的 IP「49.50.68.17」,並且其他的 header 是空的。但如果我今天使用 Burp Suite 之類的 Proxy 工具自行竄改封包,加上 X-Forwarded-For 或是 Client-IP header:3 o$ L! L& g6 g5 C

, m7 t% L% l5 y2 n修改完畢之後,再到原本的顯示 IP 介面,會發現網頁錯將我竄改的 header 當作正確的資料填入。
. y& M: Y4 s0 G( j$ W - e# a0 B7 b+ o4 [1 x% R5 ?% r* Z c4 M
" R! z, ]1 _$ l) t. z) B! J0 V
使用代理伺服器 Proxy 的情況使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。* P* E" ?' k, u1 Y( T) Z
直接連線 (沒有使用 Proxy)" X6 S1 k' a# ?% f7 _' ?( s
) ?; Y$ f9 j' e - REMOTE_ADDR: 客戶端真實 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無: X B! U# C/ E! v( B; F& k6 O
Transparent Proxy3 H) a: g9 K; K. ?
$ {/ a* g5 t+ j/ A
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP
& W5 }5 _' {) c0 W! A. C, ?: d- @ Anonymous Proxy
9 g. j! N2 f& z: H' n* H1 Z, E, Z }3 b
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP
' N+ A7 u& t G1 O; |" \9 A High Anonymity Proxy (Elite Proxy)
: @0 T( }+ \' ?8 Y+ L, e, y- g+ {% D1 G6 J
- REMOTE_ADDR: 代理伺服器 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP)
5 Z ^, C) M) l8 }' t4 \ 實際情況在我們測試的過程中,通常我們都會讓瀏覽器自帶 X-Forwarded-For,並且自行填入 IP。常常會發現有一些網站出現如下的警告…
2 c9 j/ o+ g6 f& y" _ # M- P, @- V" V8 h0 a p6 Q' U
有沒有搞錯?「上次登入位置 127.0.0.1」?沒錯,這個是知名論壇套件「Discuz!」的功能,抓取 IP 的功能也是不安全的寫法。也有這樣的經驗,之前開著 X-Forwarded-For 的 header 到一些網站,竟然直接出現管理者後台!2 q' T0 w0 c! E# A& ^: [
你覺得只有一般人撰寫的程式會有這樣的問題嗎?其實大型網站也可能會有類似的問題:" n' c+ f* B: i

: ?# l( G) Y- a: ~先不論為什麼 127.0.0.1 會在美國,這樣的寫法可能會讓管理者永遠抓不到犯罪者的真實 IP,甚至攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。& }: h5 M/ }& I( r% [
/ l) n" v: ]4 d
正確又安全的方式「任何從客戶端取得的資料都是不可信任的!」
^ A0 d1 C; S& X( c, f F請各位開發者、管理者記住這個大原則,雖然這些 Request Header 可能含有真實 IP 的資訊,但是因為他的安全性不高,因此我們絕對不能完全信賴這個數值。6 f# Z) G) Y6 k
那我們該怎麼處理呢?我的建議是記錄所有相關的 header 欄位存入資料庫,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。
5 x9 ~8 |$ Q/ 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): R7 ^$ i0 M$ |4 A; R: H
「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的,不要再參考網路上錯誤的教學了!
5 u$ e; H- k! o
( e5 S+ v2 ] l*原文參考 CEO Allen Own 大作 http://devco.re/blog/2014/06/19/client-ip-detection/ q, c& G" F+ m$ r, e
|