byte-fe / intern-study

实习生互助学习
MIT License
33 stars 6 forks source link

[第三期] determine the user ip from the request #23

Open panjizhi opened 6 years ago

panjizhi commented 6 years ago

需求描述

这里定义为获取终端 "用户" ip, 考虑到实际场景需要 bypass proxy / LB

基本要求

单元测试的编写参考:@fe/byted-consul

思路

  1. 直连或透明代理由 TCP 协议获取

  2. proxy / LB 从 http 协议(header)获取

  3. 一些标准化的云服务 / LB 服务, 从 header 中标准定义获取

策略梳理

  1. 优先 header 关键字判定, 命中则为 proxy / LB

    1. 检查最标准无歧义的 header: X-Client-IP

      一般国外云服务商(Amazon / Heroku)遵循的业界标准

    2. 检查记录代理信息的 header: x-forwarded-forx-real-ip

      都为约定速成的 header, x-forwarded-for 目前应用最广泛, x-real-ip 是早期 fastcgi 等默认的 header

      node 服务最常见的 proxy 和 LB 默认配置, 属性值为 [client_IP, proxy1_IP, proxy2_IP, ...]

      如果是可控的 proxy 配置, 例如公司 TLB(nginx), 确保: location 配置包含 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Real-IP $remote_addr;

    3. 检查一些常见云服务商约定的 header:

      1. cf-connecting-ip(Cloudflare)
      2. true-client-ip(Akamai)
      3. x-cluster-client-ip(一些 LB 服务商标准)
    4. 检查 x-forwarded-for 的常见变体:

      1. x-forwarded
      2. forwarded-for
      3. forwarded
  2. 取 TCP 协议中的 remoteAddress (只有两种情况下可以获取 client ip, 与 client 直连或是经过透明代理)

    透明代理的 nginx 配置: proxy_bind $remote_addr transparent;

    按 node net 模块 实现, 依次检查:

    1. req.connection.remoteAddress
    2. req.socket.remoteAddress
    3. req.connection.socket.remoteAddress
    4. req.info.remoteAddress
  3. 兼容一些 serverless 服务商, 从 req 附加 context 获取

    1. req.requestContext.identity.sourceIp (AWS Lambda)
leecade commented 6 years ago

Ref:

https://wanago.io/2018/09/17/javascript-testing-tutorial-part-four-mocking-api-calls-and-simulating-react-components-interactions/