2

I have a Django app running under Apache2 and mod_wsgi and, unfortunately, lots of requests trying to use the server as a proxy. The server is responding OK with 404 errors but the errors are generated by the Django (WSGI) app, which causes a high CPU usage.

If I turn off the app and let Apache handle the response directly (send a 404), the CPU usage drops to almost 0 (mod_proxy is not enabled).

Is there a way to configure Apache to respond directly to this kind of requests with an error before the request hits the WSGI app?

I have seen that maybe mod_security would be an option, but I'd like to know if I can do it without it.

EDIT. I'll explain it a bit more.

In the logs I have lots of connections trying to use the server as a web proxy (e.g. connections like GET http://zzz.zzz/ HTTP/1.1 where zzz.zzz is an external domain, not mine). This requests are passed on to mod_wsgi which then return a 404 (as per my Django app). If I disable the app, as mod_proxy is disabled, Apache returns the error directly. What I'd finally like to do is prevent Apache from passing the request to the WSGI for invalid domains, that is, if the request is a proxy request, directly return the error and not execute the WSGI app.

EDIT2. Here is the apache2 config, using VirtualHosts files in sites-enabled (i have removed email addresses and changed IPs to xxx, change the server alias to sample.sample.xxx). What I'd like is for Apache to reject any request that doesn't go to sample.sample.xxx with and error, that is, accept only relative requests to the server or fully qualified only to the actual ServerAlias.

default:

<VirtualHost *:80>
        ServerAdmin [email protected]
        ServerName X.X.X.X
        ServerAlias X.X.X.X

        DocumentRoot /var/www/default
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /var/www/>
                Options FollowSymLinks
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

        ErrorDocument 404 "404"
        ErrorDocument 403 "403"
        ErrorDocument 500 "500"
        ErrorLog ${APACHE_LOG_DIR}/error.log

        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

actual host:

<VirtualHost *:80>
 ErrorDocument 404 "404"
 ErrorDocument 403 "403"
 ErrorDocument 500 "500"

 WSGIScriptAlias / /var/www/sample.sample.xxx/django.wsgi

 ServerAdmin [email protected]
 ServerAlias sample.sample.xxx
 ServerName sample.sample.xxx

 CustomLog /var/www/sample.sample.xxx/log/sample.sample.xxx-access.log combined

 Alias /robots.txt /var/www/sample.sample.xxx/static/robots.txt
 Alias /favicon.ico /var/www/sample.sample.xxx/static/favicon.ico

 AliasMatch ^/([^/]*\.css) /var/www/sample.sample.xxx/static/$1

 Alias /static/ /var/www/sample.sample.xxx/static/
 Alias /media/ /var/www/sample.sample.xxx/media/

 <Directory /var/www/sample.sample.xxx/static/>
  Order deny,allow
  Allow from all
 </Directory>

 <Directory /var/www/sample.sample.xxx/media/>
  Order deny,allow
  Allow from all
 </Directory>
</VirtualHost>

EDIT 3. Fixed. The problem was the loading of the Virtual Host files. The attack requests didn't really have the host header set, but the Apache status page was showing it because it was loading the default virtualhost file after the the WSGI app Virtual Host file. The solution was to rename the default virtual host file to 00-default so that apache loads it first. Then all the tips you guys have mentioned have helped to ignore those requests. CPU is back under control!

2
  • You'd have to show the configuration of httpd for mod_wsgi. Normally, you should avoid passing nonsense to the backend.
    – adaptr
    Nov 5, 2012 at 15:35
  • That is what I'd like to do, I have added the virtual host files I'm using (only slightly edited). Nov 5, 2012 at 15:57

3 Answers 3

1

The simplest course of action I can recommend is to keep mod_proxy disabled and use two different <VirtualHost *:80>...</VirtualHost> sections.

In the first one you will put any ServerName that you like; since it is the first one, Apache will use it for HTTP requests that do not feature a Host: header configured in other VirtualHost sections, like proper proxy requests should be, or requests without a Host: header. It might look like this:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName default
    RedirectMatch gone .*
</VirtualHost>

The second one will be your actual server configuration, more or less exactly like what you have posted, with the correct ServerName and ServerAlias directives.

EDIT: if, as you commented, the Host: header contains your domain, then you may simply want to add

RedirectMatch gone ^http:.*

to your existing vhost. That will do the trick.

12
  • For precision's sake: this will refuse "proxy" requests with a 410 Gone instead of a 404 Not found status, but I believe it will achieve exactly what you want; in any case it will relieve your app of the unwanted load. You can do the same by, say, specifying an empty directory as DocumentRoot and disabling directory indexes inside the default VirtualHost; then you will get a 404 Not found.
    – pino42
    Nov 5, 2012 at 16:44
  • Why would apache use the first vhost for "proxy requests"? This is only true if the Host: request header does not exist or is not provided.
    – adaptr
    Nov 5, 2012 at 16:49
  • Yes, this does not work when the requests are directed to the vhost, so it is only partially useful. The attacks have the host header set to given domain name. Nov 5, 2012 at 16:54
  • Because the first vhost is the default one. Looking at the documentation: "Due to the fact that www.example.com is first in the configuration file, it has the highest priority and can be seen as the default or primary server. That means that if a request is received that does not match one of the specified ServerName directives, it will be served by this first VirtualHost." So it works both when the Host: header is missing, and when it contains something not configured elsewhere.
    – pino42
    Nov 5, 2012 at 16:56
  • 1
    I mention about default VirtualHost briefly in 'Fallback to default VirtualHost definition.' of blog.dscpl.com.au/2012/10/requests-running-in-wrong-django.html May provide some more context for understanding the issue as arises in other ways as well. Nov 5, 2012 at 22:05
0

If by proxying you mean using the CONNECT HTTP method, you can try:

<Limit CONNECT>
  Order allow,deny
  Deny from all
</Limit>

Otherwise you will need to explain what you mean by proxying.

1
  • Thanks, I have added a bit more detail to try to explain what I try to accomplish. Nov 5, 2012 at 14:58
0

You should probably add a dummy default vhost entry that never matches anything, and deny all access to it.

NOTE that whether this will help against these proxy-like attacks depends on the Host: header they supply; if they do not supply a Host: header, the request defaults to HTTP/1.0 and they will hit the first vhost anyway - which would be good.

<VirtualHost *:80>
  ServerName dummy.that.will.never.match
  DocumentRoot /tmp
  Redirect 404 /
  LogLevel crit
  ErrorLog ${APACHE_LOG_DIR}/dummy_error.log
  CustomLog ${APACHE_LOG_DIR}/dummy_access.log "[%t] %h(%a) Host: %{Host}i %H %m %r"
</VirtualHost>

The above CustomLog will provide you with a neat list of offenders.
You don't need the status since you know what it is :)

Also remove the useless ServerAlias from your WSGI host, and move the root Directory definition outside of ANY vhosts - this should be in the main server config, and it MUST deny access to everything and everyone.

<Directory />
  AllowOverride None
  Options None
  Order Allow,Deny
  Deny From All
</Directory>

You can make per-vhost exceptions for symlinks later.

3
  • The attacks have the host header set (as the Apache status page shows) so this won't help much, would it? And thanks for the other tips :-) Nov 5, 2012 at 16:57
  • What apache status page ?
    – adaptr
    Nov 5, 2012 at 17:01
  • I have the Apache status page enabled, but did not show it in the config files. Nov 5, 2012 at 17:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .