rss logo

How to secure Roundcube webmail

Rouncube Logo

Here's a new article on Roundcube, this time I will deal with security. Here I'll show how to set up fail2ban to block brute-force attacks. In addition, we'll explore the integration of a 2FA (Two-Factor Authentication) plugin, created by alexandregz, to improve overall authentication security.

Although I've already covered the subject of enabling HTTPS in Roundcube here, I'll once again show you the steps you need to enable HTTPS for an extra layer of protection.

  • Configuration:
    • debian: 12 bookworm
    • php: 8.2
    • roundcube: 1.6.5

Enable fail2ban

Fail2ban is a powerful software designed to monitor authentication errors in log files and temporarily block remote addresses responsible for repeated failed attempts. It is a versatile tool applicable to various services such as sshd, apache, dovecot etc…

Install and Configure

  • Install fail2ban:
root@host:~# apt update && apt install fail2ban
  • Start and enable nftables service:
root@host:~# systemctl start nftables root@host:~# systemctl enable nftables
  • Edit the /etc/fail2ban/jail.conf file:
banaction = nftables-multiport banaction_allports = nftables-allports
  • Edit the /etc/fail2ban/jail.d/defaults-debian.conf file:
[sshd] enabled = true backend = systemd [roundcube-auth] enabled = true logpath = /var/log/roundcube/errors.log
  • Restart the fail2ban service to take the changes into account:
root@host:~# systemctl restart fail2ban
  • Check the status of the roundcube-auth jail:
root@host:~# fail2ban-client status roundcube-auth Status for the jail: roundcube-auth |- Filter | |- Currently failed: 0 | |- Total failed: 0 | `- File list: /var/log/roundcube/errors.log `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list:

Unblock an IP address

  • List blocked ip addresses:
root@host:~# nft -a list ruleset table inet filter { # handle 1 chain input { # handle 1 type filter hook input priority filter; policy accept; } chain forward { # handle 2 type filter hook forward priority filter; policy accept; } chain output { # handle 3 type filter hook output priority filter; policy accept; } } table inet f2b-table { # handle 2 set addr-set-roundcube-auth { # handle 2 type ipv4_addr elements = { 192.168.10.36 } } chain f2b-chain { # handle 1 type filter hook input priority filter - 1; policy accept; tcp dport { 80, 443 } ip saddr @addr-set-roundcube-auth reject with icmp port-unreachable # handle 6 } }
  • If necessary, we can temporarily unblock ip addresses:
root@host:~# fail2ban-client set roundcube-auth unbanip 192.168.10.36
  • Or we can permanently whitelist IP addresses by editing /etc/fail2ban/jail.conf:
ignoreip = 127.0.0.1/8 ::1 192.168.10.36
  • Then restart the fail2ban service:
root@host:~# systemctl restart fail2ban

Add the twofactor_gauthenticator plugin

We should use an application compatible with Google Authenticator on a smartphone. I personnaly use the andOTP application which is not longer maintained: https://github.com/andOTP/andOTP but still works. And I haven't tested the FreeOTP application.

The official GitHub project can be found here: https://github.com/alexandregz/twofactor_gauthenticator

Enable the 2FA plugin

  • Install git and download the plugin:
root@host:~# apt update && apt install git root@host:~# git clone https://github.com/alexandregz/twofactor_gauthenticator.git
  • Move the twofactor_gauthenticator folder to the Roundcube plugins directory:
root@host:~# mv twofactor_gauthenticator /var/lib/roundcube/plugins/
  • Edit /etc/roundcube/config.inc.php to activate the plugin:
$config['plugins'] = [ 'twofactor_gauthenticator', ];
  • From the Roundcube web interface, go to Settings > 2-Factor Authentication:
Rouncube web interface settings menu with 2-factor authentication entry
  • Check the Activate box and click on Fill all fields:
Rouncube web interface settings for the 2-factor authentication plugin
  • A pop-up window appears, just click on OK:
2FA roundcube plugin warning window for QR code scanning
  • Write down the secret and recovery codes that will be useful if you lose your 2FA device, then scan the QR Code on your 2FA application with your smartphone:
