0

I have a custom Django web app sitting behind an NGINX proxy server.

I am seeing occasional errors come through from my Django server with messages like

Invalid HTTP_HOST header: 'my.domain.com:not-a-port-number'. The domain name provided is not valid according to RFC 1034/1035.

where the part after the colon has been a variety of wack garbage like,

  • my.domain.com:§port§/api/jsonws/invoke
  • my.domain.com:xrcr0x4a/?non-numeric-port-bypass
  • my.domain.com:80@+xxxxtestxxxx/
  • my.domain.com:80@+${12311231}{{12311231}}/

I am able to replicate a similar error using curl where the request url and the host header are different:

curl https://my.domain.com --header 'Host: my.domain.com:not-a-port-number'

I suspect that these are likely coming from our network security scanning software trying to find vulnerabilities in our custom web apps, but I am a little surprised that NGINX allows these requests to make it through to my Django server, especially if, as the 500 error output suggests, these are invalidly formatted headers.

Trying to prepare for the worst, is there anything I should change or be concerned about with this for the sake of security? Is there a best practice for this situation that I am unaware of? Should NGINX be filtering out these sorts of requests?

For my own convenience it would be nice to not to see the noise of these 500 errors coming from Django while I am on the lookout for real app level errors, but simply hiding the alerts seems to be a poor solution.

Additional Info:

I have ALLOWED_HOSTS set to 'my.domain.com' in my Django settings.py file.

NGINX configuration:

server {
        listen 80 default_server;
        return 444;
}

server {
        listen 80;
        server_name my.domain.com;
        return 301 https://$server_name$request_uri;
}

server {
        listen 443 ssl default_server;
        ssl_certificate     /path/to/cert.cabundle.pem;
        ssl_certificate_key /path/to/cert.key;
        return 444;
}

# App https server.
# Serve static files and pass requests for application urls to gunicorn socket.
server {
        listen 443 ssl;
        server_name my.domain.com;

        ssl_certificate     /path/to/cert.cabundle.pem;
        ssl_certificate_key /path/to/cert.key;

        ... 

        location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_pass http://unix:/path/to/gunicorn.sock;
        }
}

Khidrix
  • 31
  • 5

1 Answers1

1

I never met such a situation on practice, however I can guess nginx select your last server block to handle the request according to the information from the SNI Client Hello extension which by some reason (malformed request from scanning software?) is different from the Host header value in the encrypted request.

If you want to filter those requests at the nginx level, you can try this:

server {
    listen 443 ssl;
    server_name my.domain.com;

    ssl_certificate     /path/to/cert.cabundle.pem;
    ssl_certificate_key /path/to/cert.key;

    if ($http_host != my.domain.com) {
        return 444;
    }

    ...
}

PS. For the security considerations I never use my real certificate in a stub server block like this one:

server {
    listen 443 ssl default_server;
    ssl_certificate     /path/to/cert.cabundle.pem;
    ssl_certificate_key /path/to/cert.key;
    return 444;
}

Use a self-signed one as shown here. The reason if obvious - dear hacker, if you don't know what exactly domain you are scanning now, I'm not going to tell you what it is.

Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37