通过HttpServletRequest得到的IP统一: 127.0.0.1
因为使用了Nginx反射代理,修改Nginx的配置并重载Nginx即可
项目中使用request.getRemoteAddr();对来源IP进行了判断,相同IP地址半小时只能上传一次数据,我测试的时候本机访问次数没有这么多次,而且这个数据初次访问时间是项目正式部署上线的时间,是生产环境产生的日志,生产环境怎么会拿到本机地址呢?
经过一番研究
解决办法: 在nginx配置文件nginx.conf
proxy_set_header Host $http_host;//包含客户端真实的域名和端口号 proxy_set_header X-Real-IP $remote_addr;//表示客户端真实的IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;//这个Header和X-Real-IP类似,但它在多层代理时会包含真实客户端及中间每个代理服务器的IP。 proxy_set_header X-Forwarded-Proto $scheme;//表示客户端真实的协议(http还是https) # Nginx设置如下 location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
过程:
使用Github Search:
-
基于qqwry.dat查找ip归属地的java程序 miraclesu/IPLocator
使用17moncnIP专属查询库 ,年代久远,DAT文件已未更新。通过IP地址本地解析
使用纯真IP库,下载离线版EXE,安装后文件夹中存在 qqwry.dat 文件
直接调用(推荐,效率最高):
String ip = "202.108.22.5"; QQWryFile qqWryFile = QQWryFile.getInstance(); RandomAccessFile ipFile = qqWryFile.getIpFile(); QQWryRecord record = qqWryFile.find(ip, ipFile); System.out.println(Utils.ipToStr(record.getBeginIP())); System.out.println(Utils.ipToStr(record.getEndIP())); System.out.println(record.getCountry()); System.out.println(record.getArea());
想要直接调用成功,需要将项目中的类都导入到项目中
-
使用ip2region -> 需要生成 xdb。
ip2region 是什么?
官方:ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法
其实就是一个库,用于 IP地址解析定位用的,支持很多客户端,速度很快也不占内存,目前github已经到了10k star 了
特性:
准确率高,数据聚合多个供应商的数据
体积小,空间优化形成了仅仅几兆的 ip2region.db 文件
速度快,内置三种查询算法,支持毫秒级查询
支持多客户端,支持很多客户端,java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua、lua_c, nginx
它的数据聚合了一些知名ip到地名查询提供商的数据,例如:(如果一下开放API或者数据都不给开放数据时ip2region将停止数据的更新服务)
淘宝IP地址库, http://ip.taobao.com/
GeoIP, https://geoip.com/
纯真IP库, http://www.cz88.net/
mica,在 mvnrepository 中发现,相较于org.lionsoul 更快捷。 使用的版本为 2.6.3
net.dreamlu mica-ip2region 2.6.3 导入Maven后直接 @Autowired 或者 @Resource,调用查询
@Resource Ip2regionSearcher ip2regionSearcher; // 通过工具类得到请求的真实IP ip = getIpAddress(); // 根据ip地址获取到address IpInfo ipInfo = ip2regionSearcher.memorySearch(ip); if (null != ipInfo){ System.out.println(ipInfo.getAddress()); System.out.println(ipInfo.getIsp()); }
相关使用参考:
ip2region - 基础篇
ip2region - 使用篇
更新2022年08月03日 21:20:45
发现IP属地大部分都能成功获取,存在部分传递过来还是127.0.0.1,查看了 HttpServletRequest 获取的IP并没有问题,Nginx配置也没有问题。
那么这个获取到的内网IP的通过什么形式获取到的呢?百思不得其解
隔天一觉睡醒幡然醒悟,127.0.0.1 则等于 localhost ,也就是服务器本身直接发送甚至未经过Nginx代理转发。
情景复现,通过公网IP直接访问并执行操作,发现果然如此,解析获取到的是内网IP。
怀疑:公网IP泄漏,从行为上来看直接通过公网IP访问网站的几率很小。可以PASS
回头一想,Https和Http的默认端口分别是 443 、80。
而我Https安全证书SSL 443的端口在Nginx已经配置完成,而80端口,非安全访问没有进行配置。
很明显部分用户是通过Http协议访问的网站,80端口转发直接是内网IP。
在80端口下设置好Nginx.conf
proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
再次查看
已可以正确获取到对应的IP属地
自此引申出另外一个问题:禁止通过公网IP直接访问网站。
通过公网IP直接访问网站其实是需要禁止的,这样做是为了避免别人把未备案的域名解析到自己的服务器IP而导致服务器被断网
在使用的时候会遇到很多的恶意IP攻击,这个时候就要用到Nginx 禁止IP访问了。
Nginx禁止IP访问
Nginx禁止IP直接访问
止IP访问](https://developer.aliyun.com/article/548497?spm=a2c6h.12873639.article-detail.28.122af1ccGxZn81)
Nginx禁止IP直接访问
还没有评论,来说两句吧...