问题描述
我们gateway由于用到了nginx做https反向代理,但nginx反向代理后remote_addr会变成127.0.0.1,这样gateway的ip拦截机制就失效了
概念讲解:
REMOTE_ADDR
是远端IP,默认来自tcp连接客户端的Ip。可以说,它最准确,确定是,只会得到直接连服务器客户端IP。如果对方通过代理服务器上网,就发现。获取到的是代理服务器IP了
HTTP_X_FORWARDED_FOR,HTTP_CLIENT_IP
为了能在大型网络中,获取到最原始用户IP,或者代理IP地址。对HTTp协议进行扩展。定义了实体头。
HTTP_X_FORWARDED_FOR = clientip,proxy1,proxy2其中的值通过一个 逗号+空格 把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务
器每成功收到一个请求,就把请求来源IP地址添加到右边。
HTTP_CLIENT_IP 在高级匿名代理中,这个代表了代理服务器IP。
其实这些变量,来自http请求的:X-Forwarded-For字段,以及client-ip字段。 正常代理服务器,当然会按rfc规范来传入这些值。
但是,攻击者也可以直接构造该x-forword-for值来“伪造源IP”,并且可以传入任意格式IP.
这样结果会带来2大问题,其一,如果你设置某个页面,做IP限制。 对方可以容易修改IP不断请求该页面。 其二,这类数据你如果直接使用,将带来SQL注册,跨站攻击等漏洞
规避方法
获取IP的方法
gin 框架(包括目前业内所有的web框架),获取请求者IP有两种方式
- client_ip()
这种方式获取的是请求头中:X-Forwarded-For字段,以及client-ip字段,容易被伪造 - request.remote_addr
这种方式为最真实的,但如果经过反向代理后,会显示为127.0.0.1
解决
我们可以在nginx上将remote_addr写入到X-Forwarded-For请求头,然后nginx请求后端资源会携带该请求头,后端直接获取client_ip即可,这样即使客户端伪造了一条X-Forwarded-For的数据,也会在nginx这一层被覆盖为真实地址,不过要注意的是,不仅是X-Forwarded-For,X-Real-IP头也要设置
因为client_ip()方法会获取这两个请求头的数据,以go语言的gin框架为例:
这样,我们即获取到了真实IP又规避了被伪造源IP攻击的风险
配置
location / {
proxy_pass http://gateway;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
}