Securing your MongoDB server

Hi,

As I’m sure many of you know, there has been a massive amount of open MongoDB servers on the internet that have been discovered, and “hackers” have been taking advantage of this. Part of what makes these attacks so easy for “hackers” is that the tools are already there, just google “mongodb-tools” and you’ll see tools like mongodump, mongoexport, mongorestore, etc, as well as of course just the mongo shell. By leveraging these tools it’s incredibly easy for “hackers” to make extremely simple scripts to automate the process of dumping, dropping, and inserting a ransom note or in some cases, just dropping and inserting a ransom note.

Let’s get into how to protect against these kind of “attacks”. Now first of all, if you are running the MongoDB instance on the same server that your code that needs to access the MongoDB is running on, this is super easy. Just get a firewall (however you should still enable authentication, read further)! You should have one regardless. I recommend firewalld, as it’s super easy to use, works great, and is in basically every single distributions repositories. For CentOS 7/RHEL you can do:

sudo yum install firewalld # installs firewalld
sudo systemctl enable firewalld # enables firewalld to run on boot
sudo systemctl start firewalld # starts firewalld

There you go! Now if you need to run your MongoDB server on a server different than the one that is running your app itself, it’s slightly trickier, but still ridiculously easy, we just need to add authentication and a rule on who can access port 27017 on our MongoDB server. First, do the following in the mongo shell:

use admin
db.createUser({
user: "<username>",
pwd: "<password>",
roles: [ "root" ]
});

Now like with Regex, it’s best to be as specific as possible, so for example, if your application only needs access to the “production_memes” database, then just create a user that has the role: { role: “readWrite”, db: “production_memes” }, of course, you still should create a root user for yourself, just don’t use it in the application.

Then we make sure MongoDB is always started with authentication. Find your MongoDB configuration (for me it’s /etc/mongodb.conf) file and add the following line:

auth = true

Now since you can also start mongodb via the “mongod” command, we should add the following in our .bashrc in case we accidentally start mongod from bash instead of systemctl start mongodb:

alias mongod='mongod --auth'

Now to use the mongo shell as root and “login” we just do:

use admin
db.auth("<username>", "<password>");

There we go! If you need to connect from mongoose for example, we would do:

mongodb://<username>:<password>@localhost:27017/<dbName>?authSource=admin

Remember to read the username and password from a file in another directory so that your application won’t accidentally expose it’s credentials if the source were to get leaked somehow.

Now let’s add the rule to our firewalld configuration to only accept traffic from the app’s main server:

firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="<your app server IP address>"
port protocol="tcp" port="27017" accept'
firewall-cmd --reload

Now I certainly did not cover all there is, so you should still check out the MongoDB Security Checklist. I hope this story taught you how easy it is to do these types of “attacks” and gave you a start on how to keep your MongoDB secure!

TL;DR, get a firewall (and set it up correctly), and enable authentication. Use good practices when coding applications that connect to mongo.