获取 IP 的几种来源
req.connection.remoteAddress
参考: https://nodejs.org/api/net.html#net_socket_remoteaddress

指 socket 连接的源IP信息, 适用于客户端 直连 服务端的场景.
X-Forwarded-For (RFC 7239)
通常 Server 端不会直接与 Client 端通信, 而是通过 Nginx 等代理接受客户端请求, 这时候 remoteAddress 是代理服务的地址, 无法描述客户端IP.

由此引入了HTTP 扩展协议头: X-Forwarded-For , 格式是:
X-Forwarded-For: client, proxy1, proxy2

获取的时候取 X-Forwarded-For 的第一个 IP 地址即可.
但需要注意的是: X-Forwarded-For 可伪造!

通常 Nginx 作为 proxy 时的配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
X-Real-IP
代理程序设置请求源的 IP 信息, 目前并不是 RFC 标准.

X-Real-IP 不可伪造, 但仅能描述最近一个代理的真实IP, 如果有多级代理, 仍旧不可作为真实客户端的 IP.
通常 Nginx 作为 proxy 时的配置:
proxy_set_header X-Real-IP $remote_addr;
对比
| req.connection.remoteAddress | X-Forwarded-For | X-Real-IP(前提是自有Nginx主动设置) | |
|---|---|---|---|
| 是否可伪造 | 否 | 是 | 否 |
| 有效性 | 仅在客户端直连服务端时 | 仅在未伪造时 | 仅在客户端未经过多级代理时 |
Express 中获取 IP 方式及建议
req.ip (readonly)
默认是返回的是 req.connection.remoteAddress;
当设置 app.set('trust proxy', true) 时, 返回的是 X-Forwarded-For 中的第一个 IP;
注: 如果
X-Forwarded-For第一个被伪造且不是一个正常IP,req.ip不会做任何处理.
proxy-addr
req.ip 背后用的即是 proxy-addr, 不单独讨论.
request-ip
综合了多种 Header 建立了 IP 获取的优先顺序, 同时如果有伪造的异常数据会进行过滤.
https://github.com/pbojinov/request-ip#how-it-works

推荐 Express 做法
使用 request-ip 库:
const express = require('express')
const requestIP = require('request-ip')
const app = express()
app.set('trust proxy', false) // default is false
app.use(requestIP.mw({ attributeName: 'clientIP' })
推荐 Nginx 配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
引申阅读
req 上的各种 remoteAddress 异同
https://stackoverflow.com/a/19524949/1918831
req.connection.remoteAddressreq.socket.remoteAddressreq.connection.socket.remoteAddressreq.info.remoteAddress
req是http.IncomingMessage的实例req.connection===req.socket: https://nodejs.org/api/http.html#http_request_socket (lib/_http_incoming.js)req.connection.socket: https only & node <= 0.11.2 有效req.info: for hapi 框架, https://hapijs.com/api#-requestinfo