Django team considers host header poisoning (CVE-2011-4139 and CVE-2012-4520) as a security issue that must be resolved at a framework level. Pyramid, for instance (that is, its underlying low-level request wrapper—webob) does not consider this as an issue.
On production & development machines I have nginx which seems to pass correct SERVER_NAME even if Host header contains complete garbage, and responds with 444 No response if there is no matching server_name.
Question: should I worry about Host header poisoning in such case, if I use SERVER_NAME to build absolute URLs?
If you use nginx to sanitize the HTTP_HOST and SERVER_NAME fields, you are doing the right thing and do not need to worry about Host header poisining.
Like Django, Pyramid considers a large part of this the task of the WSGI host environment. And nginx does an excellent, battle-hardened job of sanitizing the HTTP request information.
Related
I keep getting an Invalid HOST Header error which I am trying to find the cause of. It reads as such:
Report at /GponForm/diag_Form
Invalid HTTP_HOST header: '192.168.0.1:443'. You may need to add '192.168.0.1' to ALLOWED_HOSTS
I do not know what /GponForm/diag_Form is but from the looks of it, it may be a vulnerability attacked by malware.
I also am wondering why the IP is from a router 192.168.0.1 as well as why it is coming through SSL :443
Should I consider putting a HoneyPot and blocking this IP address? Before I do, why does the IP look like a local router?
The full Request URL in the report looks like this:
Request URL: https://192.168.0.1:443/GponForm/diag_Form?style/
I am getting this error at least ~10x/day now so I would like to stop it.
Yes, this surely represents a vulnerability - someone tried to access this url on router (which usually have ip 192.168.0.1).
It looks so because request from attacker contains HOST header with this value.
Maybe django is run locally with DEBUG=True.
You may consider running it more production wised with web-server (i.e. nginx) in front filtering unwanted requests with nginx config and further adding fail2ban to parse nginx error logs and ban ip.
Or make site available only from specific ips / ads simple authorization, i.e. Basic Auth on web-server level.
Previous irrelevant answer
ALLOWED_HOSTS option specifies domains django project can serve.
In running locally - python manage.py runserver or with DEBUG=True - it defaults to localhost, 127.0.0.1 and similar.
If you are accessing django via different url - it will complain in such a manner.
To allow access from another domains - add them to ALLOWED_HOSTS: ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]', '192.168.0.1'].
HSTS = HTTP Strict Transport Security
From the Django Docs on HSTS
For sites that should only be accessed over HTTPS, you can instruct modern browsers to refuse to connect to your domain name via an insecure connection (for a given period of time) by setting the “Strict-Transport-Security” header. This reduces your exposure to some SSL-stripping man-in-the-middle (MITM) attacks.
SecurityMiddleware will set this header for you on all HTTPS responses if you set the SECURE_HSTS_SECONDS setting to a non-zero integer value.
However this header can also be set by Nginx in the conf file, by adding a line:
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains;";
So the question is, should we configure Nginx to set this header or Django SecurityMiddleware, by adding the HSTS settings in the project settings file?
It's entirely up to you. If you run multiple sites it might be easier to set a global value in your webserver settings. However, if you set it in Django it will be easier to move your application to a new webserver.
I have a bit problem with my site.
So setup is ElasticBeanstalk(NGINX) + Cloudflare
But each day around 4AM I have direct IP attack to my server.
Around 300 requests in 1-2 minutes.
Bot try to access some resources like
GET /phpMyadmi/index.php HTTP/1.1
GET /shaAdmin/index.php HTTP/1.1
POST /htfr.php HTTP/1.1
For now all of them going to 80 or 8080 ports.
And successfully handled by Nginx configuration that redirect it to example:443
server {
listen 80 default_server;
listen 8080 default_server;
server_name _;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl on;
...
So questions are,
have many site owners/devOps face the same attack. What is your action to prevent such attacks.
For now it is handled very well and did not affect on server work, should I worry about it? Or just filter out logs with /phpmy/ pattern and forgot about it.
Before this attacks I have request with method PROPFIND, should I blocked it for security reasons? It is handled by default server for now.
I know that I can use Cloudflare Argotunel or ELB + WAF. But I am not really want to do it for now.
I have found one solution on stackoverflow. Is whitelist of all cloudflare ips. But i think it is not a good one.
Also another solution that should work I guess it is to check Host header, and compare it with 'example.com'.
To answer your specific questions:
Every public IP receives unwanted traffic like you describe, sadly its pretty normal. This isnt really an attack as such, its just a bot looking for signs of specific weaknesses, or otherwise trying to provoke a response that contains useful data. This data is no doubt later used in actual attacks, but its basically automated recognisance on a potentially massive scale.
This kind of script likely isnt trying to do any damage, so as long your server is well configured & fully patched its not a big concern. However these kinds of scans are first step towards launching an attack - by identifying services & application versions with known vulnerabilities - so its wise to keep your logs for analysis.
You should follow the principle of least privilege. PROPFIND is related to WebDAV - if you dont use it, disable it (or better white list the verbs you do support and ignore the rest).
If your site is already behind CloudFlare then you really should firewall access to your IP so only Cloudflares IPs can talk to your server. Those IPs do change, so I would suggest a script to download the latest from https://www.cloudflare.com/ips-v4 and have it periodically update your firewall. Theres a slightly vuage help article from CloudFlare on the subject here: https://support.cloudflare.com/hc/en-us/articles/200169166-How-do-I-whitelist-Cloudflare-s-IP-addresses-in-iptables-
If for whatever reason you cant firewall the IP, your next best option is something like fail2ban (www.fail2ban.org) - its a log parser that can manipulate the firewall to temporarily or permanently block an IP address based on patterns found in your log files.
A final thought - id advise against redirecting from your IP to your domain name - your telling the bot/hackers your URL - which they can then use to bypass the CDN and attack your server directly. Unless you have some reason to allow HTTP/HTTPS traffic to your IP address, return a 4XX (maybe 444 a " Connection Closed Without Response") instead of redirecting when requests hit your IP. You should then create a separate server block to handle your redirects, but only have it respond to genuine named URLs.
I'm currently developing a site where the functionality needs to be split into separate subdomains, dashboard.example.com, admin.example.com, and facebook.example.com. I would like everything to be served through a single Django project because everything will be using the same core models. I'm using Nginx as a front-facing proxy server handling static files and passing all other requests to Apache.
The solution I thought of was to map each of these subdomains to the appropriate app through nginx:
server {
listen 80;
server_name dashboard.example.com;
...
location / {
proxy_pass http://127.0.0.1/dashboard/;
...
}
}
server {
listen 80;
server_name admin.example.com;
...
location / {
proxy_pass http://127.0.0.1/admin/;
...
}
}
...doing that for each subdomain, effectively mapping the subdomains to their respective app url namespaces. The problem I encountered was that Django was unaware of the mapping, so when it reversed a URL, it would prepend /dashboard/, etc. to it, creating URLs like dashboard.example.com/dashboard/dashboard/. I figure I could write a custom reverse function to strip out the unnecessary subdirectory, but that seems like a band-aid.
Is there a better way to accomplish what I need, or should I restructure the project?
Thanks for your help.
Django's Sites framework (https://docs.djangoproject.com/en/1.7/ref/contrib/sites/) should be sufficient for this, if not, take a look at django-subdomains (http://django-subdomains.readthedocs.org/en/latest/) as seems to have a means of resolving your reverse URLs (based off a quick Google search, I've never used it myself!)
My server is mapped to 2 domain names, and I want to return different web pages when a user is visiting the home page, based on which domain name is used.
Django has a get_host() function in request object, Django doc:
get_host() Returns the originating host of the request using information from the HTTP_X_FORWARDED_HOST (if USE_X_FORWARDED_HOST is enabled) and HTTP_HOST headers, in that order. If they don’t provide a value, the method uses a combination of SERVER_NAME and SERVER_PORT as detailed in PEP 3333.
I am not sure if every mainstream browsers respect these headers.
Can I rely on this function to tell me which domain name is the user visiting?
Yes, all mainstream browsers send the Host header as it is mandatory for all requests sent via HTTP/1.1. Many HTTP/1.0 clients also support this header.