nginx反向代理后,在应用中取得的ip都是反向代理服务器的ip,取得的域名也是反向代理配置的url的域名,解决该问题,需要在nginx反向代理配置中添加一些配置信息,目的将客户端的真实ip和域名传递到应用程序中。

nginx反向代理配置时,一般会添加下面的配置:

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;

其中第一行关于host的配置,是关于域名传递的配置,余下跟IP相关。

先看下C#代码的处理:

  1. #region 获取反向代理时的客户端的IP地址 getClientIP
  2. /// <summary>
  3. /// 获取反向代理时的客户端的IP地址
  4. /// </summary>
  5. /// <returns>返回客户端真实IP</returns>
  6. private string getClientIP()
  7. {
  8. HttpRequestBase request = HttpContext.Request;
  9.  
  10. string ip = request.Headers.Get("x-forwarded-for");
  11.  
  12. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  13. {
  14. ip = request.Headers.Get("Proxy-Client-IP");
  15. }
  16. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  17. {
  18. ip = request.Headers.Get("WL-Proxy-Client-IP");
  19.  
  20. }
  21. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  22. {
  23. ip = request.UserHostAddress;
  24. }
  25. return ip;
  26. }

但是需要注意的是,通过nginx反向代理后,如果访问IP通过了几层代理,可能取得的IP地址是这种格式:clientIP, proxy1, proxy2 .又可能需要进行插入数据库的话,防止数据库恶意注入。所以要针对上述IP地址的格式进行截取。

  1. #region 获取反向代理时的客户端的IP地址 getClientIP
  2. /// <summary>
  3. /// 获取反向代理时的客户端的IP地址
  4. /// </summary>
  5. /// <returns>返回客户端真实IP</returns>
  6. private string getClientIP()
  7. {
  8. HttpRequestBase request = HttpContext.Request;
  9.  
  10. string ip = request.Headers.Get("x-forwarded-for");
  11.  
  12. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  13. {
  14. ip = request.Headers.Get("Proxy-Client-IP");
  15. }
  16. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  17. {
  18. ip = request.Headers.Get("WL-Proxy-Client-IP");
  19.  
  20. }
  21. if (ip == null || ip.Length == || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
  22. {
  23. ip = request.UserHostAddress;
  24. }
  25. //可能存在如下格式:X-Forwarded-For: client, proxy1, proxy2
  26. int i = ;
  27. if(ip.Contains(", "))
  28. {
  29. //如果存在多个反向代理,获得的IP是一个用逗号分隔的IP集合,取第一个
  30. //X-Forwarded-For: client 第一个
  31. string[] ipaddrs = ip.Split(new string[] { ", " },StringSplitOptions.RemoveEmptyEntries);
  32.  
  33. for(i=;i<ipaddrs.Length;i++)
  34. {
  35. if(ipaddrs[i]!="")
  36. {
  37. if (false == IsInnerIP(ipaddrs[i]))//判断是否为内网IP
  38. {
  39. IPAddress realip;
  40. if (IPAddress.TryParse(ipaddrs[i], out realip) && ipaddrs[i].Split('.').Length == )
  41. {//合法IP
  42. return ipaddrs[i];
  43. }
  44. else
  45. {//非法IP
  46. //IP地址不符合规范
  47. }
  48. }
  49. }
  50. }
  51. ip = ipaddrs[];//默认取第一个ip地址
  52. }
  53.  
  54. return ip;
  55. }
  56. #endregion

之前发现,虽然说截取了上述IP地址的第一个clientip,但是发现有时候读出来的这个ip地址为内网IP。所以要加上内网IP的判断。

  1. #region 判断IP地址是否为局域网内网地址
  2. /// <summary>
  3. /// 判断IP地址是否为内网IP地址
  4. /// </summary>
  5. /// <param name="ipAddress">IP地址字符串</param>
  6. /// <returns></returns>
  7. private bool IsInnerIP(String ipAddress)
  8. {
  9. bool isInnerIp = false;
  10. ulong ipNum = ip2ulong(ipAddress);
  11. /**
  12. 私有IP:A类 10.0.0.0-10.255.255.255
  13. B类 172.16.0.0-172.31.255.255
  14. C类 192.168.0.0-192.168.255.255
  15. 当然,还有127这个网段是环回地址
  16. **/
  17. ulong aBegin = ip2ulong("10.0.0.0");
  18. ulong aEnd = ip2ulong("10.255.255.255");
  19. ulong bBegin = ip2ulong("172.16.0.0");
  20. ulong bEnd = ip2ulong("172.31.255.255");
  21. ulong cBegin = ip2ulong("192.168.0.0");
  22. ulong cEnd = ip2ulong("192.168.255.255");
  23. isInnerIp = IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd) || ipAddress.Equals("127.0.0.1");
  24. return isInnerIp;
  25. }
  26. /// <summary>
  27. /// 把IP地址转换为Long型数字
  28. /// </summary>
  29. /// <param name="ipAddress">IP地址字符串</param>
  30. /// <returns></returns>
  31. private ulong ip2ulong(string ipAddress)
  32. {
  33. byte[] bytes = IPAddress.Parse(ipAddress).GetAddressBytes();
  34. ulong ret = ;
  35.  
  36. foreach (byte b in bytes)
  37. {
  38. ret <<= ;
  39. ret |= b;
  40. }
  41. return ret;
  42. }
  43. /// <summary>
  44. /// 判断用户IP地址转换为Long型后是否在内网IP地址所在范围
  45. /// </summary>
  46. /// <param name="userIp"></param>
  47. /// <param name="begin"></param>
  48. /// <param name="end"></param>
  49. /// <returns></returns>
  50. private bool IsInner(ulong userIp, ulong begin, ulong end)
  51. {
  52. return (userIp >= begin) && (userIp <= end);
  53. }
  54. #endregion

