先上代码

var http = require('http')
var server = http.createServer(function (req,res) {
console.log(req.headers['x-forwarded-for'] ); // 判断是否有反向代理
console.log(req.socket.remoteAddress ); // 判断后端的 socket 的 IP
let ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress
res.end(ip)
})
server.listen('9098')

x-forwarded-for是什么?

X-Forwarded-For 是一个扩展header头,用来表示 HTTP 请求端真实 IP,在HTTP/1.1(RFC 2616)协议中没有定义,但是现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

由人为设置

一些代理服务器会设置一些消息头,比如nginx会在转发请求的时候可以带上这个消息头,向应用服务传递客户端的真实IP;

使用下面的配置在nginx设置反向代理转发的X-Forwarded-For:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; // 常用
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $remote_addr" // 不常用,$http_x_forwarded_for是读取到的消息头,如果请求头没有x-Forwarded-for,这个值就是空的。

这样就能在应用服务器拿到消息头 X-Forwarded-For;

可以伪造

因为是人为设置,伪造一个假的很简单,如下:

proxy_set_header X-Forwarded-For "121.12.12.12";

所以接收到的不可信任的服务器传递回来的header,或者客户端伪造了header,其中x-forwarded-for是不能当做客户端IP的。

格式

X-Forwarded-For请求头格式非常简单,就这样:X-Forwarded-For:client, proxy1, proxy2,由[英文逗号+空格]隔开的多个部分组成,最开始的是离服务端最远的设备IP,然后是每一级代理的IP。

如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,代理服务器会把前一个网络设备的IP地址追加到X-Forwarded-For 上面,经过层层追加,服务端最终会收到以下信息:

X-Forwarded-For: IP0, IP1, IP2

同时注意到IP3是不会追加上到这个列表上的。

实际验证:在本地电脑开启一个nodejs服务,端口为9090;开启nginx反向代理,端口为8062;

  • 通过8062访问nginx服务的时候,req.headers['x-forwarded-for']值为
192.168.1.105 //nginx通过X-Forwarded-For将客户端的地址转发了过来
  • 通过9090直接访问nodejs访问,req.headers['x-forwarded-for']值为
undefined //直接请求的时候,没有设置消息头,自然为undefined

所以:

  1. 有没有X-Forwarded-For和代理服务器的设置有关;
  2. 正确与否也和代理服务器有关;

remoteAddress

如果没有X-Forwarded-For,应用服务器可以通过与服务端建立 TCP 连接获取到。在nodejs中可以通过req.socket.remoteAddress获取到IP3;

remoteAddress有没有可能是假的呢?因为tcp链接需要三次握手,所以无法伪造这个ip。

X-Real-IP是什么

是一个自定义的消息头,目前并不属于任何标准,完全由用户控制。

结论;

没有代理:直接使用remoteAddress获取客户端IP,因为header中x-forwarded-for不可靠,可能有也可能没有,甚至可能是伪造的;

有代理的情况下,获取到的remoteAddress是代理服务器的IP,如果代理服务器是可信赖的,那么能通过x-forwarded-for来获取客户端IP。

在express,koa中都有获取ip的方法,他们是怎么封装的呢?

koa中是如何封装获取客户端IP的?

express中是如何处理IP的?

如有错误之处,望请斧正。