Roundcube interface 2FA plugin with QR Code and recovery codes
  • From your smartphone, retrieve the current one time password and type it into the text box, then click on Check code to confirm that everything is correct:
2FA roundcube plugin check code code validation window
  • Finally, click on Save:
2FA roundcube plugin check code
  • After the next connection, 2FA authentication should appear:
2FA roundcube login page

Reset 2FA authentication for a user

If you have lost your 2FA device, you will not be able to connect to Roundcube. To recover a user's 2FA recovery code, or to disable the 2FA application, we'll need to perform a few actions on the Roundcube server. This procedure is effective with a SQLite database.

  • Connect to the SQLite database:
root@host:~# sqlite3 /var/lib/dbconfig-common/sqlite3/roundcube/roundcube
  • Identify the user account to be reset and retrieve 2FA recovery codes :
SELECT * FROM users ; 1|john@std.rocks|std.rocks||2024-02-09 15:02:30|2024-02-24 12:31:00|2024-02-24 11:43:03|1|en_US|a:2:{s:11:"client_hash";s:16:"Tzl9oKiP5cifLfVO";s:24:"twofactor_gauthenticator";a:3:{s:6:"secret";s:16:"VTAPZI2PZVUIR45Q";s:8:"activate";b:1;s:14:"recovery_codes";a:4:{i:0;s:10:"B2FDEYC5J7";i:1;s:10:"A6TY7H5XD6";i:2;s:10:"CYYNSZ22UB";i:3;s:10:"SWISSDWBZ7N";}}}
  • Or set preferences to null:
UPDATE users SET preferences = NULL WHERE user_id = 1;

Enable HTTPS

For security reasons, it's a good idea to enable HTTPS connections to Roundcube. This can be done using Let's Encrypt certificates or self-signed certificates. Let's see how to implement either solution.

  • First, activate the Apache ssl module:
root@host:~# a2enmod ssl

Let's Encrypt

We can request a Let's Encrypt certificate, the advantage of which is that it will be recognized by web browsers and therefore won't display a warning when you connect.

  • Install the certbot utility:
root@host:~# apt update && apt install certbot
  • Stop the apache2 service:
root@host:~# systemctl stop apache2
  • Run the certbot tool (ports 80 and 443 must be redirected to the Roundcube server, and the dns entry roundcube.std.rocks must point to the same server):
root@host:~# certbot certonly --email letsencrypt@std.rocks --standalone -d roundcube.std.rocks
  • Modify the configuration file /etc/apache2/sites-available/default-ssl.conf and add:
SSLCertificateFile /etc/letsencrypt/roundcube.std.rocks/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/roundcube.std.rocks/privkey.pem SSLCertificateChainFile /etc/letsencrypt/roundcube.std.rocks/chain.pem
  • Enable and restart the apache2 service:
root@host:~# a2ensite default-ssl root@host:~# systemctl start apache2

Self-Signed Certificates

  • Alternatively, you can create a self-signed certificate:
root@host:~# mkdir /etc/apache2/ssl/ root@host:~# openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout /etc/apache2/ssl/selfsigned.key -out /etc/apache2/ssl/selsigned.crt ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:FR State or Province Name (full name) [Some-State]:STD Locality Name (eg, city) []:stdcity Organization Name (eg, company) [Internet Widgits Pty Ltd]:std Organizational Unit Name (eg, section) []:std Common Name (e.g. server FQDN or YOUR name) []:roundcube.std.rocks Email Address []:email@std.rocks root@host:~# cat /etc/apache2/ssl/selfsigned.key /etc/apache2/ssl/selsigned.crt > /etc/apache2/ssl/cert.pem
  • Edit the /etc/apache2/sites-available/default-ssl.conf configuration file:
DocumentRoot /var/lib/roundcube/public_html/ #AUTOGENERATE CERTIFICATES SSLCertificateFile /etc/apache2/ssl/cert.pem SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key
  • Edit the /etc/apache2/ports.conf configuration file and disable http:
#Listen 80
  • Enable and restart the apache2 service:
root@host:~# a2ensite default-ssl root@host:~# systemctl restart apache2