tid=12495& 本帖最後由 IT_man 於 2015-7-3 10:47 編輯 4 B, K6 k% n3 h/ b% `
9 u1 `+ g T9 ?0 z# j3 G很多網站都會有偵測使用者 IP 的功能,不管是判斷使用者來自哪邊,或者是記錄使用者的位置。但是你知道嗎?網路上大多數的教學全部都是「錯誤」的。正確的程式寫法可以確保知道訪客的 IP,但是錯誤的寫法卻可能讓網站管理者永遠不知道犯罪者的來源。4 S, V. E, F, a
5 n1 L; C, u2 J/ d" `8 t8 e這次我們單就偵測 IP 的議題來探討各種錯誤的寫法。. Q( q2 v' S. |9 ?# ?5 p
3 g- U/ u* r2 Q `9 K" y K! W
9 Q* T8 U3 U! Y
你知道網路上的教學是不安全的嗎?
9 b6 _0 K9 y# t3 @ s$ c8 |# F) }我們先來看一下網路上的教學,讓我們 Google 找一下「PHP 取得 IP」,就可以看到許多人熱心的教學,我們隨意挑一個常見的教學來看看。
" a0 C/ r* T, e. {+ l' v以 PHP 為例:! \# n; ~. j" Q& [' D* a2 J8 V; _
- <?php
4 p% C/ R& p4 j: q/ n - if(!empty($_SERVER['HTTP_CLIENT_IP'])){- y, B& _. P& U- I0 x( o# {
- $myip = $_SERVER['HTTP_CLIENT_IP'];
# W# V! N4 r% K) b- P - }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
7 ^% x2 g0 D5 a8 X' A3 D" ~# @# ?' M - $myip = $_SERVER['HTTP_X_FORWARDED_FOR'];
4 u Y% l) s6 w4 T: J. W - }else{
; S9 o2 R! k" \4 u) ?9 ~: o - $myip= $_SERVER['REMOTE_ADDR'];. g1 l$ U& A3 D! W) Y) e* {
- }* v, I; |$ X+ V- _3 J) P4 Q" O! x
- echo $myip;) H. \4 Y: J0 E. E3 m2 R
- ?>
複製代碼
! F, n& A: ?( i R) x; n: K {5 |+ p: ^0 j
這是一個很基本的寫法、很正確的想法,如果 HTTP Header 中包含「Client-IP」,就先以他當作真實 IP。若包含「X-Forwarded-For」,則取他當作真實 IP。若兩者都沒有,則取「REMOTE_ADDR」變數作為真實 IP。因為當使用者連線時透過代理伺服器時,REMOTE_ADDR 會顯示為代理伺服器 Proxy 的 IP。部分代理伺服器會將使用者的原始真實 IP 放在 Client-IP 或 X-Forwarded-For header 中傳遞,如果在變數中呼叫則可以取得真實 IP。0 E3 P( j5 U2 [6 j/ z
但是你知道嗎?網路上 80% 的教學寫法全部都是「錯誤」的。$ J C8 h7 Q5 K0 m4 ~1 I, u$ a
; L- N1 v% ^) l- f
為什麼這樣說呢?請大家記得一件事情:「任何從客戶端取得的資料都是不可信任的!」; e0 Q& X! L4 s
/ ]+ d- |/ ]6 z: d# h o( n7 H7 W
竄改 HTTP Header「X-Forwarded-For」這個變數雖然「有機會」取得使用者的真實 IP,但是由於這個值是從客戶端傳送過來的,所以「有可能」被使用者竄改。- t' N. D8 y! S% Z4 m) s$ G
舉例來說,我寫了一個小程式,偵測這些常見的 HTTP Header 判斷 IP。並且使用 Burp Suite 這個工具來修改 HTTP Request。! u5 z. j4 \+ Y$ h" L9 G7 C
' }) f) c7 Y/ f- ]. w& N9 i5 L6 @1 a' O" U6 E0 `
頁面上顯示目前我目前的 IP「49.50.68.17」,並且其他的 header 是空的。但如果我今天使用 Burp Suite 之類的 Proxy 工具自行竄改封包,加上 X-Forwarded-For 或是 Client-IP header: c/ |3 n2 @8 C7 W. U6 X0 S

