一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: 1 9 @" k/ f/ M1 k, C- V0 _
| proxy_set_header remote-user-ip $remote_addr;
/ @+ [6 N n& T9 H/ y
$ U. ?+ ~2 _7 m: q0 }; y- [- ? |
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,8 f* V4 G3 }9 P. }! A
怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1
0 t" s+ l5 @0 { @' T, e" ~2 ' v( \+ y( p7 [: c
3
* q8 {0 S3 U" i7 _, v1 {4 ; C B5 q1 u4 Q3 x
| <?php1 X4 D2 l: w4 j4 E" u7 N
$ip = getenv("HTTP_REMOTE_USER_IP");- K& @0 m5 L, n! j; q
echo $ip; . M9 n8 r) n# G
?>% N p u7 R! H' w
1 `- ~# V. |- {- V9 W
| : i2 [+ Y3 n/ W! q" i. U! t" N
访问getRemoteUserIP.php,结果如下:
9 f6 j; H3 ?4 Y% N$ Q6 U( Q 120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳 3 D4 p9 [0 N6 `9 m
4 e1 V6 n. ^! ?5 x二.通过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 - `# j- \6 I/ r Q, G" _
2 9 a3 h, u! @( l6 F# \( S0 S
3
& k7 o" Z: H- O. `1 z5 w. J' h4 ( o3 i$ e4 z, i) R
5
7 J: b3 s& g2 m# ?+ X9 S | getFor.php
" ]! d4 R; U5 E# k8 o/ ^) z$ R f<?php
8 v' Y. S7 ?0 m* U2 n! O $ip = getenv("HTTP_X_FORWARDED_FOR");
9 ^ m/ N: T4 D* ] echo $ip;
+ Y7 f1 ~2 R5 a' S( M7 P' f?>3 P% r, ^# V7 [8 K; a
% U2 z0 r4 j) a( z( | | 0 u$ o4 w ]. f0 x% \
访问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. ' s9 i! \. K6 P# k$ g" _
$ G( l$ R5 f- R1 a. [" K& F7 w 三.使用nginx自带模块realip获取用户IP地址
) h! T3 k% O: f ^安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module
7 x' N! t1 v9 f$ ?4 H; J" e 6 d0 h0 A! L s. h- F0 B
真实服务器nginx配置 1
9 k2 y# `1 F4 h+ t- c' v& O ^: P2 " i. {8 i7 p# Q& T: m: _) [
3 + X+ Y0 R: H6 Z' Z0 c# u/ g
4 5 Z% f- P2 l9 }6 P8 d( S- t
5 ' e& G' p: U' v3 Z- L* H
6 " @0 A) c& ~! D& Q; I
7 8 o. f' M( I1 s
8
8 Z m: J! u, g! K& q" Z4 c9
% ^4 B# [9 R* \0 U10 3 ]7 A! t, `! h9 }
11
2 }: b& p0 }1 ~! q& |12
1 g8 e. K/ M! R+ @13
& C9 G* ?. u2 R: p- ~# z14
# B* f* N2 X# M+ T5 c15 0 q; Z) `0 x& r* C w
16
, U$ [1 V4 J0 r0 z/ W9 W1 w( I+ [17
3 {7 N5 x9 N7 y18
) R, G1 z4 W- A( U19 3 k/ q; ~* V; B3 c( c
20 9 u5 J+ s0 E& R5 w' T7 R% e! j
21 : I8 }" h+ q2 ]$ h; H
22
: l+ H# }$ c) v6 D9 J& I5 i) ^) O' E23
% T+ e; f6 A8 n- @' o, p24
6 h5 C2 D V9 M6 R; a! Q. O25
( L6 F: S' X2 q; N* w26
" i8 a+ t2 c+ x27
. a3 k1 j0 q# p+ S28
5 d8 m+ C: O3 q9 S29 8 K0 w/ y g% ]8 E- i" X
30 7 W w: W( D/ {. X: m% Z' W* C
31
% m m% y8 ?% `6 { | server {
% ^% _ J6 w3 ?1 ~2 v listen 80;
1 N) @" j; p- ^# Y' r$ f" H2 x( X' s/ H server_name www.ttlsa.com; 9 C D; d8 v: B9 f* I `# N
access_log /data/logs/nginx/www.ttlsa.com.access.log main;
1 A2 c) R- O9 W$ q7 J* s, V 3 O4 m$ x6 x$ ]" c( `7 }# y* ?/ P
index index.php index.html index.html; 2 @+ s% e L' h
root /data/site/www.ttlsa.com; 3 J( N0 b& A( P# w
; F6 j4 F4 N6 {/ m: N r: [1 D location /
% D8 M, p0 |2 b0 x0 @* m. f0 f { $ N3 ~* U" H% ~. c8 [/ m
root /data/site/www.ttlsa.com; # S' O- }6 Q, V# k
}
6 p. p1 n9 g' A' O P' J location = /getRealip.php
: {% T, ~' K, u8 F {
, g( Q$ t( i8 U/ D& l4 Q; A set_real_ip_from 192.168.50.0/24; 2 A' G$ E+ _% c5 K. ~& M
set_real_ip_from 61.22.22.22;
* S+ @; o% T( C set_real_ip_from 121.207.33.33;
! }. {& N6 c1 e set_real_ip_from 127.0.0.1;
) b' i! {4 o4 D& `# c real_ip_header X-Forwarded-For;
' W0 W3 {; }. C2 ^. U real_ip_recursive on; 5 o; t% V4 L9 o r; z5 ]6 t
fastcgi_pass unix:/var/run/phpfpm.sock; ! `+ p, }! Z1 q
fastcgi_index index.php; 7 T: k3 W% X+ V$ a9 D9 A
include fastcgi.conf; ( I7 j; P7 d" d; i H- ^9 x% ~: g
} , ?0 v3 ~& b1 |) |
} ( w2 @ j \: l2 E
. T/ U3 I/ S& b) J2 R
getRealip.php内容
+ t% o' y1 |, {* L# G1 I. V <?php " H& b; [! X% G! ~- O
$ip = $_SERVER['REMOTE_ADDR'];
# i6 @4 K! ~% W: c# s% _( k echo $ip; 2 V* h8 H& V/ `5 b2 \7 G
?> ( C0 W1 r% S; @0 J$ U" |
& R1 n6 H* ~5 v+ R& X7 g# r |
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行+ }- [" H$ L+ ~6 @4 Y
real_ip_header:从哪个header头检索出要的IP地址. C* S" x# K# @$ `5 ~) _# e
real_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
+ X/ y( T% I1 P u3 {% w120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121
) G6 ]+ i( y, ~+ }7 ~# _在real_ip_recursive on的情况下
- O# a% M! c5 G1 u61.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或者不设置的情况下" ?$ N$ @% b: K! O
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;
2 \) h* z( x, _访问结果如下: 121.207.33.33 ( ?% L: N" [/ ^: R
' r# ~7 e0 C6 [6 h1 h
四.三种在CDN环境下获取用户IP方法总结
3 ]7 t b# w4 g: Q4.1 CDN自定义header头# G3 r2 A; Z c' u
优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
% ]& q5 o8 v# g, w7 R缺点:需要CDN厂商提供
% i! ^: s* S, v) Z9 M; ^6 s+ ^: ]
4.2 获取forwarded-for头4 m3 m2 V, {2 \4 c+ O$ y2 n
优点:可以获取到用户的IP地址/ t( @. t, w1 M. }% ]; y2 T5 X5 K
缺点:程序需要改动,以及用户IP有可能是伪装的 , z9 T U: g0 j) ^5 h8 l+ k8 z4 e, {8 \
4.3 使用realip获取
' q C! n" q; j# W% `8 l优点:程序不需要改动,直接使用remote_addr即可获取IP地址 A/ l$ {: X$ N1 J+ {1 q
缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段
+ B2 ^! t: g/ o+ [( j4 I |