fail2ban custom filter for custom node.js application

2.6k views Asked by At

Need some help related to create a custom filter for custom app which is websocket server written in node.js . As per my understanding from other articles the custom node.js app needs to write a log which enters any authentication failed attempts which will further be read by Fail2ban to block IP in question . Now I need help with example for log which my app should create which can be read or scanned by fail2ban and also need example to add custom filter for fail2ban to read that log to block ip for brute force .

1

There are 1 answers

0
Norbert On

Its really old question but I found it in google so I will write answer.

The most important thing is that line you logging needs to have right timestamp because fail2ban uses it to ban and unban. If time in log file is different than system time, fail2ban will not find it so set right timezone and time in host system. In given example I used UTC time and time zone offset and everything is working. Fail2Ban recognizes different types of timestamps but I didn't found description. But in fail2ban manual you can find two examples. There also exist command to check if your line is recognized by written regular expression. I really recommend to use it. I recommend also to use "regular expression tester". For example this one. Rest of the log line is not really important. You just need to pass user ip.

This are most important informations but I will write also example. Im just learning so I did it for educational purposes and Im not sure if given example will have sense but it works. I used nginx, fail2ban, pm2, and node.js with express working on Debian 10 to ban empty/bad post requests based on google recaptcha. So set right time in Your system: For debian 10 worked:

timedatectl list-timezones
sudo timedatectl set-timezone your_time_zone
timedatectl <-to check time

First of all You need to pass real user ip in nginx. This helped me so You need to add line in You server block.

sudo nano /etc/nginx/sites-available/example.com.

Find location and add this line:

location / {
...
proxy_set_header X-Forwarded-For $remote_addr;
...
}

More about reverse proxy. Now in node.js app just add

app.set('trust proxy', true)

and you can get user ip now using:

req.ip

Making it work with recaptcha: All about recaptcha is here: Google Developers

When You get user response token then you need to send post request to google to verify it. I did it using axios. This is how to send post request. Secret is your secret, response is user response.

const axios = require('axios'); 
axios
    .post(`https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${response}`, {}, {
      headers: {
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
      },
    })
    .then(async function (tokenres) {

      const {
        success, //gives true or false value
        challenge_ts,
        hostname
      } = tokenres.data;

      if (success) {
        //Do something
      } else { 
        //For fail2ban. You need to make correct timestamp.
        //Maybe its easier way to get this but on my level of experience
        //I did it like this:
        const now = new Date();
        const tZOffset = now.getTimezoneOffset()/60; 
        const month = now.toLocaleString('en-US', { month: 'short' });
        const day = now.getUTCDate();
        const hours = now.getUTCHours()-tZOffset;
        const minutes = now.getUTCMinutes();
        const seconds = now.getUTCSeconds();    
        console.log(`${month} ${day} ${hours}:${minutes}:${seconds} Captcha verification failed [${req.ip}]`); 
        res.send(//something)
}

Time zone offset to set right time. Now pm2 save console.log instructions in log file in /home/youruserdir/.pm2/logs/yourappname-out.log

Make empty post request now. Example line of bad request will look like this:

Oct 14 19:5:3 Captcha verification failed [IP ADRESS]

Now I noticed that minutes and seconds have no 0 but fail2ban still recognizes them so its no problem. BUT CHECK IF DATE AND TIME PASSES WITH YOUR SYSTEM TIME.

Now make filter file for fail2ban:

sudo nano /etc/fail2ban/filter.d/your-filter.conf

paste:

[Definition]

failregex = Captcha verification failed \[<HOST>\]

ignoreregex =

Now ctrl+o, ctrl+x and you can check if fail2ban will recognize error lines using fail2ban-regex command:

fail2ban-regex /home/youruserdir/.pm2/logs/yourappname-out.log /etc/fail2ban/filter.d/your-filter.conf

Result will be:

Failregex: 38 total
|-  #) [# of hits] regular expression
|   1) [38] Captcha verification failed \[<HOST>\]
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [38] {^LN-BEG}(?:DAY )?MON Day %k:Minute:Second(?:\.Microseconds)?(?: ExYear)?
`-

Lines: 42 lines, 0 ignored, 38 matched, 4 missed
[processed in 0.04 sec]

As You can see 38 matched. You will have one. If You have no matches, check pm2 log file. When I was testing on localhost my app gave IP address with ::127.0.0.1. It can be ipv6 related. It can maybe make make a problem.

Next:

sudo nano /etc/fail2ban/jail.local

Add following block:

[Your-Jail-Name]
enabled = true
filter = your-filter
logpath = /home/YOURUSERDIR/.pm2/logs/YOUR-APP-NAME-out.log
maxretry = 5
findtime = 10m
bantime  = 10m
 

So now. Be sure that you wrote filter name without .conf extension. In logpath be sure to write right user dir and log name. If You will get 5(maxrety) wrong post requests in 10minutes(finditme) then user will be banned for 10 minutes. You can change this values. Now just restart nginx and fail2ban:

sudo systemctl restart nginx
sudo systemctl restart fail2ban

After You can check if Your jail is working using commands:

sudo fail2ban-client status YOUR-JAIL-NAME

There will be written how much matches was found and how much ips are banned. More information You can find in fail2ban log file.

 cat /var/log/fail2ban.log
 Found IPADDR - 2021-10-13 13:12:57
 NOTICE  [YOUR-JAIL-NAME] Ban IPADDRES

I wrote this step-by-step because probably only people with little experience will look for this. If You see mistakes or you can suggest me something then just comment.