【问题标题】:Express.js: how to get remote client addressExpress.js:如何获取远程客户端地址
【发布时间】:2012-06-06 15:50:12
【问题描述】:

我不完全明白我应该如何获取远程用户 IP 地址。

假设我有一个简单的请求路由,例如:

app.get(/, function (req, res){
   var forwardedIpsStr = req.header('x-forwarded-for');
   var IP = '';

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});

上述方法是否正确获取真实用户 IP 地址还是有更好的方法? 那么代理呢?

【问题讨论】:

标签: node.js express ip ip-address


【解决方案1】:

如果您在 NGiNX 之类的代理或您拥有的代理后面运行,那么您应该检查'x-forwarded-for'

var ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress 

如果代理不是“你的”,我不会信任 'x-forwarded-for' 标头,因为它可能会被欺骗。

【讨论】:

  • 这是正确的,但是在我的情况下我不得不使用方括号(见上面的编辑)另外确保你在你的 nginx 配置中启用了 x-forwarded-for。像魅力一样工作!
  • 您需要记住,您必须将此指令 proxy_set_header X-Forwarded-For $remote_addr; 放入您的 nginx 配置中,以防您使用自己的反向代理。
  • copy-pasta 用户请注意:这可以返回一个逗号分隔的 IP 地址列表。我们有一个来自开发人员的错误,它复制了这个并将结果与​​ IP 进行比较。也许做类似var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim(); 的事情来获取客户端IP。
  • @Rishav ::1 是本地主机的 IPv6 地址
  • @DavyJones 的 sn-p 不适用于打字稿,因为任何未列出的 req.headers(包括“X-”标头)都输入了string|string[],并且不能使用split 方法。可以重写,应该用类型保护重写
【解决方案2】:

如果您可以使用 3rd-party 库。您可以查看request-ip

你可以通过

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});

源码比较长,这里就不复制了,大家可以去https://github.com/pbojinov/request-ip/blob/master/src/index.js查看

基本上,

它在请求中查找特定的标头并回退到一些 如果它们不存在,则为默认值。

