一.使用CDN自定义IP头来获取 假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下: | proxy_set_header remote-user-ip $remote_addr;' b3 t9 v. ?- a1 D; l2 A3 \
" M1 ?8 k( \0 I) f; M |
//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,
' e1 b9 Q: C, m2 L/ z! N1 x怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效> 后端PHP代码getRemoteUserIP.php 1
5 Q. M( E; H1 e( y. s( `2 2 }' Q2 n7 Y& p4 t
3 9 D3 @+ W' h' x
4
9 c& Y" O0 w. ?5 L; z# ] | <?php" I$ }2 B6 o9 n& I5 ^8 a
$ip = getenv("HTTP_REMOTE_USER_IP");& j! m2 k2 D" w$ p* H
echo $ip;
. F- I- [) L' }# @* P6 {' L?>
5 V! E+ Q3 s0 a) q O4 i2 D6 v
|
! F5 P. Q- B7 D! l, {& b: B访问getRemoteUserIP.php,结果如下:
7 F2 H- o# C4 s8 | 120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳
. @# L+ Z/ W; @! J) x7 T
# f6 v' N: t% f* v* q3 r7 ~, k二.通过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- z: M% A- w; L$ y# i
2
4 L. H7 j/ ~0 n8 K5 P3
; X* t( i4 o' X7 G4
& S: v G) t8 H3 v0 J5 4 P' M$ C: z$ Q( ?! L
| getFor.php
$ @6 V9 g, s$ s<?php# t2 A) l2 K q
$ip = getenv("HTTP_X_FORWARDED_FOR");8 f) P% U* Q) S
echo $ip;
* J1 k9 g, r5 c+ }" D?>3 ~) p7 n- W2 H3 c
4 t/ ~) k& Y& g$ U
|
, Q; M1 g5 d2 n: B" {8 D访问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.
7 r3 e8 g# ^% O$ k
% H) t0 ?. b" _) J/ c 三.使用nginx自带模块realip获取用户IP地址
$ _" {) C7 { G8 C安装nginx之时加上realip模块,我的参数如下: ./configure –prefix=/usr/local/nginx-1.4.1 –with-http_realip_module$ d5 r/ L* r+ U. O3 q* w* D# _3 {3 }. z
( _! Z! e# O' y7 R真实服务器nginx配置 1
5 W7 K: m5 S8 Z+ M& s9 p2 1 k, L* F8 d n$ ^
3
) O2 u1 l! _4 e2 _2 M4 : g' G# g! b0 R% w% S/ y/ ]5 ]
5 . Q7 M% H9 ]1 D9 S
6 # H7 H4 O' d# y- t2 a
7
# @3 w# P# o' N5 E+ f8 ' M& B& u- G0 z! K. w* I
9 / F. ?$ m& O1 B: c9 ]6 _$ R
10 / c0 @8 j8 @2 m1 Y t+ b
11 0 q/ k1 h& h ?* J2 F
12
* U/ Y: N" ?; [& `! [$ j13
" l6 E2 q6 g5 t: ]( |! l14
0 V9 m! l% s' W6 N1 C15
' l2 f, e; L4 K2 S q9 d16
- v4 K# Q$ Z- E17
0 E6 R6 b3 r$ ?; y' |; f+ ?' [' V18
0 C+ @9 V( ^) W- ^) r$ \* h$ X( V! j19 ) E( D# \# i; F" {
20
5 }9 Q& p# n3 A9 l- ]7 g* {21 % W; K& V8 O7 d0 G4 `+ O. R5 P
22 # L M8 A/ L1 {$ Q$ c/ _0 z
23
! }* I; ^% X1 e& [24 6 \3 u9 ~, J6 t
25 8 N# W Z: j; H0 y8 e
26
, J( k* X. a' w% T4 m& }9 S27 7 h9 c0 u$ N+ O/ @; V8 X0 t- k
28 3 w# v) {6 H* ~ }& O
29
4 R4 P9 G7 ^4 K5 y+ k0 r30
5 C* s$ D9 s& V6 H6 e5 R31 2 r! P% a9 D( ^) w9 x1 z
| server { + T& L4 w" ~( X, V6 u
listen 80;
4 Z' Z3 t2 t$ I server_name www.ttlsa.com;
( E- z1 q/ F' j; \; `4 X access_log /data/logs/nginx/www.ttlsa.com.access.log main; * \/ \- f5 H; s# K8 I
+ `: g9 s# D: k5 O1 y
index index.php index.html index.html;
- _4 s" _, R' {* u. C& h root /data/site/www.ttlsa.com;
) M1 G) b) b* R/ N$ \ 6 `+ J4 d: y* Q* i( H. h, S0 B
location / + X, g: N, z. H. L
{ + h) G# n. U% R, D, E2 z
root /data/site/www.ttlsa.com; ; @4 i& v* V4 H" i# ~
} 1 y2 E! w4 e' ^5 @5 o
location = /getRealip.php
7 t" W" a" V0 G. ?% w {
6 A2 c% M# V! W3 l- Y% p' \ set_real_ip_from 192.168.50.0/24; 9 o1 {, j, r, V- j
set_real_ip_from 61.22.22.22; # _! F8 [( c% H( C( p- }& d
set_real_ip_from 121.207.33.33;
% `, [" I& h7 z! H5 `- w set_real_ip_from 127.0.0.1;
% n1 I6 H; h4 V* N, @ real_ip_header X-Forwarded-For; ; j+ r6 J. a" r8 ^ u
real_ip_recursive on; ' y: P1 J# \2 `3 N" f$ t1 l
fastcgi_pass unix:/var/run/phpfpm.sock;
) ]) \+ Q" E+ |8 v p, j! x) s fastcgi_index index.php;
' O2 W( r+ O) j0 a include fastcgi.conf;
8 }- B+ {0 R W9 |& r( D2 ^! z } 8 ~' M9 N% |( n, A3 ?5 Y2 g7 b
}
0 R3 q) e9 j$ y; |) @) ~$ ^8 ~9 Q8 W v- Y5 a. |; `9 G
getRealip.php内容
- f9 A- \0 c" P' H) M' S+ u <?php | z0 J+ o- I9 Q) Q1 Q
$ip = $_SERVER['REMOTE_ADDR'];
, o- Y8 r* E; R, y6 i, i0 W echo $ip; , w7 p7 ~' R# o6 z3 V) m8 p! F
?> 5 h# z |% C. i h% v# T
* L1 {% d6 t u9 s) \9 H( ^
|
很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧. set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行+ J. M3 N, U1 d: D! R5 y4 L4 E
real_ip_header:从哪个header头检索出要的IP地址
% |1 K* u' b4 {) @1 R# Yreal_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:1 _4 N9 ]) v6 h
120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121
8 R" A" W0 B& b' f) {0 ? Y: v- z在real_ip_recursive on的情况下6 s7 w! @% P( J' ^: O0 \
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或者不设置的情况下
+ s3 ~9 q% Q) |- e$ Q3 z+ C192.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; ; p0 q2 n$ a9 @( A" p
访问结果如下: 121.207.33.33
" o' Y0 Q9 M& F6 |4 l6 _, r* e * `% k* [1 h+ d$ s2 e2 `
四.三种在CDN环境下获取用户IP方法总结
) O& |8 H9 D3 i9 T4.1 CDN自定义header头
4 N! |' v- n8 G" P优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
1 @& t- _( W, P缺点:需要CDN厂商提供 ; \1 p2 R1 ~3 p G, E
4.2 获取forwarded-for头
- X. B! f, c( a8 Z$ G优点:可以获取到用户的IP地址5 {; |. y1 K4 s& I4 Q* z
缺点:程序需要改动,以及用户IP有可能是伪装的
1 I/ B2 h5 D0 T! G; C7 k9 P
4.3 使用realip获取) z4 F# ~9 ^; {2 d
优点:程序不需要改动,直接使用remote_addr即可获取IP地址
! e" w+ S4 Q8 @缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段 ( U- A! P5 N6 \# g; E9 Q4 F0 t; H
|