Skip to main content

Django X-Forwarded-For Properly

Project description

https://travis-ci.org/ferrix/xff.svg?branch=master https://coveralls.io/repos/github/ferrix/xff/badge.svg

The X-Forwarded-For header is used by many reverse proxies to pass the IP addresses of the whole chain of hosts between client and application server. The header looks something like this:

X-Forwarded-For: 54.12.13.14, 192.168.2.0, 192.168.3.1

This translates to:

X-Forwarded-For: client, proxy1[, proxy2[...]]

However it is just a header. Most default configurations simply append to the header. It is trivial for a malicious client to deliver a header in the initial request:

X-Forwarded-For: phony, client

What django-xff does

This library provides a decent and configurable middleware to rewrite the request.META['REMOTE_ADDR'] to the correct client IP.

This is done by setting a depth of reverse proxies to be trusted alone. The X-Forwarded-For header will additionally be sanitized from any extraneous entries.

By default, if the expected depth of proxies is 3, the client address will be used in all of these examples:

X-Forwarded-For: phony, client, proxy1, proxy2
X-Forwarded-For: client, proxy1, proxy2
X-Forwarded-For: client, proxy

Note:

  • Less proxies than expected is allowed by default, for varying lengths of proxy chains, the longest is the only one that can be trusted.

  • No header set is allowed by default and the library does nothing.

What django-xff does not do

This library does not check the IP addresses of any proxies along the path of the message.

This library is unable to detect compromised proxies or any incoming requests that have the right number addresses in the correct header.

TODO

  • Separate middleware that checks CIDR for the trusted proxies

  • Separate middleware that checks exact IP addresses for proxies

Configuration

Add the following to your Django settings.py module to enable this middleware for two reverse proxies expected. The middlewares are processed order of appearance. This middleware should go somewhere near the top to avoid giving a potentially malicious user chances to validate passwords with malformed requests:

MIDDLEWARE_CLASSES = [
   <a few middlewares here>
   'xff.middleware.XForwardedForMiddleware',
   <more middlewares here>
]

XFF_TRUSTED_PROXY_DEPTH = 2

By default, no attempts are denied. There are several settings to send a 400 (Bad Request) response to failing requests. Strict mode will stop all failing requests:

XFF_STRICT = True

To prevent only the clearly malicious requests, use the following instead:

XFF_NO_SPOOFING = True

To prevent requests that do not come through enough proxies, use the following:

XFF_ALWAYS_PROXY = True

The previous setting implies a Bad Request when there is no X-Forwarded-For header present. The following setting follows the XFF_ALWAYS_PROXY and XFF_STRICT by default but can be set independently:

XFF_HEADER_REQUIRED = False

Even in XFF_LOOSE_UNSAFE mode this will require the header:

XFF_LOOSE_UNSAFE = True

For an unsafe setting, in development possibly, you can trust that the first entry is always correct and still get the assumed client IP in the right place, use:

XFF_LOOSE_UNSAFE = True

By default, this middleware rewrites REMOTE_ADDR. To leave it untouched, use:

XFF_REWRITE_REMOTE_ADDR = False

If you want to keep the X-Forwarded-For header untouched even if there are extra entries, use:

XFF_CLEAN = False

Whitelisting

In some cases requests from alternate request paths are to be expected. The Amazon Elastic Loadbalancer healthcheck or other administrative tasks need to be available even if they do not match the criteria.

This library accepts URIs as regular expressions to be exempt for checking. These will be exempt for any validation including XFF_STRICT and XFF_HEADER_REQUIRED.

To define the whitelist:

XFF_EXEMPT_URLS = [
    r'^healthcheck/$',
    r'^admin/',
]

This will allow calling /healthcheck/ and /admin/* from anywhere. It is a daft idea to allow everyone to access the admin site with less requirements than the other parts of the site. For this reason it is possible to respond with 404 (Not Found) when the request arrives through the main entrance:

XFF_EXEMPT_STEALTH = True

This will assume that anything below XFF_TRUSTED_PROXY_DEPTH is trusted. The method is naive, but effective.

Logging

Dropped requests will be logged. This means that there will be plenty of logs when the library is misconfigured or malicious things are taking place. It is recommended to keep the logs for tracing in case of a real attack. However they can be filtered from development by setting:

LOGGING = {
    'loggers': {
         'xff.middleware': {
              'handlers': ['null'],
              'propagate': False,
         },
     },
}

Setting up

It is recommended to enable the middleware with the assumed number of proxies and investigating the logs. If the header is not present or the middleware is not configured, there will be no log entries. If the logs state that the depth is incorrect, it should be reduced. If all requests are considered as spoofing, the depth should probably be increased:

MIDDLEWARE_CLASSES = [
    'xff.middleware.XForwardedForMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
]

XFF_TRUSTED_PROXY_DEPTH = 2

When logs appear correct, control can be increased in increments:

XFF_NO_SPOOFING = True

Then:

XFF_STRICT = True

Defining exceptions is feasible with other flags set. The following could be used behind an AWS Elastic Loadbalancer to prevent entry without the proper header set but allow healthcheck to return correctly. The stealth would also mask the same URI with a 404 error:

XFF_TRUSTED_PROXY_DEPTH = 1
XFF_EXEMPT_URLS = [r'^health/]
XFF_REQUIRE_HEADER = True
XFF_EXEMPT_STEALTH = True

In case there is a chain of reverse proxies, the healthcheck URI is available for all layers except the last one.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-xff-1.4.0.tar.gz (23.2 kB view details)

Uploaded Source

Built Distributions

django_xff-1.4.0-py3.11.egg (10.3 kB view details)

Uploaded Source

django_xff-1.4.0-py2.py3-none-any.whl (11.3 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-xff-1.4.0.tar.gz.

File metadata

  • Download URL: django-xff-1.4.0.tar.gz
  • Upload date:
  • Size: 23.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for django-xff-1.4.0.tar.gz
Algorithm Hash digest
SHA256 fc87333f64d2ff2ce4ab6449e814240f9f195c290d2c8789ca81a1c98f5522ec
MD5 a7a72609c4ee6f84644a5803f9877085
BLAKE2b-256 0a74096967a0362267295ab28aebd4fbbacbf525f62ac55e4d99b91904282d15

See more details on using hashes here.

File details

Details for the file django_xff-1.4.0-py3.11.egg.

File metadata

  • Download URL: django_xff-1.4.0-py3.11.egg
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for django_xff-1.4.0-py3.11.egg
Algorithm Hash digest
SHA256 d2a34e947e730d0c899b6386b28cf675edafa9d64336cdb8c9656b0a58ed80b6
MD5 73f68d5a8bcf55ff1311b7a83b2f0e6a
BLAKE2b-256 b24c643beeda1fe2b989898c6a70cb0f8832b6a0f212563fff8e31a202f67fe9

See more details on using hashes here.

File details

Details for the file django_xff-1.4.0-py2.py3-none-any.whl.

File metadata

  • Download URL: django_xff-1.4.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for django_xff-1.4.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 8935dce34383d65b545564a3cc17dc8010c8cdec231b0932e6073ddc766d679d
MD5 9f699a032d0932d763c645826f313c0e
BLAKE2b-256 b8e4abc34c02d4c51d49192aaa35c76ff6987e60e49368e95923d62e532bacfa

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page