|
一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: | proxy_set_header remote-user-ip $remote_addr;6 f" L) j) j3 H( T" \
7 p. Y) D* F( }; D! I) e0 Z
|
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,( [) O6 ]6 B5 W. J$ u+ ]
怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1 ( m0 f8 X$ b/ X. M- G4 o
2 + Y/ t2 l- L" D* x. ?* v O
3
. K$ G& p+ ?: c1 v. A4 " m `; X- T; K4 o- V
| <?php' u* ^( n- J+ Z8 o
$ip = getenv("HTTP_REMOTE_USER_IP");
# e5 F' A" Y% v$ N E0 e& f) Q/ i o echo $ip;
0 c# O+ S% [9 L7 Q4 {, P?>% Y9 H0 Z! ^! q# ?
* V1 j* x N6 [' n9 @
|
4 n5 A E2 V% j* l6 {1 W* z9 W3 b( R访问getRemoteUserIP.php,结果如下:4 [( u0 \# ~& N" Z I
120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳 D; b7 Y3 o3 J9 Z* r
% ], A- `: e# _) K$ I
二.通过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 6 C) `3 E) `* m
2 - [- ^ m7 p- V
3
) X& a) o* b, n: W3 ]2 q, U. u6 E) T8 P4 * w+ `: ]& q! }7 d0 q4 N: {6 p6 x
5 3 s9 K* V3 p# l7 s2 U, d2 h
| getFor.php
5 @- a7 i n4 Q, d+ I, b2 ]! x<?php, A6 x0 n! [5 F7 a* [! r
$ip = getenv("HTTP_X_FORWARDED_FOR");
2 e$ ~' v3 `' X: [4 K' D& a ` echo $ip;4 ~7 Y& a: Q/ k
?>
6 h' e, ]% I$ W/ d7 p, F
% k# _& M4 n% Z J, F% e6 M | / A. g: R+ |5 N) [9 }/ g; y4 ?
访问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. 4 m0 X* p) ~9 Z" y
6 H( n7 f/ V& F) ~6 P2 a 三.使用nginx自带模块realip获取用户IP地址' D3 Q$ V: Y( a9 o% v7 n
安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module4 @& e+ S/ }+ t- ?% {4 m
5 s, v7 z* E# q# `7 D) \5 `" s
真实服务器nginx配置 1 ' O2 V+ e$ u2 I5 j, q9 K4 E: N
2 9 O, k, e4 n( [
3
2 I3 C3 |) ]0 o4
8 [. I: j+ `, g5 7 |: v' S8 P6 c5 P2 Z
6
7 x# d0 P' y1 r8 m3 N6 h( C7
0 M# i H3 D9 v8
5 b& u2 w: N P- n' I$ r9
7 h" x, N* ?: p- R. _# w! K) m10 # t4 E& A" U3 `% K" a- Q; A( l
11
. i4 I' {3 z) D+ r, p5 A* y12
* L+ v3 M( k9 E7 j' N13
7 F ^( `" G4 O$ Y. A8 d5 ?14
1 Y O. K" C5 N; L& l- }2 p2 S15 / o' k+ V9 ^6 d# h i
16 / u" y: D& f; W$ S: X: b9 a, Z
17 : X2 b# G$ x: C% T5 \' X
18 3 m8 ~: Q; t* O, s- x: l" G
19
( E" R% J9 v# [$ K20
; D% t+ s1 C% v6 t ]/ n3 b; B21 / {4 l& s" M( f5 V
22 1 b. E4 f/ R; ^, |+ K! w) F
23
8 N) C( R, t$ s' z! A4 y, D24
+ i* ?0 \+ m5 j, F6 X1 V" e/ s' j25
; `1 J$ G1 j2 r- W4 j26
: y3 v* U" I6 p$ h+ p% ~27 7 T' |" P. b7 ~3 t! U$ @8 D H
28
$ c8 i1 T: Q+ @29
% }1 A2 ~8 y) C4 s, Z7 [- e30
5 ]) Z" H) `% c31 0 S. ?: h2 h4 a! P2 k( {/ P7 N1 j
| server {
( M7 w7 C( ~+ X. s4 b8 h# V listen 80; 5 Q9 k9 r/ }# B# N: z
server_name www.ttlsa.com; 6 T4 u1 m( {4 d! w2 C6 a
access_log /data/logs/nginx/www.ttlsa.com.access.log main; 5 v- I4 y8 ?( M
- B" }( [: S8 C- t
index index.php index.html index.html;
& q& u% K) @8 ~6 h8 O; K root /data/site/www.ttlsa.com; + }$ Z' h0 W* A
f. v+ x" n$ b% r; \6 t* F+ ~ location / : L. s& g3 O: r0 U2 h
{
# E4 F: ^$ N" U2 f3 z root /data/site/www.ttlsa.com; ! f8 t. p/ V7 _
} 0 {" A6 p' g2 |. R5 C
location = /getRealip.php 7 c" q, T, H4 j& w! {
{ ! b% v9 L8 R- C5 \" a
set_real_ip_from 192.168.50.0/24;
7 a4 d1 h+ U0 U3 l0 O set_real_ip_from 61.22.22.22; 0 S/ R$ M6 k' ~7 J: w% B) U
set_real_ip_from 121.207.33.33;
( J7 ~3 Y, }9 M- ? set_real_ip_from 127.0.0.1; 3 P8 Y* N' l0 G& x) j. X
real_ip_header X-Forwarded-For; ) A- ?5 C( {8 T) L/ O9 w5 Z# Y
real_ip_recursive on;
( [$ v8 H( @( U- M$ H6 D7 B3 z fastcgi_pass unix:/var/run/phpfpm.sock;
3 t: ]4 k/ b; C* P2 W fastcgi_index index.php; + U, C. V- m! c' u
include fastcgi.conf; 5 B& D/ v! j g f$ e: c
} ; W7 Q/ H. G% F' d, V
} * W" M. ^. `9 F/ P$ d
D& c5 D( @2 ~$ `1 d; M! ^
getRealip.php内容 - J* r; \% Z' H, e
<?php
, L1 _0 n* Q! R $ip = $_SERVER['REMOTE_ADDR'];
* J! d: N4 b# v" s9 z echo $ip;
* n$ W( }8 a# J8 ~$ o5 f+ o# P) T2 j ?> . c, P4 ?8 D D# G: g
0 b; g+ O* s4 w0 k5 y7 C
|
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行( h6 e/ \8 Y4 ?8 L
real_ip_header:从哪个header头检索出要的IP地址
3 L# E0 F/ f1 x Z) }: creal_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
$ J4 o8 G7 ?' M P120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121) H4 s5 s ?* T! x2 Y" a
在real_ip_recursive on的情况下7 v+ f3 i- ~1 v' ]( P6 b
61.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或者不设置的情况下. ?9 i: n9 S6 ]+ m# M2 K2 l# E( |7 N# `
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;
/ E6 P; ]; x7 r% Y访问结果如下: 121.207.33.33
. }4 R5 d+ N. N' g! ]3 N# n " U: A9 ~# _2 q- Y, ~* R
四.三种在CDN环境下获取用户IP方法总结
. O* r, b( l4 D4.1 CDN自定义header头
( F2 c7 F7 s# Y5 x( s优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
" x/ {8 D+ f+ e5 ~缺点:需要CDN厂商提供 6 Z0 [: Q8 m, o6 e9 \" m/ B
4.2 获取forwarded-for头
8 s; T: d: _" k4 Z0 t& ~优点:可以获取到用户的IP地址
- _: n- u% @! a缺点:程序需要改动,以及用户IP有可能是伪装的 4 w+ {8 u4 e. `1 n; V8 \1 v# K
4.3 使用realip获取
( @/ Y/ U% e6 Y3 }# L' m3 C优点:程序不需要改动,直接使用remote_addr即可获取IP地址
9 j/ s& [8 L5 }& B2 m# ~: W/ Y9 Y |缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段 % s$ i* y. q$ @4 z/ _( D5 l
|