在使用Cloudflare的情况下,如何在后端Nginx中获取到真实的客户端IP地址呢?
Cloudflare作为代理服务,它的作用是让用户的请求通过Cloudflare的网络进行转发,
从而加速网站访问并提供一些安全防护措施,不会暴露后端真实服务器地址。
但这也导致了,后端的Nginx服务器看到的请求IP是Cloudflare的IP地址。
Cloudflare会把真实的客户端IP地址通过HTTP头部 CF-Connecting-IP 传递给后端真实服务,只需要在Nginx中提取该头部信息。
修改Nginx配置,获取Cloudflare转发的真实IP
在 /etc/nginx/conf.d/cloudflare.conf 文件中(记得在 nginx.conf 中引入该配置文件),加入以下内容:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 | set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
 | 
 
配置解释:
- set_real_ip_from:Cloudflare的IP,可以从Cloudflare官方文档找到最新的IP地址列表。
获取Cloudflare的IPv4地址列表:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 | $ curl https://www.cloudflare.com/ips-v4
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22
 | 
 
- real_ip_header:告诉Nginx,从哪个HTTP头部中获取真实IP地址。Cloudflare提供的是 CF-Connecting-IP 这个头部。
配置完成后,重启Nginx服务即可。
如果是ipv6,则需要修改 /etc/nginx/conf.d/cloudflare.conf 文件,加入以下内容:
| 1
2
3
4
5
6
7
8
 | set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IPv6;
 | 
 
获取Cloudflare的IPv4地址列表:
| 1
2
3
4
5
6
7
8
 | $ curl https://www.cloudflare.com/ips-v6
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32
 | 
 
Cloudflare提供的是 CF-Connecting-IPv6 这个头部。
当然也可以使用 X-Forwarded-For 头部。X-Forwarded-For 头部可以设置多个值,多个值之间用逗号隔开。
X-Forwarded-For 头部格式:X-Forwarded-For: client, proxy1, proxy2
client 为用户实际访问的 IP 地址。proxy1, proxy2 为访问经过的代理服务的 IP 地址。
有了nginx配置后,只需要用脚本定时获取IP地址,更新nginx配置文件即可。
脚本参考 网站配置了Cloudflare代理后,如何配置Nginx获取的真实客户端IP地址?
gin框架中获取用户真实IP
根据nginx的配置,则可以在后端真实业务服务中获取用户真实 IP 地址。
比如在gin框架中,可以通过 c.Request.Header.Get("X-Forwarded-For") 或 c.ClientIP() 获取用户真实 IP 地址。
并且在gin框架中,已经提供了 TrustedPlatform 配置项,可以设置默认代理平台,设置后,c.ClientIP() 会自动获取对应平台的用户真实 IP 地址。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 | // Trusted platforms
const (
	// PlatformGoogleAppEngine when running on Google App Engine. Trust X-Appengine-Remote-Addr
	// for determining the client's IP
	PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
	// PlatformCloudflare when using Cloudflare's CDN. Trust CF-Connecting-IP for determining
	// the client's IP
	PlatformCloudflare = "CF-Connecting-IP"
	// PlatformFlyIO when running on Fly.io. Trust Fly-Client-IP for determining the client's IP
	PlatformFlyIO = "Fly-Client-IP"
)
 | 
 
在启动gin engine 的时候,设置IP地址获取方式即可,比如设置为 PlatformCloudflare。
| 1
2
3
4
5
6
 |     var opt gin.OptionFunc = func(engine *gin.Engine) {
		engine.TrustedPlatform = gin.PlatformCloudflare
	}
	// Creates a gin router with default middleware:
	// logger and recovery (crash-free) middleware
	r := gin.Default(opt)
 | 
 
配置Nginx安全访问
在获取到真实的IP地址后,也可以进行一些安全配置了。比如禁止IP访问,禁止爬虫访问,禁止非法访问等等。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 | http {
    ## 使用map动态匹配IP地址
    map $http_cf_connecting_ip $blocked_ip {
        default 0;
        127.0.0.1 1;
    }
    server { 
        listen 80;
        server_name example.com;
        if ($blocked_ip) {
            return 403;
        }
        ## 禁止IP访问
        deny 192.168.1.1;
        ## 禁止IP段访问
        deny 192.168.1.0/24;
        ## 禁止爬虫访问
        deny ~* (?i)crawler|spider|bot;
        ## 禁止非法访问
        deny ~* (?i)php|cgi|pl|py|jsp|asp|js|css|ico|jpg|png|gif|swf|exe|mp3|mp4|rar|zip|tar|gz|7z|doc|docx|xls|xlsx|ppt|pptx|pdf|txt|xml|json|md|sql|log|htaccess|htpasswd|ftp|sftp|ssh|telnet|ftps|ssh|mysql|mariadb
        ## 禁止访问文件
        deny ~* (?i)file.php|file.html|file.txt|file.doc|file.docx|file.xls|file.xlsx|file.ppt|file.pptx|file.pdf|file.zip|file.rar|file.7z|file.exe|file.mp3|file.mp4|file.avi|file.flv|file.wmv|file.jpg|file.png|file.gif|file.swf|file.ico|file.css|
        ## 禁止访问目录
        deny ~* (?i)admin|config|logs|tmp|cache|backup|upload|download|files|media|static|public|node_modules|vendor|.git|.svn|.hg|.idea|.env|.env.example|.gitignore|.gitmodules|.gitattributes|.editorconfig|.travis.yml|.phpunit.xml|.env.testing|.env.local|.env.local.php|.env.testing.php|.env.php|.env
        ## 允许IP访问
        allow 192.168.1.1;
        
        location / { 
            ## 引入特定的IP黑名单文件
            include /etc/nginx/blocked_ips.conf;
            ##  允许其他所有 IP 访问
            allow all;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_pass http://127.0.0.1:8080;
        }
    }
}
 | 
 
黑名单配置文件blocked_ips.conf 示例:
| 1
2
 | deny 192.168.1.1;
deny 192.168.1.0/24;
 | 
 
参考