2

So I am running apache 2.4.54 on a redhat centos 7 machine. I am using the below configuration to run my django application with mod_wsgi:

# create new
#LoadModule wsgi_module modules/mod_wsgi.so
LoadModule wsgi_module "/home/ec2-user/.virtualenvs/myproj_prod/lib/python3.9/site-packages/mod_wsgi/server/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so"
WSGIPythonHome "/home/ec2-user/.virtualenvs/myproj_prod"

#LogLevel Info

<VirtualHost *:80>

    LogLevel Info
    #LogLevel Error
    ServerName www.mysite.com
    ServerAlias mysite.com
    ServerAdmin webmaster@mysite.com

    #DocumentRoot /usr/local/www/documents
    #Alias /robots.txt /usr/local/www/documents/robots.txt
    #Alias /favicon.ico /usr/local/www/documents/favicon.ico
    #Alias /media/ /usr/local/www/documents/media/

    #Alias /robots.txt /path/to/mysite.com/static/robots.txt
    Alias /favicon.ico /var/www/mysite.com/static/favicon.ico
    #Alias /media/ /path/to/mysite.com/media/
    Alias /static/ /var/www/mysite.com/static/

    <Directory "/var/www/mysite.com/static">
        <RequireAll>
            Require not ip 47.222.213.25
            Require not ip 34.207.41.127
            Require not ip 54.209.63.240
            Require not ip 44.196.220.146
            Require not ip 34.206.83.67
            Require not ip 34.194.232.56
            Require not ip 44.194.69.200
            Require all granted
        </RequireAll>
    </Directory>

    WSGIDaemonProcess mysite.com processes=1 threads=5 display-name=%{GROUP} home=/home/ec2-user/DjangoProjects/myproj python-path=/home/ec2-user/.virtualenvs/myproj
    WSGIProcessGroup mysite.com
    WSGIScriptAlias / /home/ec2-user/DjangoProjects/myproj/myproj/wsgi.py process-group=mysite.com application-group=%{GLOBAL}

    <Directory "/home/ec2-user/DjangoProjects/myproj">
        <RequireAll>
            #Require not ip 47.222.213.25
            Require not ip 34.207.41.127
            Require not ip 54.209.63.240
            Require not ip 44.196.220.146
            Require not ip 34.206.83.67
            Require not ip 34.194.232.56
            Require not ip 44.194.69.200
            Require all granted
        </RequireAll>
        <Files "wsgi.py">
            <RequireAll>
                #Require not ip 47.222.213.25
                Require not ip 34.207.41.127
                Require not ip 54.209.63.240
                Require not ip 44.196.220.146
                Require not ip 34.206.83.67
                Require not ip 34.194.232.56
                Require not ip 44.194.69.200
                Require all granted
            </RequireAll>
        </Files>
    </Directory>

</VirtualHost>

I would like to block the ip addresses marked in the <RequireAll></RequireAll> tags - however it is not blocking the ip addresses. When I insert mine to test, it allows me to go straight through. When I was using deny from it would at least block my ip, but I read that it was deprecated. So I thought while I am trying to prevent these ips I might as well fix the configuration file.

It will run, I can access the site (which ironically is the problem since I am trying to test this by blocking my ip), so I think it could be a logical configuration problem, but I am too much of an amatuer to know what that is, so guidance would be greatly appreciated! Thank you.

I've googled up and down and have tried many of the suggested answers, so that is why I think it has to be a configuration problem on my end - but seeing that the documentation has it like so in my config file, I'm at a loss. I've seen someone mention that aliases in the file could potentially bypass any ip restrictions a config file would have, but I think I can rule that out in this situation - I have 1 alias for static files and if I could block just the main site, I wouldn't necessarily care about what static files the blocked ips could find.

I haven't tried a .htaccess file yet, but I might start working on that. I read somewhere that it is slower than just configuring it in the .conf file.

UPDATE .htaccess file - I don't know why anyone would expect for this to be any different, but it didn't work.

EDIT - I am uncertain as to how pertinent this is, but I get this error in my error logs:

[Thu Oct 13 16:53:59.234764 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port] Invalid HTTP_HOST header: 'x.x.x.x'. You may need to add 'x.x.x.x' to ALLOWED_HOSTS.
[Thu Oct 13 16:53:59.234764 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port] Traceback (most recent call last):
[Thu Oct 13 16:53:59.234769 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]   File "/home/ec2-user/django/django/core/handlers/exception.py", line 55, in inner
[Thu Oct 13 16:53:59.234772 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]     response = get_response(request)
[Thu Oct 13 16:53:59.234776 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]   File "/home/ec2-user/django/django/utils/deprecation.py", line 136, in __call__
[Thu Oct 13 16:53:59.234779 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]     response = self.process_request(request)
[Thu Oct 13 16:53:59.234783 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]   File "/home/ec2-user/django/django/middleware/common.py", line 48, in process_request
[Thu Oct 13 16:53:59.234786 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]     host = request.get_host()
[Thu Oct 13 16:53:59.234789 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]   File "/home/ec2-user/django/django/http/request.py", line 148, in get_host
[Thu Oct 13 16:53:59.234793 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port]     raise DisallowedHost(msg)
[Thu Oct 13 16:53:59.234796 2022] [wsgi:error] [pid 4234] [remote y.y.y.y:port] django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'x.x.x.x'. You may need to add 'x.x.x.x' to ALLOWED_HOSTS.

