How to protect Odoo against brute force attack behind Nginx or Caddy

Odoo community is not protected against brute force attack by default, so the system is highly vulnerable when it is directly opened on internet. Fortunately on Odoo store, auth_brute_force App that handles this task is available through this link. However it doesn’t work correctly behind a reverse proxy such as Caddy or Nginx. In the second part of this post, i’ll explain the little tip to make it work.

Download and install the modulebrute force attack module

Download the file corresponding to your version of Odoo. Unzip the file “auth_brute_force-9.0.1.1.0.zip”. Move the folder “auth_brute_force” to your module folder: “/usr/lib/python2.7/dist-packages/openerp/addons/“.

apps

Enable the developper mode through “About” popup. Then go to Apps menu and click on “Update apps lists”, search for the new app and process to the installation. You’re good to go if you reach your system directly to port 8069 without ssl. This module will be able to ban the remote ip address. Depending on the version you’re using, more or less options are available to add in “System parameters” in settings, then parameters menu. Documentation can be find on the module download page. But if your system is behind a reverse proxy, the next part of this post is for you. By default the localhost IP 127.0.0.1 will only be the IP banned.

brute force module options

Odoo through ssl (Certificate provided by Let’s encrypt) behind reverse proxy (Caddy or Nginx)

Let’s encrypt is a free, open Certificate Authority which needs a reverse proxy to convert your unsecured into ssl connection. I won’t describe how to set it up in this article, maybe later in another post. However with this config and module, the only ip the system will be able to ban is the localhost IP (127.0.0.1) wherever your connection is coming from. It could put potentially your server offline, and make it unreachable for all of your users. So to ban computer client’s real IP address, we need to customize first the reverse proxy.

Caddy proxy

Those lines will force the proxy to forward the remote ip address into X-Real-IP and X-Forwarded-For variables, we will be able then to get their value in your Python code.

    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Proto {scheme}
vi /et/caddy/CaddyFile

Your file should look like this after modification.

odoo.numberspeaks.com {
  proxy / http://127.0.0.1:8069 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Proto {scheme}
    }
  proxy /longpolling http://127.0.0.1:8072 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Proto {scheme}
    }
  gzip
  log syslog
}

restart caddy daemon.

NGINX PROXY

Lines to add in your site conf file:

        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 https;
vi /etc/nginx/sites-enabled/default

This part of your file should be like this after modification

    location / {
        proxy_pass  http://openerp;
        # force timeouts if the backend dies
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect off;

        # set headers
        proxy_set_header    Host            $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 https;
    }

    location /longpolling {
        proxy_pass http://127.0.0.1:8072;
        proxy_redirect off;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_set_header    Host            $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 https;
    }

Update the auth_brute_force module

The right way to bring those updates should be by creating a new module that will override functions in “auth_brute_force” module, but i’m a bit too lazy. Depending on the version of your Odo you’re using, modification we will make might be a bit different. I will just show you the additional code to add for Odoo 8, 9 modules, it should be quite similar for newer version (Odoo 10, 11)

Odoo 8 module

Edit controller.py file in controller folder of auth_brute_force module and copy and paste lines bellow into your file. If the proxy is set correctly, now the real remote ip address is stored in HTTP_X_FORWARDED_FOR key in request.httprequest.environ array, we just need to set a new value of remote variable if  HTTP_X_FORWARDED_FOR exists.


            if 'HTTP_X_FORWARDED_FOR' in request.httprequest.environ:
                _logger.critical(request.httprequest.environ["HTTP_X_FORWARDED_FOR"])
                remote = request.httprequest.environ["HTTP_X_FORWARDED_FOR"]

Your file should be like this after modification

controller.py code

Save your modification and restart odoo to apply the update, after a login attempt failure you should see now your ip address instead of 127.0.0.1 ip.

ip lists

odoo 9 module

Open res_users.py file in models folder. Add those lines bellow into your file. HTTP_X_FORWARDED_FOR variable is stored in curren_thread().environ dictionary.

            if 'HTTP_X_FORWARDED_FOR' in current_thread().environ:
                x_forwarded_for_addr = current_thread().environ["HTTP_X_FORWARDED_FOR"]
                if x_forwarded_for_addr:
                    remote_addr = x_forwarded_for_addr

This part of your file should be like this.

res_users.py

Save and restart odoo to apply the update. After a login attempt failure, you should see your remote ip address.

 

attempts

Your system is now protected against brute force attack.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.