实践使用nodejs获取用户真实IP?的更多相关文章

  1. PHP获取用户真实 IP , 淘宝IP接口获得ip地理位置(转)

    <?php /** * 获取用户真实 IP */ function getIP() { static $realip; if (isset($_SERVER)){ if (isset($_SER ...

  2. java 获取用户真实ip

    /** * 获取用户真实ip * @param request * @return */ public static String getIpAddr(HttpServletRequest reque ...

  3. 多层代理获取用户真实IP

    1. 几个概念remote_addr:如果中间没有代理,这个就是客户端的真实IP,如果有代理,这就是上层代理的IP.X-Forwarded-For:一个HTTP扩展头,格式为 X-Forwarded- ...

  4. Java中使用HttpRequest获取用户真实IP地址端口

    import javax.servlet.http.HttpServletRequest; /** * 自定义访问对象工具类 * * 获取对象的IP地址等信息 * @author X-rapido * ...

  5. 在有nginx做反向代理时候,如何获取用户真实Ip信息

    在获取用户的Ip地址时,不一定可以获取到用户真实的地址信息,这要看代理服务器的类型,代理服务器有普通匿名代理服务器,高匿代理服务器,像这种情况很难获取到用户真实的Ip地址 假如用户没有使用匿名代理服务 ...

  6. 获取用户真实IP:(模拟:客户端--F5--nginx--tomcat 后端获取用户真实IP)

    模拟:客户端--F5--nginx--tomcat 后端获取用户真实IP 192.168.109.137 :nginx01(充当第一层代理==F5)192.168.109.138 :nginx02(二 ...

  7. 如何根据HttpServletRequets获取用户真实IP地址

    最近的一个项目的某个功能获取用户的ip地址,添加用户的系统使用记录. 我发现当我直接使用getRemoteAddr()方法从HttpServletRequet中获取用户的ip时,获取到的是服务器的ip ...

  8. nginx反向代理获取用户真实ip

    nginx做反向代理时,默认的配置后端获取到的ip都是来自于nginx,如何转发用户的真实ip到后端程序呢?如是是java后端,用request.getRemoteAddr();获取到的是nginx的 ...

  9. CDN下nginx获取用户真实IP地址

    随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:nginx如何获取用户 ...

随机推荐

  1. webpack介绍—上

    6.1 webpack概念的引入 在网页中会引用哪些常见的静态资源? JS .js. .jsx ..coffee. .ts(TypeScript 类 C# 语言) CSS .css. .less. . ...

  2. selenium(2)-selenium针对浏览器的操作有哪些

    对浏览器有哪些操作 最大化.最小化浏览器 控制.获取浏览器大小 获取当前标签页title.url 前进.后退.刷新 执行js语句 打开.关闭,切换新标签页 滚动页面 上传附件 鼠标悬停 对话框的定位方 ...

  3. c语言"##"的使用

    #include<stdio.h> #define Operations(x) operation_ ## x // ## 是黏贴字符串 int Operations(sum)(int x ...

  4. 如何用Tesseract做日文OCR(c#实现)

    首先做一下背景介绍,Tesseract是一个开源的OCR组件,主要针对的是打印体的文字识别,对手写的文字识别能力较差,支持多国语言(中文.英文.日文.韩文等).是开源世界里最强的一款OCR组件.当然和 ...

  5. python脚本中调用其他脚本

    如果只关注脚本中调用他脚本直接看代码30行 PS:该脚本功能有:自动清理目录,创建目录,自动运行脚本,以此提升工作效率 import numpy as np import os from shutil ...

  6. .net core docker容器编排部署(linux)

    环境准备 需要一个linux操作系统:我这里用的是ubuntu 18.04,安装步骤就不说了,网上很多教程,当然也可以私信我. 既然需要用到docker,那么就安装个docker,apt instal ...

  7. CentOS 7安装Oracle 12c图文详解

    环境: CentOS7@VMware12,分配资源:CPU:2颗,内存:4GB,硬盘空间:30GB Oracle 12C企业版64位 下载地址:http://www.oracle.com/techne ...

  8. SharePoint删除图片库文件

    SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite(SPContext.Current. ...

  9. 使用SpringBoot构建REST服务-什么是REST服务

    前言: 本文按照Spring官网构建REST服务的步骤测试,可以得到结论: 到底什么样的风格才是RESTful风格呢? 1,约束请求命令如下: GET,获取资源.例如:/employees表示获取列表 ...

  10. SpringBoot-多数据源配置-Mysql-SqlServer-Oracle

    Maven依赖 <!-- mysql的jdbc依赖 --> <dependency> <groupId>mysql</groupId> <arti ...