I don't get this error when I try to access an invalid route and my ip isn't in ALLOWED_HOSTS, which is interesting to me. It may not mean anything.

Shmack
  • 131
  • 6
  • If you look at your access logs, are you requests coming from the expected ip addresses? – larsks Oct 13 '22 at 11:36
  • 1
    I did not have the access logs contain output information on the source ip address, so I changed that. Rather I saw that the in the error logs that an ip address was trying to access a (very malicious looking) route that didn't exist. Now when I check the access logs, I see my ip address - so yes, they are coming from the expected ip addresses. – Shmack Oct 13 '22 at 15:30
  • An important note that may be helpful: I noticed that django was throwing an error that might give a hint as to how to fix this problem... IDK. Check the EDIT section. It doesn't throw this error for me when I request access to a route that doesn't exist. – Shmack Oct 13 '22 at 18:57

1 Answers1

1

I wonder if you can simplify your configuration to figure exactly what isn't working? The following seems to work exactly as expected:

<VirtualHost *:80>
    ServerName www.mysite.com

    <Directory /var/www/html/protected>
        <RequireAll>
            Require not ip 192.168.1.200
            Require not ip 192.168.1.201
            Require all granted
        </RequireAll>
    </Directory>
</VirtualHost>

If I access that from a an address not in the deny list, it works just fine:

$ curl -H 'Host: www.mysite.com' 192.168.122.67/protected/
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Root</title>
  </head>

  <body>
This is the protected document.
  </body>
</html>

But if I access from a forbidden IP, I get a 403 Forbidden response:

$ curl -H 'Host: www.mysite.com' 192.168.122.67/protected/ --interface 192.168.1.200
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>

Are you able to reproduce that behavior? Try that first, and if it works, then start introducing additional parts of your configuration until the behavior changes.


If your web server is behind a proxy, you need a slightly different solution. First, you need to ensure that your frontend proxy provides you with the original client address in an HTTP header such as X-Forwarded-For or Forwarded.

You have a couple of options:

  1. You can match directly against the header. For example, if the original client IP is in X-Forwarded-For, we could prevent access from a specific client like this:

    <Directory "/usr/local/apache2/htdocs">
        Options Indexes FollowSymLinks
        AllowOverride None
    
        Require expr %{HTTP:X-Forwarded-For} != '172.25.0.1'
    </Directory>
    
  2. You can tell Apache to treat an IP address in header as the client address for the purposes of access control using the mod_remoteip module.

    In that case, you might have:

    LoadModule remoteip_module modules/mod_remoteip.so
    RemoteIPHeader X-Forwarded_for
    
    <Directory "/usr/local/apache2/htdocs">
        Options Indexes FollowSymLinks
        AllowOverride None
    
        Require not ip 172.25.0.1
    </Directory>
    
larsks
  • 43,623
  • 14
  • 121
  • 180
  • Right now I get 404 after copying and pasting. I would assume it'd be enough to test it on the static dir, because it's so simple, but I can access all the contents of the static dir, despite blocking my ip address. – Shmack Oct 15 '22 at 20:25
  • Okay, was getting a 404 with curl - but when I access the site in a web browser, it can find the file... ie there was no 403 after blocking my ip. – Shmack Oct 15 '22 at 20:44
  • Try to figure out why you're getting 404 errors with curl: are you using the wrong URL? Is there a problem with your Apache configuration? Do you actually have something else listening on port 80? If you can answer this question you may be closer to a solution. – larsks Oct 15 '22 at 21:35
  • Okay, I figured part of it out. The server is hosted on an EC2 instance and is being load balanced by an ELB, so the IP Address that I need to block to stop all requests is from the ELB... if I do this, all traffic is blocked... what I need to do is block from the flag `X-FORWARDED-FOR`, so I don't block all traffic, but I am not coming across anything for Apache 2.4.54. – Shmack Oct 29 '22 at 17:58
  • Just searching for "apache block x-forwarded-for" leads me to https://serverfault.com/questions/852000/how-to-block-ip-address-on-apache-when-it-comes-from-proxy and https://serverfault.com/questions/235648/apache-use-x-forwarded-for-for-allow and other similar procedures. https://httpd.apache.org/docs/2.4/howto/access.html shows how you might apply these to 2.4.x (in particular in the "Access control by arbitrary variables" section, I think). – larsks Oct 29 '22 at 18:04
  • Yah, sorry, I just found it :) - I spoke too quick! Adding `RemoteIPHeader X-Forwarded-For` to my file solved it. So how should I resolve this question? If you'd like to include a warning (as well as your initial post) to others coming here that they need to check if they are sitting behind a load balancer / reverse proxy and include `RemoteIPHeader X-Forwarded-For` as a potential solution, I'd love to mark this as the accepted answer. Otherwise, if you feel like the question should just be deleted, because it could be deemed as a potential duplicate, I can do that too. – Shmack Oct 29 '22 at 18:11
  • I do want to add as well that I had stumbled across those links in a search, but I mean I am assuming the answers weren't for apache 2.4+, because they were from 2011, with the potential exception of https://serverfault.com/a/904169/913804. But it's whatever - just get back with me on my previous comment, when you get the chance. – Shmack Oct 29 '22 at 18:19
  • I've updated the answer to include examples both of using a `Require expr` expression as well as `mod_remoteip`. – larsks Oct 29 '22 at 18:46
  • Cool - I didn't have to import mod_remoteip, but that may not matter. Thanks for your suggestions and willingness to help. – Shmack Oct 29 '22 at 18:50