
It was a nice summer day. I was driving to New York and intended to stay for couple of days in the peaceful city of Buffalo. Everything was falling nicely into place. There was not much traffic and I reached my destination way ahead of time.
After settling down at the hotel, I thought I will look at the pet project I was working with. Unfortunately, it looked like mongo server installed on my remote VPS was down as I was not able to fetch any data. I went and checked the server, and alas, all my tables were missing. And also found one single table, with the following data inserted.
{
"_id" : ObjectId("5f4a3e64eca4e2ee018f91b5"),
"content" : "All your data is a backed up. You must pay 0.04 BTC to 1LiC8kq4NdMcxQfGSHsrwq4cGKcXSWL5GP 48 hours for recover it. After 48 hours expiration we will leaked and exposed all your data. In case of refusal to pay, we will contact the General Data Protection Regulation, GDPR and notify them that you store user data in an open form and is not safe. Under the rules of the law, you face a heavy fine or arrest and your base dump will be dropped from our server! You can buy bitcoin here, does not take much time to buy https://localbitcoins.com with this guide https://localbitcoins.com/guides/how-to-buy-bitcoins After paying write to me in the mail with your DB IP: recoveryourdata@mailnesia.com"
}
I remembered at that time that I had opened up the default 27017 port to the world night before to access from my local machine and forgot to revert it. So ransomware attacks are not so 2017s, it still happened in 2020. Most likely it will continue to happen in 2021. In this blog I will go through the steps I went through to secure mongo db. For me all data in that database was BS, so I didn’t care about recovery.
Enabling Default Security
Since the ransomware attacks in 2017, mongo has made changes to only enable server to be accessed from localhost. This is a good thing, as now this server is not accessible from the internet. However if you are logged into the machine, you can still access it without using a password.
The first thing that we will be doing is enabling administrative user. For this I will borrow from my older post My Notes on Mongo DB. Use the following to create a new admin user.
# What are available DBs > show dbs admin 0.000GB config 0.000GB local 0.000GB # Switch user to Admin > use admin switched to db admin # Create a user with all DB access > db.createUser({user: "suser", pwd: "$ecret", roles: [ "userAdminAnyDatabase" ]}) Successfully added user: { "user" : "suser", "roles" : [ "userAdminAnyDatabase" ] }
We enable authorization in mongo daemon config.
$ sudo vi /etc/mongod.conf #### mongod.conf edit #### security: authorization: "enabled" #### mongod.conf edit end #### $ sudo systemctl restart mongod $ sudo systemctl status mongod $ mongo -u suser -p --authenticationDatabase admin
Security block in mongod.conf is normally commented out. We will uncomment this and enable Authorization. See lines 4 and 5 above. After this we will restart mongo daemon (as seen on line 8). Default mongo client will still continue to work and you will see a mongo prompt. However, since you are not authorized, you will not be able to see any databases. We will start up the database client using -u (user) and -p (prompt password). We will also be authenticating against the Admin database (see line 10).
Till now we have taken care of disabling unauthorized access to the databases. However, we can also add additional security measures to make sure mongo is secure. Let us take a look at these in the next section.
Additional Security Measures
Now that the basics are out of the way, we will start doing some additional configuration changes. The first one that I did is just security by obscurity. I changed the port to use a non default port. For this blog, let us configure it to use port 27123. We make this change in mongo daemon configuration file.
$ sudo vi /etc/mongod.conf #### mongod.conf edit #### net: port: 27123 #### mongod.conf edit end #### $ sudo systemctl restart mongod $ mongo -u suser -p --port 27123 --authenticationDatabase admin
After restarting, note that we have to send an additional parameter to start client. However, at this time, this is still not accessible from the external world. To make it work from any IP address, let us add the following rules in mongo config. For this blog I am assuming the following (both fake, I do not own any of these IPs):
- I will access from my home network at IP 123.45.67.89
- IP for my application server calling this mongo is 123.54.76.98
Let’s adjust configuration to reflect these values.
$ sudo vi /etc/mongod.conf #### mongod.conf edit #### net: port: 27123 bindIp: 127.0.0.1,123.45.67.89,123.54.76.98 #### mongod.conf edit end #### $ sudo systemctl restart mongod $ mongo -u suser -p --port 27123 --authenticationDatabase admin
The only addition you will see is the bindIp (line 6). By default it will only listen to localhost, we are adding the additional IP addresses required.
Now we will make sure that this port is open from the firewall. If you are not a network admin, I will guess you also use uncomplicated firewall (ufw) on Linux. If you are on a Mac or Windows, you can use the built in firewall using their UI. For this blog, and because most of my VPS are Ubuntu Linux, I will just go with ufw.
$ sudo ufw allow from 123.45.67.89 to any port 27123 proto tcp
This will allow access from your home IP address to the server. Similarly, you can add a different rule for server IP.
Final Notes
Now that the database is presumable a lot more secure from attacks, should you just leave it that way? Here are some additional things that has to be done.
- Take backups every day, so you can restore in case of attack or more mundane data corruptions
- Mongo has plenty of logging, keeping an eye on them helps
- From time to time compact database
I hope you will find this blog useful to setup mongo security. Ciao for now!
Image Copyright: Image by StockUnlimited