获取请求来源 IP 地址

IP 追溯主要用于获取请求的真实 IP ,因为现有服务是基于 Nginx 实现负载均衡的,所以获取请求真实 IP 存在必定难度。在 Matrix 现有实现中,IP 追溯由 getIp 函数完成,其具体代码以下。javascript

/** * 得到请求发送方的 ip * @param {Context} ctx * @return {string} */
export function getIp(ctx) {
  const xRealIp = ctx.get('X-Real-Ip');
  const { ip } = ctx;
  const { remoteAddress } = ctx.req.connection;
  return xRealIp || ip || remoteAddress;
}
复制代码

在对代码进行更为详细的讨论以前,咱们须要分析几种经常使用获取请求 IP 来源的方式:html

  • req.socket.remoteAddress
  • X-Forwarded-For
  • X-Real-IP

req.socket.remoteAddress

在 Node.js 官方文档 net_socket_remoteaddress 中,咱们得知可经过 req.socket.remtoeAddress 获取 Socket 链接的源 IP 地址信息。java

socket.remoteAddress

Added in: v0.5.10node

  • String

The string representation of the remote IP address. For example, '74.125.127.100' or '2001:4860:a005::68'. Value may be undefined if the socket is destroyed (for example, if the client disconnected).nginx

根据官方文档 http_request_socket 的描述,req.connectionreq.socket 是等价的,咱们也能够经过 req.connection.remoteAddress 获取 Socket 链接的源 IP 信息。这种获取请求 IP 来源的方式,适用于客户端直连服务端的场景。git

但因为现有 Matrix 服务使用了 Nginx 做为服务集群的负载均衡,故经过 req.socket.connection 获取获得的是 Nginx 的 IP 地址,并非请求的真实 IP 地址。github

X-Forwarded-For

根据 RFC 7239 规范,HTTP 代理(如 Nginx、Apache 等)会改写 HTTP 请求头部,添加 X-Forwarded-For 字段,用于追踪请求的来源,该字段的格式以下:api

X-Forwarded-For: client, proxy1, proxy2
复制代码

下面对 X-Forwarded-For 字段的处理过程,进行详细阐述:浏览器

  • 客户端(如浏览器)在发送 HTTP 请求时,默认是不带 X-Forwarded-For 字段。
  • 当请求到达第一个 HTTP 代理服务器时,代理服务器根据 RFC 7239 规范,为请求头部添加 X-Forwared-For 字段,而且将值设置为客户端的 IP 地址
  • 若后面存在多个 HTTP 代理(即请求在后续会依次被多个 HTTP 代理处理),则每一个代理都会在 X-Forwarded-For 字段值中追加上一代理的 IP 地址
  • 在业务服务器中,咱们可经过 X-Forwarded-For 值的最左边的 IP 地址获取客户端的 IP 地址。

但遗憾的是,X-Forwarded-For可伪造的:若是客户端在发起 HTTP 请求时,设置了伪造的 X-Forwarded-For 字段,因为后续的每层代理只会追加此字段而不会覆盖,故业务服务器最终获取的客户端 IP 地址多是客户端伪造的地址。安全

一般,咱们须要进行额外的配置,才能使得 Nginx 支持 X-Forwarded-For

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
复制代码

X-Real-IP

HTTP 代理服务器可在请求头部中设置 X-Real-IP 请求源信息,但这并非 RFC 规范中的内容

X-Real-IP客户端不可伪造的,但仅能描述最近一个代理的真实 IP ,若是有多层代理,其仍旧不可做为客户端请求的真实 IP 。在现实生活中,多层代理实际上是比较少见的,常见的是单层代理,所以在一般状况下,使用 X-Real-IP 是足以完成任务的,且相对于 X-Forwarded-For 有更好的安全性。

咱们可经过如下设置,使得 Nginx 支持 X-Real-IP 字段的自动设置。

proxy_set_header X-Real-IP $remote_addr;
复制代码

几种方式的对比

如下是我对几种获取客户端真实 IP 的方式的总结,分析了各方式的局限和应用场景。

req.socket.remoteAddress X-Forwarded-For X-Real-IP
是否可伪造
有效性 仅在客户端直连服务端时 仅在未伪造时 仅在客户端未通过多级代理时

参考资料

相关文章
相关标签/搜索