用户ip由以下顺序决定:

  1. X-Client-IP
  2. X-Forwarded-For (Header 可能会返回多个 IP 地址,格式为:"client IP, proxy 1 IP, proxy 2 IP",所以我们取第一个 一)
  3. CF-Connecting-IP (Cloudflare)
  4. Fastly-Client-Ip(转发到云功能时的快速 CDN 和 Firebase 托管标头)
  5. True-Client-Ip(Akamai 和 Cloudflare)
  6. X-Real-IP(Nginx 代理/FastCGI)
  7. X-Cluster-Client-IP(Rackspace LB,Riverbed Stingray)
  8. X-ForwardedForwarded-ForForwarded(#2 的变体)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

如果找不到 IP 地址,它将返回null

披露:我与图书馆无关。

【讨论】:

  • 非常好@hongbo!值得一提的是,由于节点区分大小写,如果想跳过中间件解决方案,应该使用req.headers['x-client-ip']req.headers['x-forwarded-for'] 等。
【解决方案3】:

我为此编写了一个包。您可以将其用作快速中间件。我的包发布在这里:https://www.npmjs.com/package/express-ip

您可以使用

安装模块
npm i express-ip

用法

const express = require('express');
const app = express();
const expressip = require('express-ip');
app.use(expressip().getIpInfoMiddleware);

app.get('/', function (req, res) {
    console.log(req.ipInfo);
});

【讨论】:

【解决方案4】:

就我而言,类似于this 解决方案,我最终使用了以下x-forwarded-for 方法:

let ip = (req.headers['x-forwarded-for'] || '').split(',')[0];

x-forwarded-for 标头会不断添加从源站到最终目标服务器的 IP 路由,因此如果您需要检索源站客户端的 IP,这将是 第一项 的数组。

【讨论】:

    【解决方案5】:

    将所有 witk @kakopappa 解决方案加上 morgan 客户端 IP 地址的日志记录放在一起:

    morgan.token('client_ip', function getId(req) {
        return req.client_ip
    });
    const LOG_OUT = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :client_ip'
    self.app.use(morgan(LOG_OUT, {
        skip: function(req, res) { // custom logging: filter status codes
            return res.statusCode < self._options.logging.statusCode;
        }
    }));
    
    // could-flare, nginx and x-real-ip support
    var getIpInfoMiddleware = function(req, res, next) {
        var client_ip;
        if (req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
            var first = req.headers['cf-connecting-ip'].split(', ');
            client_ip = first[0];
        } else {
            client_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
        }
        req.client_ip = client_ip;
        next();
    };
    self.app.use(getIpInfoMiddleware);
    

    【讨论】:

      【解决方案6】:

      虽然来自@alessioalex 的答案有效,但Express - guide代理背后的表达部分所述还有另一种方法。

      1. app.set('trust proxy', true) 添加到您的快速初始化代码中。
      2. 当你想获取远程客户端的ip时,照常使用req.ipreq.ips(好像没有反向代理一样)

      选读:

      • 使用req.ipreq.ipsreq.connection.remoteAddress 不适用于此解决方案。
      • 如果您需要比信任 x-forwarded-for 标头中传递的所有内容更复杂的东西(例如,当您的代理未从不受信任的来源中删除预先存在的 x-forwarded-for 标头时),则可以使用更多 'trust proxy' 选项。有关详细信息,请参阅链接指南。
      • 如果您的代理服务器没有填充x-forwarded-for 标头,则有两种可能性。
        1. 代理服务器不中继请求最初所在位置的信息。在这种情况下,将无法找出请求的最初来源。您需要先修改代理服务器的配置。
          • 例如,如果您使用 nginx 作为反向代理,您可能需要将 proxy_set_header X-Forwarded-For $remote_addr; 添加到您的配置中。
        2. 代理服务器以专有方式(例如,自定义 http 标头)中继有关请求最初来自何处的信息。在这种情况下,这个答案是行不通的。可能有一种自定义方式可以获取该信息,但您需要先了解该机制。

      【讨论】:

      • 我的回答更笼统(与 Express 无关),但如果您使用 Express,那确实是更好的方法。
      • 您的代理服务器必须将标头“x-forwarded-for”设置为远程地址。以 nginx 为例,你的配置文件中应该有 proxy_set_header X-Forwarded-For $remote_addr
      • 在 IIS 后面使用 IISnode 作为代理,app.enable('trust proxy') 也可以使用 req.ip。除非我得到了端口1.2.3.4:56789。为了剥离它,我做var ip = req.ip.split(':')[0]
      • 我觉得这个答案缺乏安全性,需要更新。您应该始终定义您的应用程序信任哪些代理。接受的答案至少有一点关于欺骗的通知。也就是说,如果您使用的是 express,那么使用这样的库是一个更好的解决方案,但引用的代码不正确,并且在链接的资源中找不到。
      • 为什么给我::1
      【解决方案7】:

      具有 can-flare、nginx 和 x-real-ip 支持

      var user_ip;
      
          if(req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
            let first = req.headers['cf-connecting-ip'].split(', ');
            user_ip = first[0];
          } else {
            let user_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
          }
      

      【讨论】:

        【解决方案8】:

        这只是this answer 的附加信息。

        如果您使用的是nginx,您可以将proxy_set_header X-Real-IP $remote_addr; 添加到站点的位置块中。 /etc/nginx/sites-available/www.example.com 例如。这是一个示例服务器块。

        server {
            listen 80;
            listen [::]:80;
        
            server_name example.com www.example.com;
        
            location / {
                proxy_set_header  X-Real-IP  $remote_addr;
                proxy_pass http://127.0.1.1:3080;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
            }
        }
        

        重启nginx后,你就可以用req.headers['x-real-ip'] || req.connection.remoteAddress;访问你的node/express应用路由中的ip了

        【讨论】:

          【解决方案9】:

          我知道这个问题已经得到解答,但这是我的工作方式。

          let ip = req.connection.remoteAddress.split(`:`).pop();
          

          【讨论】:

            【解决方案10】:

            headers 对象有你需要的一切,只需这样做:

            var ip = req.headers['x-forwarded-for'].split(',')[0];
            

            【讨论】:

              【解决方案11】:

              var ip = req.connection.remoteAddress;

              ip = ip.split(':')[3];

              【讨论】:

              • 输出是这样的:- ::ffff:XXX.XX.XX.XX 从中我们会得到ip
              • 我认为ip = ip.split(':').pop(); 在这种情况下会是击球手,如果正常的 ip 即 127.0.0.1 会来它仍然可以给你 ip。
              【解决方案12】:
              1. 添加app.set('trust proxy', true)
              2. 照常使用req.ipreq.ips

              【讨论】:

              • 这是要走的路。详情请见expressjs.com/en/guide/behind-proxies.html
              • 如此简单明了。喜欢简单的答案。
              • 只是分享express-rate-limit node package 的文档中也提到了这种方法,通过设置app.set('trust proxy', true); 和引用req.ip,我能够为我的网站获得所有期望和预期的行为它使用 cloudflare 作为代理。
              【解决方案13】:

              这对我来说比其他人更有效。我的网站在 CloudFlare 后面,它似乎需要cf-connecting-ip

              req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
              

              没有测试Express behind proxies,因为它没有说明这个cf-connecting-ip 标头。

              【讨论】:

                【解决方案14】:

                根据Express behind proxiesreq.ip已经考虑了反向代理,如果你已经正确配置了trust proxy。所以比req.connection.remoteAddress从网络层获取,不知道代理要好。

                【讨论】:

                  【解决方案15】:

                  nginx.conf 文件中:
                  proxy_set_header X-Real-IP $remote_addr;

                  node.js 服务器文件中:
                  var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

                  注意表示小写标题

                  【讨论】:

                  • 欢迎来到 Stack Overflow!而不是只发布一段代码,请解释为什么这段代码解决了所提出的问题。没有解释,这不是答案。
                  • @ququzone 的回答还可以。解释是在名为“x-real-ip”的请求上设置了一个自定义标头,该标头从访问者那里获取原始 IP 地址。它适用于我的 node 和 socket.io。
                  • 对我来说,IP 地址在req.headers['x-real-ip'] 下可用,即使在nginx.conf 标头设置为大写字母。
                  • 这就是为我解决的问题。即使将 trust-proxy 设置为 true,它仍然使用本地 127.0.0.1 地址
                  【解决方案16】:

                  特别是对于节点,http 服务器组件的文档,在event connection 下说:

                  [触发] 当建立新的 TCP 流时。 [The] socket 是一个类型的对象 网络套接字。通常用户不想访问此事件。在 特别是,套接字不会发出可读事件,因为 协议解析器附加到套接字。插座也可以 通过 request.connection 访问。

                  所以,这意味着 request.connection 是一个套接字,根据文档确实有一个 socket.remoteAddress 属性,根据文档是:

                  远程 IP 地址的字符串表示形式。例如, '74.125.127.100' 或 '2001:4860:a005::68'。

                  在express下,request对象也是Node http请求对象的一个​​实例,所以这种方式应该还是可以的。

                  但是,在 Express.js 下,请求已经有两个属性:req.ipreq.ips

                  req.ip

                  返回远程地址,或者启用“信任代理”时 - 上游地址。

                  req.ips

                  "trust proxy"true时,解析“X-Forwarded-For”ip地址列表并返回一个数组,否则为空数组 回来。例如,如果值为“client, proxy1, proxy2”,您 将接收数组 ["client", "proxy1", "proxy2"] 其中 "proxy2" 是最远的下游。

                  值得一提的是,根据我的理解,Express req.ip 是比req.connection.remoteAddress 更好的方法,因为req.ip 包含实际的客户端 ip(前提是在 express 中启用了可信代理),而另一个可能包含代理的 IP 地址(如果有的话)。

                  这就是当前接受的答案建议的原因:

                  var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

                  req.headers['x-forwarded-for'] 将等同于 express req.ip

                  【讨论】:

                  • req.connection 现在被标记为已弃用
                  猜你喜欢
                  • 2018-04-30
                  • 2011-06-08
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-05-10
                  • 1970-01-01
                  相关资源
                  最近更新 更多