IP tracing is mainly used to obtain the real IP address of the request. As the existing service implements load balancing based on Nginx, it is difficult to obtain the real IP address of the request. In the existing implementation of Matrix, IP traceability is completed by getIp function, whose specific code is as follows.

/** * get the request sender's 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;
}
Copy the code

Before discussing the code in more detail, we need to examine several common ways to get the source of a request’s IP:

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

req.socket.remoteAddress

In the node.js documentation net_socket_remoteAddress, we know that req.socket.remtoeAddress can be used to obtain the source IP address of the socket connection.

socket.remoteAddress

Internet: v0.5.10

  • 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).

Req. connection and req.socket are equivalent, according to http_request_socket. We can also through the req. Connection. RemoteAddress obtain information source IP Socket connection. This method is applicable to the scenario where the client directly connects to the server.

However, since the existing Matrix service uses Nginx as the load balancer of the service cluster, the IP address of Nginx obtained through req.socket.connection is not the real IP address of the request.

X-Forwarded-For

Httpforwarded_for According to RFC 7239, HTTP proxies (such as Nginx, Apache, and others) will overwrite the header of the HTTP request and add the X-Forwarded-For field to it. This field has the following format:

X-Forwarded-For: client, proxy1, proxy2
Copy the code

This section describes how the X-Forwarded-For field is processed.

  • By default, the client (such as a browser) does not send an HTTP requestX-Forwarded-ForField.
  • When the request reaches the first HTTP proxy server, the proxy server adds to the request header according to the RFC 7239 specificationX-Forwared-ForField, and sets the value toIP address of the client.
  • If there are more than one HTTP proxy (that is, the request is subsequently processed by multiple HTTP proxies), each proxy will be in theX-Forwarded-ForIn the field valuesAppend the IP address of the previous proxy.
  • In the business server, we can passX-Forwarded-ForThe value of theThe IP address on the far leftObtain the IP address of the client.

Unfortunately, X-Forwarded-For is forgerable: If a client sets a forged X-Forwarded-For field when it initiates an HTTP request, the service server may obtain the client’S IP address from the client. This field is appended to each layer of forwarded-For proxies.

Usually, additional configuration is required For Nginx to support X-Forwarded-For.

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Copy the code

X-Real-IP

The HTTP proxy server can set x-real-IP request source information in the request header, but this is not part of the RFC specification.

X-real-ip cannot be forged by the client, but can only describe the Real IP address of the last proxy. If there are multiple proxies, it still cannot be used as the Real IP address requested by the client. In Real life, multi-layer proxies are rare. Single-layer proxies are common. Therefore, x-real-IP is usually sufficient to complete the task, and has better security than X-Forwarded-For.

Nginx supports automatic setting of the X-real-IP field with the following Settings.

proxy_set_header X-Real-IP $remote_addr;
Copy the code

A comparison of several ways

The following is a summary of several methods to obtain the real IP address of the client, and the limitations and application scenarios of each method are analyzed.

req.socket.remoteAddress X-Forwarded-For X-Real-IP
Forgerable no is no
effectiveness Only when the client directly connects to the server Only if it is not forged Only when the client does not go through multi-level proxies

The resources

  • How does the Node.js HTTP(s) service obtain a client IP address
  • Using X-Forwarded-For to forge client IP vulnerability causes and prevention
  • X-forwarded-for in the HTTP request header