.net core 3.x 部署到CentOS7 上以后,无法获取到真实的客户端IP地址

java__net 2020-11-27 01:52:08
我将发布好的程序部署到服务器上以后,在某些特殊的方法上设置了拦截器,但是IP白名单的操作发现总被拦截,最后根据打印日志输出发现,我所有的客户端访问,拦截器打印出来的地址都是服务器所在的网关地址,请问如何让通过 dotnet app.dll --urls=http://*:88 启动的程序,可以获得真实的客户端ip地址呢?
...全文
8925 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
wenoxy 2020-12-01
  • 打赏
  • 举报
回复
过滤MAC地址不香么
X-i-n 2020-12-01
  • 打赏
  • 举报
回复
我知道你怎么发布的网站。前面我一直在强调,你的代码没有问题,发布方式也没有问题,需要先排查设备,还有你的网络结构。 按你现在的代码+部署方式,即使不在同一个网段,甚至不在同一个局域网,都不会有任何问题(实际的生产环境可能会再套一层web hosting,加个证书之类的,一般是用反向代理,同时代码相应改成取X-Forward-For或者X-RealIP;如果要引申出来讲的话,这个地方也可以作为一种控制手段,通过这三个IP可以区分出请求有没有走反向代理,比如为定时任务写一个只允许本机访问的接口,假定叫/Api/Task1,然后通过crontab执行curl http://localhost:88/Api/Task1来触发,接口获取不到请求的代理IP时,表明请求来自本机,身份合法,允许运行,如果获取到了代理IP,说明是从外部访问,请求非法,不予执行,这是一种成本极低,安全性极高的定时任务运行方式)。 另外,你也可以新建一个默认web项目,Program.cs的CreateHostBuilder方法下,修改ConfigureWebHostDefaults的配置,为webBuilder添加.UseUrls("http://0.0.0.0:88"),然后调试配置文件从iisexpress切到成dotnet,直接F5就行。 分别从本机访问,从同一网段访问,从局域网其它网段访问,从互联网外部访问的时候,断点到return View()上,查看HttpContext.Connection.RemoteIpAddress的值,前三个应该是一样的结果,最后一个应该是客户端的公网IP。 写了半天,发现还是上个图最有说服力,测试都帮你做好了。

#/Home/Index
public IActionResult Index() => Content(HttpContext.Connection.RemoteIpAddress.ToString());
java__net 2020-12-01
  • 打赏
  • 举报
回复
引用 10 楼 X-i-n 的回复:
先说白名单,无论是场景也好,使用方法也好,你的思路没有任何问题。离开真正的需求场景直接说用法不对,非常无脑。 1. 客户端公网IP:context.HttpContext.Connection.RemoteIpAddress,正常情况这个没有问题,它可以直接获取到客户公网IP,你的路由器是什么设备?怎么发布的网站?如果是负载均衡类的或者具有反向代理功能的设备,才会出现这个问题。 2. X-Forwarded-For:使用反向代理的时候,每一层代理都会将自己的IP追加到这个变量里,所以你的网站会拿到所有的代理IP 3. X-Real-IP:使用反向代理的时候,每一层代理会覆盖到这个变量里,所以你的网站会拿到最后一层的代理服务器IP。 首先,使用了反向代理时,1会获取到最后一台反向代理的IP(所以我怀疑你的网关设备有类似的功能); 其次,使用反向代理,并且反向代理服务器会主动更新相应header的时候,2和3才能够取到值,这两个条件缺一不可,否则获取到的就是空(也就是你说的另外两个没输出,httpHeader里也找不到)。
你说的没有错,2和3没有值是因为我没有用任何反向代理。 路由是什么设备,这个我得问一下运维的同事,环境的事情不是我在负责。 至于怎么发布的网站,上面我多次提到过了,可能你没仔细看,因为只是一个测试,所以我直接用的最简单的方式 dotnet app.dll --urls=http://*:88
java__net 2020-11-30
  • 打赏
  • 举报
回复
也许是我表述的不够好,可能给大家造成很多误解。 首先说业务场景,这里涉及IP地址的地方有2个 1 记录访问网站用户的IP地址,所谓真实ip,其实也就是用户的公网IP,如果用户都在一个边界里,那么他们的公网IP是一样的,这个并不是问题。 2 根据IP白名单过滤不符合要求的ip。 其次说实现,先上代码


 public override void OnActionExecuting(ActionExecutingContext context)
        {
           
            //if ( !IPAddress.IsLoopback(context.HttpContext.Connection.RemoteIpAddress))
            //{
                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
                Console.WriteLine("remoteIp:"+remoteIp);
                var tmpForwardedIp = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
                Console.WriteLine("tmpForwardedIp:"+ tmpForwardedIp);
                var tmpRealIp = context.HttpContext.Request.Headers["X-Real-IP"].FirstOrDefault(); 
                Console.WriteLine("tmpRealIp:"+tmpRealIp);
                var bytes = remoteIp.GetAddressBytes();
                var badIp = true;
                if (!string.IsNullOrEmpty(_whitelist))
                {
                    string[] ip = _whitelist.Split(',');
                    foreach (var address in ip)
                    {
                        var testIp = IPAddress.Parse(address);
                        if (testIp.GetAddressBytes().SequenceEqual(bytes))
                        {
                            badIp = false;
                            break;
                        }
                    }
                }

                if (badIp)
                {
                    context.Result = new StatusCodeResult(401);
                    return;
                }
            //}

            base.OnActionExecuting(context);
        }
我的服务器是CentOS7,当然这个关系不大,然后因为是临时测试用,所以没有装Nginx,直接用的 dotnet app.dll --urls=http://*:88 我在另外一台机器上通过IP:88来访问这个站点。 注意我在代码中,输出了3个不同的获取客户端IP地址的方式。只有第一个有输出,但是输出的是我这台服务器所在内网的网关地址,另外两个没有输出,是空值。 1 这里并没有获取到我本机ip,这个肯定是不对的,所以我不明白的是 dotnet app.dll --urls=http://*:88 到底做了什么,它的映射原理是什么。 2 另外两个没有输出,是当前上下文中根本就没有这2个属性的数据在httpHeader里。 最后,我的问题关键就是,这里为什么无法获取到我本机的ip,而是取到服务器的网关ip,这块让我非常不解。 还请各位大神踊跃发言~ 谢谢
X-i-n 2020-11-30
  • 打赏
  • 举报
回复
正确获取客户端IP的流程是: 1. 获取X-Forwarded-For,如果有,取最后一条; 2. 获取X-Real-IP; 3. 1或2只要有一个不为空,即表示获取成功,可以拿来作为remoteIP;1和2均为空时,获取context.HttpContext.Connection.RemoteIpAddress作为remoteIP
X-i-n 2020-11-30
  • 打赏
  • 举报
回复
先说白名单,无论是场景也好,使用方法也好,你的思路没有任何问题。离开真正的需求场景直接说用法不对,非常无脑。 1. 客户端公网IP:context.HttpContext.Connection.RemoteIpAddress,正常情况这个没有问题,它可以直接获取到客户公网IP,你的路由器是什么设备?怎么发布的网站?如果是负载均衡类的或者具有反向代理功能的设备,才会出现这个问题。 2. X-Forwarded-For:使用反向代理的时候,每一层代理都会将自己的IP追加到这个变量里,所以你的网站会拿到所有的代理IP 3. X-Real-IP:使用反向代理的时候,每一层代理会覆盖到这个变量里,所以你的网站会拿到最后一层的代理服务器IP。 首先,使用了反向代理时,1会获取到最后一台反向代理的IP(所以我怀疑你的网关设备有类似的功能); 其次,使用反向代理,并且反向代理服务器会主动更新相应header的时候,2和3才能够取到值,这两个条件缺一不可,否则获取到的就是空(也就是你说的另外两个没输出,httpHeader里也找不到)。
java__net 2020-11-30
  • 打赏
  • 举报
回复
大哥,我这是测试,而且这个也不是我问题的核心啊
ziqi0716 2020-11-30
  • 打赏
  • 举报
回复
ip白名单仅可用于局域网内服务间调用之类的,你用法错了.
qq_30335331 2020-11-29
  • 打赏
  • 举报
回复
3楼说的没有毛病 2楼嘛 呵呵 和我推测的一样 服务器做了反向代理
  • 打赏
  • 举报
回复
谈何“真实地址”?TCP/IP网络就是这样的,你从网络内部看到“外部信息”自然就是路由器的IP和(随机)端口号。可能你只在局域网里边测试,然后想当然地以为有所谓“真实的客户端ip地址”。这个只能理解为做得太少。你能获得我现在的IP吗?开玩笑吧,我的 IP 是 192.168.1.102,全世界同时有几十亿个 192.168.1.102,你要获取哪一个?TCP/IP是一个路由器协议组成的网络,不是什么“局域网”啊!不要拿一个小办公室里边的某段局域网的概念套用到网络软件设计上!
X-i-n 2020-11-28
  • 打赏
  • 举报
回复
引用 4 楼 以专业开发人员为伍 的回复:
网关公网地址
客户端不管在哪,除非和服务器在一个局域网里,否则一定会有两个网关:客户端的,服务器的。当然复杂一点的话(其实这个更为常见,一个局域网只有一个网段的情况反而是少数),设备的网关并非本局域网的最外侧。如果抠字眼,服务器网关地址、客户端网关地址,都位于内侧,只是个内网地址,意义不大。 首先,IP白名单是什么?用在什么场景?事实上,客户端ip地址不仅可以获取到,而且非常重要。
  • 打赏
  • 举报
回复
网关公网地址
  • 打赏
  • 举报
回复
引用 2 楼 X-i-n 的回复:
[quote=引用 1 楼 以专业开发人员为伍 的回复:]谈何“真实地址”?TCP/IP网络就是这样的,你从网络内部看到“外部信息”自然就是路由器的IP和(随机)端口号。可能你只在局域网里边测试,然后想当然地以为有所谓“真实的客户端ip地址”。这个只能理解为做得太少。你能获得我现在的IP吗?开玩笑吧,我的 IP 是 192.168.1.102,全世界同时有几十亿个 192.168.1.102,你要获取哪一个?TCP/IP是一个路由器协议组成的网络,不是什么“局域网”啊!不要拿一个小办公室里边的某段局域网的概念套用到网络软件设计上!

看得出来,网络这块你虽然比一窍不通略强一丁点,不过没有一句话说到点子上。而且还有不爱仔细看别人说的是什么,直接开启滔滔不绝模式的习惯。



引用 楼主 java__net 的回复:
我将发布好的程序部署到服务器上以后,在某些特殊的方法上设置了拦截器,但是IP白名单的操作发现总被拦截,最后根据打印日志输出发现,我所有的客户端访问,拦截器打印出来的地址都是服务器所在的网关地址,请问如何让通过 dotnet app.dll --urls=http://*:88 启动的程序,可以获得真实的客户端ip地址呢?

正常情况,你会获取到客户端的网关公网IP。不清楚你是怎么获取客户端IP的,最好能把相关获取IP的代码放上来。另外,如果有反向代理,和没有反向代理,这两种场景的处理也完全不一样。[/quote]

你抄一句“网管公网地址”改个名词儿就能证明不是人家服务器网关地址了?还是说你更加“爱仔细看”——真正理解了—— lz 所说的“客户端地址”是什么意思了?

实际上我之前从来不回复这类无聊的话,因为其实每一个人都有能力认真琢磨每一段语言背后说到了什么技术原理,本人听的懂的自然懂,而外人听不懂的往往就说明我回答对了。论坛不是让无聊的人剽窃东西的地方,而是能提出问题的“本人”学习的地方。
X-i-n 2020-11-28
  • 打赏
  • 举报
回复
引用 1 楼 以专业开发人员为伍 的回复:
谈何“真实地址”?TCP/IP网络就是这样的,你从网络内部看到“外部信息”自然就是路由器的IP和(随机)端口号。可能你只在局域网里边测试,然后想当然地以为有所谓“真实的客户端ip地址”。这个只能理解为做得太少。你能获得我现在的IP吗?开玩笑吧,我的 IP 是 192.168.1.102,全世界同时有几十亿个 192.168.1.102,你要获取哪一个?TCP/IP是一个路由器协议组成的网络,不是什么“局域网”啊!不要拿一个小办公室里边的某段局域网的概念套用到网络软件设计上!
看得出来,网络这块你虽然比一窍不通略强一丁点,不过没有一句话说到点子上。而且还有不爱仔细看别人说的是什么,直接开启滔滔不绝模式的习惯。
引用 楼主 java__net 的回复:
我将发布好的程序部署到服务器上以后,在某些特殊的方法上设置了拦截器,但是IP白名单的操作发现总被拦截,最后根据打印日志输出发现,我所有的客户端访问,拦截器打印出来的地址都是服务器所在的网关地址,请问如何让通过 dotnet app.dll --urls=http://*:88 启动的程序,可以获得真实的客户端ip地址呢?
正常情况,你会获取到客户端的网关公网IP。不清楚你是怎么获取客户端IP的,最好能把相关获取IP的代码放上来。另外,如果有反向代理,和没有反向代理,这两种场景的处理也完全不一样。

110,502

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