一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: | proxy_set_header remote-user-ip $remote_addr;. i5 w, l2 c/ R5 q: [- F
4 U4 ^/ B* m7 w- C3 ?& h
|
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,7 C+ K1 t( k. R3 t1 i: C8 c
怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1 8 j& R/ E/ N e1 {6 Q$ K3 _
2
9 U1 k. I* U& V3
7 l3 t( Q5 ?1 o" }$ d* T4
* u' U& b# c0 I* s* O6 | | <?php
4 n& y& r9 E5 h0 Y) |+ F8 L $ip = getenv("HTTP_REMOTE_USER_IP");3 Z7 Q/ {+ L: {8 H
echo $ip; d% E5 |8 j6 H8 c# ?: {
?>
" A( R1 }* I3 y3 y% w
. D. d; E4 k- ~; ? |
7 g1 k/ t0 \# x访问getRemoteUserIP.php,结果如下:. I& R, h: h8 `
120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳
$ h! V! ]. X6 M+ p' |# O) G$ z6 z0 B
二.通过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
# I/ ~9 x3 R9 o% G2 |, o Y2
' S8 Q$ D3 }/ o4 n) k3
1 |4 X# A4 c5 I6 \- ?7 V9 Z! L& u4
) g3 {/ M/ z& i) C/ K5 9 K" Q8 P, p5 q4 Q9 G* M+ N
| getFor.php
, n% J$ t' G* I! B<?php) e$ H: |$ Q) G6 K. h! _
$ip = getenv("HTTP_X_FORWARDED_FOR");7 U) q9 g" l1 e8 B# g3 i9 P
echo $ip;/ r6 c7 D8 t7 x$ L& o) s8 b
?>$ ]4 g' j. F! u9 d
; s; B' R2 U, G" N0 s |
8 S6 S$ [: y) s% g7 J访问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. ! z- p+ V% _+ O0 i5 o" ^
; g3 P4 \4 `2 N8 G( |! { 三.使用nginx自带模块realip获取用户IP地址
, t+ F" o7 a$ M, |$ _* }- r安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module' B6 m$ |; d- y1 F4 r0 d! k8 S
: F* N1 I2 r) }. f( J/ }0 Z0 \: k7 s真实服务器nginx配置 1 3 A" G: z2 y% X c/ e3 x
2 7 x a% } t9 T9 e: d
3
) G9 v" i5 C4 H4 D' Y4
8 E L2 e7 L- Z5 8 ~! [( u) h7 o8 E z
6 + V" ?6 c6 D7 G5 f- s1 g6 p& g
7 # o G2 C- f* v5 K
8 6 |1 ^9 {+ G. K* t
9 ; v3 |3 \3 ^3 T& Y( @$ X/ c0 U
10
# [, U, I0 l! a" A2 C; o% Q11
+ G) s F% L& i2 n/ Z. E12
1 }6 b9 }. _! I h2 Z9 @13
. h# t: o0 h- ~2 \7 @3 i' G6 t14 0 C) B2 q* ?6 @
15
. a/ _7 t$ A4 y5 h4 ?( q/ N1 D16
, X, E. S9 z; l0 s/ d. H8 M& @17
p2 ^: q* ?6 @' Y8 _18 ' C0 v i3 L3 g9 y& U, C
19
% k/ Q1 V/ I, l" p, E9 U: x20
0 L5 h! A2 S" s! r21 / x( f% f A- n0 ^; G1 H: ^' z6 C
22 / o/ f& W! j; y
23 , x* E( C i( R- Q1 S
24
# v5 l8 m4 j: R/ p& z- d25 , K! |2 T2 h4 t( G4 q! T3 N" Y
26 - a# K: l5 j- { O
27 ! Q) t9 a4 w) E7 k7 X
28
# x2 h5 f% e5 }7 _: f" r! H29 # O! V+ z% Q6 ^, J D' V, O
30
" U7 {, E3 b4 i6 `# C, D31 ) {; y0 j3 |; p* J
| server { . S4 `/ \! J2 b: m1 W
listen 80;
& t4 h R+ Z! f6 G% }$ U server_name www.ttlsa.com; 2 j$ W( N3 s) Y0 w! N: [
access_log /data/logs/nginx/www.ttlsa.com.access.log main;
$ w F2 ]7 ^7 ]9 Y. R+ O 0 g) ^) N7 h: c
index index.php index.html index.html;
|1 P$ O% a H root /data/site/www.ttlsa.com;
! \8 m" c5 \: A0 A0 q * n2 R: t3 g% k! d
location /
/ H$ w& v3 W; y& N {
2 [/ \4 J' h: ]: s4 f. R root /data/site/www.ttlsa.com; 5 h- k5 f+ W1 f! L
} ; M3 F% \: B3 }9 }" W
location = /getRealip.php
! g" c% J3 k% }( @- m& Q% K {
" u! ]8 T" W4 D6 j set_real_ip_from 192.168.50.0/24; 0 _8 m% P% Q+ p" r
set_real_ip_from 61.22.22.22; / p; m, c6 X5 _) M# O L
set_real_ip_from 121.207.33.33; , k# A; b0 [# p: ]. m0 ^
set_real_ip_from 127.0.0.1; " e3 y" u% Y5 C' T* C( ?0 U% z$ g
real_ip_header X-Forwarded-For; 4 h3 P0 k* e5 Q ~ @/ G& H
real_ip_recursive on; " K, d J6 X: k' P9 }) ^
fastcgi_pass unix:/var/run/phpfpm.sock; . J. Z' o2 L% }
fastcgi_index index.php;
! o, V4 E/ ~2 _. U include fastcgi.conf; 6 ?- s" N$ B5 H0 F" d
} 1 e; M, H" Z d' o# j8 @. N
}
: Q' f# v- j4 A
) L0 x2 v, V9 RgetRealip.php内容 $ j9 P' }9 F1 C* d" |- g. y3 S' u/ `
<?php
$ R3 E! I7 J$ B: t0 ? $ip = $_SERVER['REMOTE_ADDR']; 9 j1 x f+ ~$ M
echo $ip;
6 i) y/ W; Y' V$ g5 t6 t7 G ?>
$ W" O- {+ P6 e' V K( A2 M+ h' B' M/ t4 _2 e1 w, ]
|
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行8 s1 r2 k7 q: y4 D! c% a, H
real_ip_header:从哪个header头检索出要的IP地址. T2 F1 w) k, W# [
real_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
& J# p7 {) i3 a1 p8 n% E8 I5 K5 z120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121
6 M- o( F6 ?7 Y m4 n/ E. ^! s在real_ip_recursive on的情况下
g3 I! @; d$ b9 r' e# I61.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或者不设置的情况下
) k- [$ r! W1 H) p# q; Q# `192.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;
7 W1 }1 @1 i& V5 t8 D访问结果如下: 121.207.33.33 2 t3 S2 C# Y& j
, t) ?, X% ~. p# O1 p' `四.三种在CDN环境下获取用户IP方法总结( k- g( B- f. a3 ^ o; g; ?
4.1 CDN自定义header头( k: L, r7 L3 o2 N7 M7 i }- C
优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP# [% ~( ~4 k0 B4 @6 W/ `3 N+ n: S& ]7 n
缺点:需要CDN厂商提供 9 Q/ I2 x' H' t5 }# H9 S5 k2 K
4.2 获取forwarded-for头
5 |* [6 M' {* V, L+ f优点:可以获取到用户的IP地址
; `, D" _: g* q5 F I缺点:程序需要改动,以及用户IP有可能是伪装的
, H% H% Q8 @! b
4.3 使用realip获取, h' p- N$ c! A9 D- k0 G- b! A$ r
优点:程序不需要改动,直接使用remote_addr即可获取IP地址
, ]! B1 t6 V1 [缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段 7 h) L1 q; [1 A' A5 k- J* n9 x
|