后面又发现,nginx反向代理,得到的IP地址格式是unknown, 86.15.56.29。然后继续做处理。

  1. if (ip.Contains(", "))
  2. {
  3. //如果存在多个反向代理,获得的IP是一个用逗号分隔的IP集合,取第一个
  4. //X-Forwarded-For: client 第一个
  5. string[] ipaddrs = ip.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
  6. ip = ipaddrs[];//先默认取第一个IP地址
  7. foreach(string ipaddr in ipaddrs)
  8. {
  9. if (ipaddr != "" && ipaddr.Split('.').Length == && string.Equals("unknown",ipaddr,StringComparison.OrdinalIgnoreCase) == false)
  10. {//对应一些特殊的获取的特殊IP地址结构 unknown, 86.15.56.29
  11. if (false == IsInnerIP(ipaddr))
  12. {
  13. IPAddress realip;
  14. if (IPAddress.TryParse(ipaddr, out realip))
  15. {//合法IP
  16. ip = ipaddr;
  17. break;//只要找到一个非内网的IP地址,则跳出循环
  18. }
  19. else
  20. {//非法IP
  21. LogHelper.writeLog(LogHelper.IP_THREAD_LOG + "_" + mApp, string.Format("非法IP地址为:\n{0}",ipaddr));
  22. }
  23. }
  24. }
  25. }
  26. }

综合上述的得到IP地址,可以发现,其实并不能完全的到真实的IP地址。因为IP地址是可以伪造的。所以大家可以通过这种方式取得。但是一定要做一些特殊的判断及其处理,防止插入到数据库中,引起异常现象。

