Securing your Web Application Database
By: Bernhard Schandl
Tags: AWS, Security, Database, Software Development, MySQL

Chances are high that if you are operating a Web application, you will also need to operate a database. If you, like we do, run your infrastructure on Amazon Web Services, there are a number of options to choose from. You can deploy any database on an EC2 instance (which then you will have to administer by yourselves), or you can use RDS and make use of Amazon’s management services. At mySugr, we choose to use RDS and save the time and effort it takes to keep a database server up and running.

Risks

Regardless of which model you choose, you will need to make sure your database is secure. If your application has a certain level of traffic, you will very likely not be able to run your application and the database on the same (physical or virtual) machine. That means, your application will need to connect to a remote database, and this has some implications:

Your database host needs to be reachable from your application servers.

Your application servers need to know the credentials that they need to connect.

There is some traffic going over a network that contains data. In our case, this is highly sensitive medical and personal data.

Operating such a setup brings some security risks. You don’t want anyone to have access to your database (likely, it contains sensitive information like user data and password hashes), and you do not want someone to eavesdrop the traffic between your application servers and your database. Eventually, someone breaking into your system may lead to your user’s data being leaked, altered, or deleted, which will bring you into serious trouble.

Let’s take a closer look at what the most critical elements of this part of your application are: access to the network traffic between your app server and the database, access to your database host on the network level, and access to the database itself (which will require having the database credentials).

Obviously, you don’t want someone to listen to the traffic between your application servers and your database. This traffic will not only contain your user data, but also authentication information. Since it is “internal” traffic, it will also give someone the ability to learn about how your database is structured.

If an attacker is able to physically connect to your database server, they probably will not be able to get data out of this. Still, it opens the possibility to cause harm, like Denial-of-Service attacks (which may bring your application down), or brute-forcing database credentials.

Your database credentials (i.e., the username and password that your application uses to connect to the database) are one of the most critical pieces of information in your infrastructure. In combination with physical access to the database, an attacker might be able to read data, or (even worse) modify or delete data in your database. I think we don’t have to discuss the potential negative effects of such a situation.

What You Can Do

So, how can we protect our infrastructure and avoid such situations? There are a couple of things we can do if your infrastructure (like ours) is running on Amazon Web Services. (If it isn’t, you probably need to adapt to your environment.)

To avoid the risk of someone eavesdropping your network traffic, you should always encrypt it. How to configure transport-layer encryption depends on the database you are using. In our case, for MySQL, SSL support is already provided and can be easily enabled via configuration. If you are using MySQL on Amazon’s RDS, SSL support comes out of the box — no extra steps needed.

To prevent someone from connecting to your database (which, obviously, needs to allow for incoming connections), it’s certainly a good idea to move all your infrastructure into a private network. Amazon provides an excellent mechanisms to do so: Virtual Private Cloud (VPC) allows you to segregate your network into sub-networks and to control the traffic that is allowed between these networks. Additionally, Security Groups (a feature of VPC) act like a firewall and allow you to permit or deny incoming traffic on the host level. We’ll cover the details how to configure VPC and Security Groups in a separate blog post.

Finally, it’s good to invest some time thinking about where and how you store your database credentials. You may be thinking, “Hard-coded in your source code repository?” Maybe not, since this may spread quite quickly. If you’re using Amazon’s Elastic Beanstalk, you could store the credentials in the environment software configuration. Again, this is not particularly secure as they can be read by everyone who has access to that AWS service. Also, the credentials would be included in plain-text in any CloudFormation template that you generate out of an existing environment. In general, it’s not a good idea to pass database credentials as command-line parameters to your service, since they may appear in log output or in the process list.

Whatever you solution you choose to store your credentials, it will be quite tricky to implement one mechanism that is always considered good practice, which is to change your credentials frequently (also known as password rotation). Fortunately, AWS offers a great solution to this problem: if you are using RDS with MySQL or Aurora, you can couple database accounts to IAM accounts and use access tokens provided through an EC2 instance role. These tokens are used instead of the database password when connecting, and are valid for 15 minutes. Again, we’ll show the details how to setup IAM authentication in a separate blog post.

So, to summarize, there are a few things to consider in order to protect your database resources. First, you should make sure that traffic between your application and your database is always encrypted. Second, you should ensure that your database cannot be reached from the public Internet by putting it into a private network. Third, you should carefully consider options how to store your database credentials securely, or use some other form of authentication that does not require storing credentials