- U5 g, y& p5 `! |3 M修改完畢之後,再到原本的顯示 IP 介面,會發現網頁錯將我竄改的 header 當作正確的資料填入。
- r R2 o2 y; B- L& x0 _ ! L7 ~6 I6 A6 J+ q
. w2 E9 i* h2 r0 g
使用代理伺服器 Proxy 的情況使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。
^- X( t6 T$ |& G& |; U0 v# J直接連線 (沒有使用 Proxy)( }/ Q5 ?+ c. E
* ^; o9 [1 V; n \1 `0 z4 v9 f5 x1 j - REMOTE_ADDR: 客戶端真實 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無
6 m7 K7 p8 T- a1 Q! g Transparent Proxy* N! b6 \$ T' I
) d- I! i' u0 ]: D, Z
- REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP
$ b! X1 {! h# `! G: {8 R Anonymous Proxy
+ ^8 Z }$ Z/ ^9 ~ y$ @
) a) c( [3 c7 g: B& U - REMOTE_ADDR: 最後一個代理伺服器 IP
- HTTP_VIA: 代理伺服器 IP
- HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP
. E# i9 D* l3 p High Anonymity Proxy (Elite Proxy)
3 p7 {2 v% A/ g$ h5 @' \/ V' q1 }7 l( e
- REMOTE_ADDR: 代理伺服器 IP
- HTTP_VIA: 無
- HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP): V o( ^( t8 }3 ?/ i5 c- n7 o
實際情況在我們測試的過程中,通常我們都會讓瀏覽器自帶 X-Forwarded-For,並且自行填入 IP。常常會發現有一些網站出現如下的警告…
) B" K' _- F4 z8 B3 H) W* ~# v
! h7 S. J6 S% M( d有沒有搞錯?「上次登入位置 127.0.0.1」?沒錯,這個是知名論壇套件「Discuz!」的功能,抓取 IP 的功能也是不安全的寫法。也有這樣的經驗,之前開著 X-Forwarded-For 的 header 到一些網站,竟然直接出現管理者後台!
8 E+ G M; {! `4 ^2 D, O你覺得只有一般人撰寫的程式會有這樣的問題嗎?其實大型網站也可能會有類似的問題:: h, F9 v+ D3 y3 N
) o2 P' n- j) l% S
先不論為什麼 127.0.0.1 會在美國,這樣的寫法可能會讓管理者永遠抓不到犯罪者的真實 IP,甚至攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。
! y% D; g1 S$ u* S! q/ Y& r( C2 h, q0 v0 S# A6 T7 E/ n9 h6 Y
正確又安全的方式「任何從客戶端取得的資料都是不可信任的!」8 o( i- Q2 G) u
請各位開發者、管理者記住這個大原則,雖然這些 Request Header 可能含有真實 IP 的資訊,但是因為他的安全性不高,因此我們絕對不能完全信賴這個數值。
$ p0 u' I: G, D' F% y8 b6 f. M6 h那我們該怎麼處理呢?我的建議是記錄所有相關的 header 欄位存入資料庫,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。2 @9 O7 i6 t3 [% ^8 G' y0 l( B
可以參考的 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)! _* R9 w8 s* K1 @8 W3 J3 F" q" |* C
「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的,不要再參考網路上錯誤的教學了!
% \- |9 A1 h1 u' Q6 d+ P& U y2 T+ j7 D4 q. P. `2 c% ?- M
*原文參考 CEO Allen Own 大作 http://devco.re/blog/2014/06/19/client-ip-detection/
) c* I7 u* @9 i! X! c& q, D/ {, Q |