一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: | proxy_set_header remote-user-ip $remote_addr;
8 B8 @$ r5 z7 H" [" g0 N; {( k- f" Q# p% m( l
|
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,1 Q7 E& q& r# y. ?
怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1
5 q, G6 M7 C, G$ T2
: I3 K8 n7 Y6 Q6 Z3 6 [) }( w: h. s* I J) o9 P
4
9 v! c1 `" V; k% R V+ ?. S | <?php- M: Z2 b" w. h ^# S
$ip = getenv("HTTP_REMOTE_USER_IP");
& ?& S) o$ T( N8 U echo $ip;
& a2 j# v; a+ p9 }?>3 y2 C( R+ L- M/ P O' R
" L" R' p" @8 w6 } |) y
| 2 u5 |! Q* x+ O2 x
访问getRemoteUserIP.php,结果如下:8 \% }8 G; Z1 j; n8 o& y9 Y& H
120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳
; i$ P! x$ ~3 R, U+ C# S/ Z9 e, y! z* t7 M6 U7 |, z
二.通过HTTP_X_FORWARDED_FOR获取IP地址 一般情况下CDN服务器都会传送HTTP_X_FORWARDED_FOR头,这是一个ip串,后端的真实服务器获取HTTP_X_FORWARDED_FOR头,截取字符串第一个不为unkown的IP作为用户真实IP地址, 例如: 120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121(用户IP,CDN前端IP,CDN中转,公司NGINX代理) 1
5 t: N1 H( q$ s5 G2 r2
) n5 H/ U7 N5 }" K5 E6 H( I3
5 }- m% a( m! ~; l4 6 S. i/ d" q4 n; G4 g/ Q$ u( x/ B
5
4 t: c3 \. b; ] | getFor.php" }! l" q3 K7 a. t+ y3 ^8 p6 ~- o
<?php% Z' A$ H8 d9 _4 O% [
$ip = getenv("HTTP_X_FORWARDED_FOR");: U3 s. g( ?# e- [6 t
echo $ip;
, R8 A! e6 W, t2 S?>
8 y8 j: S# T: `: G& X! l3 {6 O" k! Y% e& G
|
8 h2 h3 g1 z* b# f1 \访问getFor.php结果如下:120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121 如果你是php程序员,你获取第一个不为unknow的ip地址,这边就是120.22.11.11. & k+ x# v( b% ?5 \
e- k: e2 Y( b 三.使用nginx自带模块realip获取用户IP地址5 J' y: p2 k6 P3 ~
安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module
# l' j9 g% s- P2 f3 u% J: v7 l 9 @5 R4 I' I6 ]3 N* ?% r1 \
真实服务器nginx配置 1
$ m& p6 r# \, O, Z1 ]6 }& E, T+ u( T9 [2
, L5 m8 q$ H' u3 P3 ( ]( R5 O: q* G" A. a# I: m* |
4
: o4 k' _* N* B1 U) B$ M$ |+ b9 f5
# A+ M/ [7 G; f. v- w7 Y& h- A6 ; t1 H, j1 ]- @1 [7 z( X) y
7 6 N X5 ?- d" S0 h8 ^
8 $ P/ q+ B! q" D6 W
9
) G7 m! T) k* I/ c7 ^% G10
& a0 J$ T& k9 f, M& r11
: j4 M; b+ }2 `5 ^4 S6 |) C12 4 Y. i( {3 H. j. z# P& g c
13 / o3 U0 R( O4 X o/ Q
14
; y2 u5 J$ \" C! C% u15
+ P3 O4 ?3 X" l. ^) [6 o/ W16 # @4 E: V8 V9 k" s% t
17 ) {( [: a+ ]: P7 l6 R7 r
18
; T% W; @, ^/ V* l1 W8 \19 : N* I# N/ F# X; k% V
20 : F6 O5 k5 n. `% o0 J+ i. \
21 : k$ @- C/ p; a D1 s
22 # H5 e6 |2 o! L- j
23 - A* i f& i8 l# q" A2 W
24 D$ g* |3 i3 w) k* f+ [, L
25 3 b, U9 W9 c" ^
26
% X6 V* W1 t8 ]# L27
# ^3 u3 m6 Y2 m) w28 / A( }7 ?! g( f; y* q
29
+ Z1 d6 V7 a& h" d# O30
- c! J8 U0 ^# W( l4 v31
6 O; g( ], {$ a5 { D0 M! f | server {
, g) J+ S/ B; s6 ^& J listen 80; 6 l: I7 D5 E7 V5 m4 z* Y$ Q
server_name www.ttlsa.com; 9 o8 M; q# z" P$ G. V, P! p
access_log /data/logs/nginx/www.ttlsa.com.access.log main; 6 ^5 t9 d/ E g3 D, e* a7 d' D
3 R. |, O0 g( ?7 S& Y
index index.php index.html index.html; + Q: V0 Q0 c+ c" [
root /data/site/www.ttlsa.com;
2 |) [1 B: W9 k o7 h- y8 K& G5 j
location /
. p% V' f4 p; F5 R7 o' j { 6 R. A$ K% N: l
root /data/site/www.ttlsa.com; $ U5 @- U' q& ^8 q# S' v
} 2 w2 v9 N+ L* l7 S7 K6 t7 e) C
location = /getRealip.php
4 z1 q o* e- L/ y {
' s! q" G" C6 b set_real_ip_from 192.168.50.0/24; ; y3 T+ Z3 i# M+ A1 w
set_real_ip_from 61.22.22.22;
4 F. }! l3 R, e- ] set_real_ip_from 121.207.33.33; . m. H1 I! V( t/ i0 U
set_real_ip_from 127.0.0.1;
8 j( e/ m# T; Q0 ]% y$ z9 K real_ip_header X-Forwarded-For; : F* r {( f' s+ q* Q+ v5 ?
real_ip_recursive on;
* d' k, v1 e- k8 u/ ? fastcgi_pass unix:/var/run/phpfpm.sock;
; ~5 i* O6 o8 G: W fastcgi_index index.php; & o! ~! C9 B1 G
include fastcgi.conf; 5 [2 B; T# D/ I$ H& O Z# N% f
} . f) |6 j" s' E5 j
} , \/ T1 u. {$ F7 J/ s% y, Q$ l" e
: e S/ N; L& N, b7 u3 t) z
getRealip.php内容 . `1 d1 C1 N: k* B* e: Q
<?php
# w: n/ S! p$ | $ip = $_SERVER['REMOTE_ADDR'];
; v4 l. T. }) x% U, G echo $ip;
/ W4 ^# Q2 N9 J$ y& L ?>
Y8 G8 m N+ E; O! q" G5 b l6 Z. Y- Z, P- _: v
|
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行 L# t" {7 N7 h, i
real_ip_header:从哪个header头检索出要的IP地址' F3 u! u6 q8 e! W$ U
real_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
1 O8 M' `8 \$ C; n120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121
6 {; V1 [/ H8 r在real_ip_recursive on的情况下
" b. @( W2 k; Z6 Z, l8 z. {1 x61.22.22.22,121.207.33.33,192.168.50.121都出现在set_real_ip_from中,仅仅120.22.11.11没出现,那么他就被认为是用户的ip地址,并且赋值到remote_addr变量 在real_ip_recursive off或者不设置的情况下
4 e. d$ L7 o; J6 X9 l1 L& O* z9 X192.168.50.121出现在set_real_ip_from中,排除掉,接下来的ip地址便认为是用户的ip地址 如果仅仅如下配置: set_real_ip_from 192.168.50.0/24; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; real_ip_recursive on; # n/ V) j& Z1 ]+ o( J
访问结果如下: 121.207.33.33 $ `) ?8 _# U3 C% r3 V# y: b7 I
8 y: C# o. ]- \- P0 \
四.三种在CDN环境下获取用户IP方法总结
8 N; f0 c5 ~; U0 B4.1 CDN自定义header头( u! Y; [& \0 I: G6 M
优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP; @" L2 z, F9 E3 }0 D3 V
缺点:需要CDN厂商提供
# ~/ x9 G8 R" h: Z
4.2 获取forwarded-for头$ M- y* q2 }, e/ F& C
优点:可以获取到用户的IP地址* W) W% v1 x8 N$ d9 y$ q5 T6 h
缺点:程序需要改动,以及用户IP有可能是伪装的
- Z4 O+ \: {1 Y$ p% \2 q$ C6 [
4.3 使用realip获取* D* z! x/ B. v& ? w; X! j
优点:程序不需要改动,直接使用remote_addr即可获取IP地址, x& d6 V7 r1 }( @
缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段 ) V' H" J! m/ {* y9 ~( r4 M
|