nginx反向代理取得IP地址的更多相关文章

  1. Nginx 反向代理,IP、端口,项目路径变化的问题

    这两天在云上部署公司项目,涉及到nginx反向代理,在部署完成测试,发现在下载文件的时候,无法下载,提示链接被拒绝. 假设nginx代理地址: http://121.53.21.188:9012/we ...

  2. Nginx反向代理实现IP访问分流

    通过Nginx做反向代理来实现分流,以减轻服务器的负载和压力是比较常见的一种服务器部署架构.本文将分享一个如何根据来路IP来进行分流的方法. 根据特定IP来实现分流 将IP地址的最后一段最后一位为0或 ...

  3. 通过Nginx反向代理实现IP分流

    通过Nginx做反向代理来实现分流,以减轻服务器的负载和压力是比较常见的一种服务器部署架构.本文将分享一个如何根据来路IP来进行分流的方法. 根据特定IP来实现分流 将IP地址的最后一段最后一位为0或 ...

  4. Nginx 反向代理 一个IP代理多个域名,不区分端口,类似windows虚拟机。

    简介: IP有限,所以我们以前使用端口来区分不同的虚拟主机,提供不同的WEB服务. 小范围还凑活,一旦规模扩大,地址记不住了吧?端口记不住了吧? 这个时候我们可以使用DNS,域名解析,毕竟记名字比记I ...

  5. Linux系统——Nginx反向代理与负载均衡

    集群集群是指一组(若干个)相互独立的计算机,利用高速通信网路组成的一个较大的计算机服务系统,每个集群节点(即集群中的每台计算机)都是运用各自服务的独立服务器.这些服务器之间可以彼此通信,协同向用户提供 ...

  6. Nginx反向代理 实现Web负载均衡

    实现负载均衡的方式有很多种,DNS.反向代理.LVS负载均衡器(软件实现).F5(负载均衡器,硬件,非常昂贵)这里我们只提到基于DNS,以及反向代理的方式来实现负载均衡Web服务       DNS服 ...

  7. nginx 反向代理实现负载均衡*配置实战

    重要点: 1配置反向代理多虚拟主机节点服务器 2经过反向代理后的节点服务器记录用户IP 3与反向代理配置相关的更多参数说明 4根据URL目录地址转发 (1)根据URL中的目录地址实现代理转发(动静分离 ...

  8. nginx反向代理+负载均衡+url重写+ssl认证

      Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄 ...

  9. nginx反向代理同一主机多个网站域名

    nginx反向代理同一ip多个域名,给header加上host就可以了 proxy_set_header   Host             $host; nginx.conf例子 upstream ...

随机推荐

  1. [Locked] Best Meeting Point

    Best Meeting Point A group of two or more people wants to meet and minimize the total travel distanc ...

  2. hdu 4705 dfs统计更新节点信息

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4705 #pragma comment(linker, "/STACK:16777216&qu ...

  3. lucene4.0与之前版本的一些改变

    最近在用lucene4.0,因为之前也没用过lucene其它版本,所以也不是很熟悉.但每次上网查资料代码的时候,总发现网友们贴的代码都是之前的版本的.当我拷贝过来的时候总会出问题,去查API的时候,总 ...

  4. Gridview实现银行选择列表

    [MainActivity.java] package com.example.activitydemo; import android.os.Bundle; import android.view. ...

  5. jquery自定义插件来实现分页的效果

    本节将介绍如何定义自己的jquery插入,实现分页效果,话不多说,.看看达到的效果: 分页插件 实现的代码例如以下: <!DOCTYPE HTML PUBLIC "-//W3C//DT ...

  6. vbird BASH学习

    http://vbird.dic.ksu.edu.tw/linux_basic/0320bash.php#alias

  7. [转] Nginx模块开发入门

    前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ...

  8. Android系统移植与驱动开发--第三章 Git使用入门及在学习中有感

    第三章 Git使用入门 使用Git的目的是减少各种版本的Linux的压缩大小,提供源代码在Linux上进行编译. 在这一个章节中,其实就是关键步骤的操作,虽然Git与我们学习的android没有很大的 ...

  9. Thinkphp 3.2及以上版本实现支付宝担保交易、即时到账接口类、函数和使用方法

    给客户开发网站时需要用到支付宝在线付款功能,小云到thinkphp网站溜了一圈,代码是有,可是都不怎么全,因此这篇文章诞生了! 本篇文章讲解了三个类的实现,担保交易.即时到账.双功能收款(该功能支付宝 ...

  10. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...