在使用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;

参考