一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: | proxy_set_header remote-user-ip $remote_addr;7 @% a) @* `( Y- Q( Z" n
$ i9 d h8 C3 G |
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,, R5 U* p+ a7 c7 r
怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1
3 d& M6 u9 n4 [6 v# l/ ^6 b2
2 Q, [0 W) u+ }1 P7 R6 U3 b4 S0 g; A& i$ A: m) M
4 1 ?1 a" r+ D0 j& p% B. f
| <?php0 o, ~, L' j1 v0 x6 ]
$ip = getenv("HTTP_REMOTE_USER_IP");& y+ g% y7 ~% v1 Y
echo $ip; 7 t6 J }& Y% Y
?>2 x# o) n' S, v8 c3 k
) z8 ?# q2 r* P* X* L9 w
| $ u7 }- _( [# P
访问getRemoteUserIP.php,结果如下:! F7 k; n6 p8 g0 i) f' z
120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳 3 C z7 n5 N5 v
- t8 n3 R" ~; f0 o& {4 _# ~
二.通过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
' V; ]/ a& k7 O/ F% e+ w2 1 D/ G$ S& ^; p9 W2 w3 u' _% o
3
* Y: p ]' h; s: g0 |+ Z4 7 X( r; B+ ^0 _5 Z
5
& z& i9 C) J; M# D | getFor.php
3 y2 l' Y6 l. [' x0 O6 z" ?0 q<?php, i+ Y' x( o' g% ~1 g
$ip = getenv("HTTP_X_FORWARDED_FOR");3 u, e4 v" o1 }& O0 q0 T
echo $ip;+ f5 g) C3 L3 A; W3 ]6 b
?>
- R6 k9 F8 `6 v$ a8 B- h
, d. Q+ p* n# B | ) M: ]4 i% Z, i0 S& D" k
访问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.
) Q6 x; R% N# ?
( A. S) s7 e3 j. }9 R 三.使用nginx自带模块realip获取用户IP地址
3 W+ p7 s- o. `! F+ h5 L1 k安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module
4 R0 o# R; y. l8 w9 f
$ u# Q3 J3 E1 P! g% D. m: H/ x3 _真实服务器nginx配置 1
; T& ]- K( Y/ v, X2 7 P4 R; z( @8 `/ ?( r
3
7 }9 a9 ^8 b# Y6 J8 J. ^' |) }# M4
8 N3 w& z4 N% d y0 V" c5 4 |' T! o" I9 t8 Q* D3 R3 Q* e
6
; I6 |* F5 x) N4 q2 _1 G" `7 ) v- ?) T# \7 w& C# c
8
4 x; N4 b9 `9 s. {. ~; G9 5 c# b5 u# v# [% a- P% ?
10
; j; \! p$ X/ f+ M% E11 $ u! O0 J8 i8 p3 [
12
2 ^. b3 ~5 x) i5 {: P$ ]13
: A6 v, e. k- v6 U3 C14
6 ^6 ?% ]! n2 A0 A" b4 L+ W15 7 Q" k; Y* W' u6 c
16 ) ? z% A8 q, e* O6 H
17
9 u+ a5 X6 q2 Q+ X" p& W3 m18 7 w0 s% e# x: q; `' [ a. ?
19 % ?& V# l; Z8 j. D2 X' b+ q
20 " h+ D6 g9 r. v
21
' {$ Y: |$ S6 z7 N; i, I22 % L; \% x, r1 Z9 \" [8 ]' l+ z9 G/ {
23 ' _& |' \' n: d, `
24
5 E/ H! ^6 {' {* ?$ T6 {+ _' \. t25
; d# |/ b9 E9 n, [/ B$ D g- k26
% y( _, `& |3 K% Q/ T27 9 d+ c; i5 b! L2 I# i4 ?
28 7 j. ]. ~. N( f6 U6 w/ e& Q
29
& ~( P4 E) W Z$ b+ ~0 O30 " g& v: v- Z% d2 }+ c; i
31
( Z9 h! K9 u$ e! U' l/ I/ ], g | server { : M& `. W# J' A: ]2 u& G$ S
listen 80; 5 B$ i' z! g: q8 s4 P% j& M
server_name www.ttlsa.com;
8 m ` {! H" `$ k! e0 D& Q access_log /data/logs/nginx/www.ttlsa.com.access.log main; 6 W: K+ S2 }( f
' O# Y+ l/ r7 Y5 ~; g Y index index.php index.html index.html; 2 u- F) `9 @2 f5 W3 w2 T! ?- T0 V
root /data/site/www.ttlsa.com; 5 l9 ^7 ^6 l3 R/ G4 G
: E% E1 ]& g$ C0 r
location / 5 Y! A. u# E4 D0 B" H g* }/ A9 z3 e/ O
{
5 m" O- w2 K4 q0 m root /data/site/www.ttlsa.com; # N, }8 y% S, k! B/ y7 ]: @- G
} ' U9 R7 x$ X ]' E: @: U7 G
location = /getRealip.php ; K8 y7 L! m. D5 d) |5 J
{
: F U* [% h2 P& r set_real_ip_from 192.168.50.0/24;
' K' A& Y# J+ ?/ X% R0 Q6 N$ x set_real_ip_from 61.22.22.22; * N4 @, n+ Z! ]& q+ [
set_real_ip_from 121.207.33.33;
* V0 Q- r5 H U5 z set_real_ip_from 127.0.0.1;
5 A$ A: o# w; L6 O9 ]9 s real_ip_header X-Forwarded-For; - J+ h, K3 p0 c& C; o7 {; N4 X
real_ip_recursive on; ; ?' N( l4 d1 b) H; h/ [
fastcgi_pass unix:/var/run/phpfpm.sock; & E+ n+ j* T2 ^3 G1 m
fastcgi_index index.php; ~" b& w3 C7 C4 d3 w+ n
include fastcgi.conf; 2 t0 Y, @5 z3 |% g& Y! h
} . d- U' m" G8 H
}
! m7 C" p, p: [3 M- D; g7 }
5 S2 f3 R9 A" m+ B5 GgetRealip.php内容 0 L( `3 R$ Z( z# f+ f( J# J8 t, G
<?php 2 H, c% H% z# B: |. C
$ip = $_SERVER['REMOTE_ADDR']; & W/ V$ N5 c1 c8 }5 s; h/ t. c
echo $ip; & {% R' g3 F/ R% c6 i9 R# Z9 V
?>
! x9 c% C& Z4 p, x, Z- {3 U& J3 e4 D1 h0 h5 N1 F9 x/ `; p3 B) x6 r* |
|
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行+ W `* a3 ]2 T0 `9 h
real_ip_header:从哪个header头检索出要的IP地址
2 Y$ W! t. t& f5 b8 F t: Jreal_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:+ K, E6 W4 `( N: n& P# r
120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.1217 a$ \2 i0 r( N/ O9 ?2 }
在real_ip_recursive on的情况下6 P% w7 ^) i" E- q1 |- I+ ~) y
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或者不设置的情况下" c! ?/ f9 a6 d
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; + X8 q8 c- L: _8 I
访问结果如下: 121.207.33.33 ) D" c: S5 I7 \4 a
/ K3 [5 Y' j! Y0 P- Y# W
四.三种在CDN环境下获取用户IP方法总结. B. `/ }- m F3 R/ f+ h; F, z
4.1 CDN自定义header头
0 b! z$ L! M* }; [- x( a$ h- z! S) h优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
! [: `0 v7 ]$ Z6 v4 v1 _5 S; Z2 k缺点:需要CDN厂商提供 Z6 j. ?% N+ R6 c
4.2 获取forwarded-for头
9 P1 Y' i! N3 `) K% I [优点:可以获取到用户的IP地址
3 K! z: Y9 n5 w缺点:程序需要改动,以及用户IP有可能是伪装的
9 L$ L8 Q9 _& J: Y# M
4.3 使用realip获取. o6 P# |# z( }/ @- `; w+ d2 V
优点:程序不需要改动,直接使用remote_addr即可获取IP地址! j2 ^; K4 d4 j* L
缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段 $ H7 S' c* m2 h' J
|