Categories
Software Technology

Boost the Security of a MySQL Database – Step by Step

MySQL is one of the most popular relational database management systems (RDBMS) around the world. Unfortunately, due to its popularity, people already know its weak points. A straight-out-of-the-box, freshly installed MySQL database can be vulnerable to many risks. To prevent attacks and security exploits, we must arm ourselves with knowledge about security improvements. So let’s start!

MySQL database

Chart 1. Database management systems according to their popularity.
September 2016, Source: http://db-engines.com/

You should be especially interested if you use the MySQL RDBMS. Dont worry – I will lead you through the most important security cases step by step.


1. Always run MySQL as a user without root privileges

Running database service as a Root is a bad practice. Firstly, you should create a new user account – with only the necessary permissions (e.g. appropriate permissions to the data directory) to run the service. After that, you should always run the MySQL server through this new user.
Running MySQL as Root means that everything the server does is also done with root privileges. If you happen to make a mistake, this can cause problems:

  • if you misconfigure the MySQL logfile to /etc/passwd, then that important file will probably be overwritten (a normal user cant do that)
  • Root usually has some amount of disk system reserved (per filesystem), therefore it’s more likely to fill the whole partition
  • code injection: if you have scripts running (for backup of the now Root-owned files) then you need higher privileges there, and – again – any mistake might have more grievous consequences

2. Make the MySQL root user account invisible

After the installation, the database’s grant tables are populated with default MySQL accounts.
Some accounts have the username: root. These are superuser accounts which have all the privileges. Basically, they can do everything. If these root accounts have empty passwords, anyone can connect to the MySQL server as root without a password and be granted all privileges. We have to prevent this!
Firstly, assign a password to each MySQL root account that doesnt have one.
Secondly, change the username of all root accounts to hard-to-guess names, because attackers have to provide the account name before trying to brute force the passwords.
This step will add an extra layer of security.

3. Delete all anonymous accounts

In addition to administrator accounts after installation, there are anonymous user accounts. They have no password, so anyone can use them to connect to the MySQL server. These accounts should be removed, because they give attackers an entry point in our database.

4. Recommended configuration tips

a) network access
Nowadays, were often in the situation where the database is running on the same server as a production application. This means we can connect to the MySQL server locally, without remote access. This remote option should be disabled to avoid the possibility of attacks from the outside.
We can do that by adding a skip-networking entry to the configuration file /etc/my.cnf (below the [mysqld] section).
Otherwise, when were running MySQL and application on separate servers, we should configure the MySQL server to give access only to allowed remote hosts. You can do this by making some changes in /etc/hosts.deny and /etc/hosts.allow files.

  • Make sure to check if your MySQL daemon is listening on remote accessible port only when it is needed. Create an appropriate firewall rule to allow connection to MySQL port only from trusted hosts.
  • In case youre using Amazon RDS as a MySQL service, check if your instance is attached to the correct security group. It is recommended to carry out some tests of connections from various remote hosts to check if your configuration is secure.
  • Set firewall rules with IP address instead of hostnames to protect yourself from DNS spoofing and similar attacks if you don’t trust your DNS. Don’t create firewall rules with wildcards.
  • In case of emergency, when you need direct access to the database to fix some issue, it is better to use the SSH tunnel instead of opening port to network or change firewall rules.
  • Check if your administrative accounts are accessible only from localhost. They should be.

 b) disable LOAD DATA LOCAL INFILE” command
Executing this allows users to read local files. This could be used by attackers through several methods, for example SQL Injection. Furthermore, they can access other files in the operating system. This can be dangerous.
This command should be disabled by adding:

set-variable=local-infile=0

to the configuration file /etc/my.cnf (below the [mysqld] section).
 
c) do not grant FILE privilege to non-administrative users
This privilege is dangerous because it allows users to write file anywhere in filesystem with privileges of mysqld daemon. It allows to modify contents of MySQLs data directory (including files that implements privilege table).
On the other hand, FILE privilege can be also used to execute LOAD DATA to read /etc/passwd or any other secret file to database table and then read it using SELECT.
I recommend to restrict access to the specified directory only by setting:

secure_file_priv=dirname

 d) do not grant PROCESS or SUPER privileges on non-administrative accounts
It is good to know the meaning of two dangerous privileges that should be set only for administrative accounts.
PROCESS privilege allows to display all currently executed SQL commands. These include vulnerable ones like setting new passwords to MYSQL users or setting new credentials by user in your web application. The list of processed queries is not limited to the currently logged user and is not encrypted.
SUPER privilege allows to change server system variables, terminate client connections, control replication servers and connect regardless of the connection limit.
 
e) disable or restrict a SHOW DATABASEScommand
TheSHOW DATABASEScommand allows users to see names of databases in our MySQL server.
If attackers are able to get the database names, they can easily get access to the data.
This command should be disabled or restricted on production server by adding:

skip-show-database

to the configuration file /etc/my.cnf (below the [mysqld] section).
 
f) change default port
By default, our MySQL server will run on port 3306. If we dont change this, attackers will try to use these initial values to get access to the database.
We should change this critical value immediately after installation to prevent dummy hacker attacks.

5. Delete the Test database

After installation, your server will have a ‘test’ database which was installed by MySQL Server package. This database can be accessed by all users by default. This is a security risk. It should be removed by running:

DROP DATABASE test;

6. Clear the MySQL history file and prevent logging to this file

This file contains historical details about initial configuration and installation. It may be exploited for getting passwords (for database users). Also, other data will be logged into this file while the MySQL server works. It’s located at ~/.mysql_history and should be deleted. We should also block logging to file by creating a softlink to the /dev/null device.

Conclusion

These are the most popular cases. Of course, there are more security threats. Remember to keep your operating system environment secure. If the entire environment is unsafe, all things in it are vulnerable and can be easily exposed to attackers.
MySQL provides a simple command to help proceed with most important security settings. This command is called:

mysql_secure_installation

It guides you through setting password for root account, removing of anonymous users, disabling root remote access, removing test database with related access rules. At the end, it flushes the privilege table. It is a quick command that should be run right after mysql daemon installation.
If you want to know more about securing or configuring the MySQL server – check out the following links.
Sources and more information:
[1] http://db-engines.com/en/ranking_trend
[2] https://dev.mysql.com/doc/refman/5.5/en/default-privileges.html

[3] https://besthostingsearch.org/tutorial/secure-mysql-databases-against-attackers/
[4] http://technotif.com/hardening-mysql-security-server/

Authors:
Mateusz Palichleb, Filip Chmarzyński

Categories
Design Software

[Infographic] Why a Product Owner is Better Than a CTO

We’ve written a longer article on why having a CTO is greatly overrated when it comes to both current and new product development. Startups simply need a PO much more. We’d like to show you the main arguments on a handy infographic.

New product development with a PO

A Product Owner is an indispensable part of Agile processes. It is his or her responsibility to consider which activities will produce the most business value. In short, a PO provides direction: and functions as the link between the team and the CEO and investors. The CTO usually determines the how, however, the results may not always be stellar.

At Espeo, we’ve completed a number of projects with companies with no CTO. We’re actually still working on some, helping them scale up. I’d recommend a look at examples. And as always, your thoughts and comments are welcome!
Infographic. Why a product owner is better than a CTO?
 

Categories
Software Technology

Using DataTables – Simple and Fast Data Listing

Looking for something to speed up your work with tables? You can use a simple jQuery plugin named DataTables. It’s a highly flexible tool that adds advanced interaction controls to any HTML table. I’ll show you how to use it.

Problem: sometimes working with lists (such as product lists) just takes too long. Everything is done on the server side and the page needs to reload every time. What’s more, we often need to present data in an elegant way. Usually, developers build their own tables with additional functionalities like sorting, filtering or searching – processed mainly on server-side. However, building this from scratch takes some time.
Solution: With DataTables, it’s enough to write a module in the backend that will supply data to this plugin, and then the pagination, sorting, searches will be handled by the plugin in the background – no reloading. Furthermore, this plugin has a growing community and extensive documentation. Additionally, it can be used in another project, and the look and style of the plugin can be changed.
 
DataTables’ most interesting features :

  • Instant search, pagination, multi-column ordering
  • Supports many data sources like: Ajax, Javascript, JSON, Server-side processing
  • Detection and building of own events
  • Security module – for example, using CSRF-token in requests or prevention of XSS attacks
  • Plenty of extensions and plugins like internationalization, API engine to fetch and manipulate columns and rows, type detection, rendering (transforming data into another format)

 
Let’s get to the practical part!
 

Requirements

DataTables has only one library dependency – jQuery. Being a jQuery plugin, DataTables makes use of many of features that jQuery provides.
 

Installation

Let’s start with installation. There are different ways to do it: through CDN, locally, using NPM or Bower. In this example, I chose Bower:

The first package is the core library of DataTables. The second one contains extensions and styling integration options.
 

HTML initial structure

Firstly, we must create a table: a well formatted HTML with a header and body, optionally with footer.

 

Initializing script

If we’ve got all the required libraries and files we need, the last thing to do is tell DataTables to work on this html table.

That’s all! In the result, we have a table that contains default styled rows, sortable headers, search field and pagination options.
Example below:
1

Using options

Now, we want to customize the way that DataTables presents its interface and features to the end user. We can use a huge range of options. In this example, we want to change the default ordering of columns, disable search, and display only numbers without “prev” and “next” buttons in the pagination:

Result below:
2
There are many more interesting options you can use to customize this table.
You can also load table data directly from files. Try it yourself with examples from the DataTables documentation.
 

Styling

Furthermore, we can change styles (DataTables stylesheet is written in SCSS) or enable embedded integration with Bootstrap, Foundation and jQuery UI.
There is also a online Theme Creator, making styles very easy to customise!
Example:
3
If you want to use nice-looking themes for DataTables, take a look at Theme Forest templates. These have DataTables support built in.
 

Server-side processing

What would be a good table plugin that doesn’t fetch data from the server? A very important issue of DataTables is the possibility to use Server-side processing.
Let me show you how to use it.
First, we have to know how the Request and Response looks. We can find it in the documentation:
Sent parameters
Returned data (JSON)
The request parameters will be prepared through DataTables, depending on the page, search field, sort headers and more. All you have to do is set the ‘serverSide’ flag as ‘true’ and choose URL to the server. Optionally – type of request, ‘POST’ method in this case.

After that, whenever you use any of the control buttons (pagination, etc.) the DataTable will send a request to the server and expect a JSON response with data.
We can also customize sending parameters and data returned though the use of ajax.dataFilter option. It may be useful when we don’t want to (or can’t) change the server-side.
Example below:

 

Internationalization

There are two solutions for loading language information into DataTable:
– As a initialization option, “language”, which could be object with all sentences we want to translate (example here)
– As a remote file loaded via Ajax (list of all available languages here)
Example with Polish (pl_PL.json)

 

Security

As I told you at the beginning, there are some security tools embedded into DataTables.
For example, we can prevent two attack types:
Cross-Site Request Forgery (CSRF)
Cross-Site Scripting (XSS)
To prevent the second one (XSS) on browser-side you can use a rendering function to block or replace all writes that contain harmful data before generating the table. These functions can be used by assigning them to columns.render option.

To prevent the first one (CSRF) most server-side systems use a token, which has to be submitted on each data request to ensure that the end-user is authenticated.
In DataTables, we can attach this token to headers, data or global Ajax header. There are many ways the server-side can expect the CSRF token.
 

Method 1 – token is attached to data:


 

Method 2 – token is attached to global header:


 

Method 3 – token is attached to data headers:


 

A similar plugin to do it the Angular way

If you’re using the Angular framework, there may be some problems with DataTables integration. Fortunately, there is a solution!
A interesting plugin for Angular 2 was created by our programmer Sebastian. It’s named ‘Angular2 Easy Table‘ with similar functionalities to jQuery DataTables. Check it out!

Categories
Software Technology

How to Build a Development Environment with Docker

Building a reliable and comfortable development environment is not an easy task. Running multiple versions of the same software might be a bit tricky. This post shows how to build an awesome development environment with Docker.

MySQL Docker


Docker is an open-source platform that automates the development of applications inside software containers.
What are the advantages of using an external tool to manage software on a development machine?

  • running multiple versions. Usually only a single version of the application can be found in package manager. Very often, it’s not the latest version. Example: there’s no Oracle MySQL package in the ArchLinux packages repository.
  • saving time spent on compiling an application from sources. Managing multiple versions of the same software is time-consuming.
  • avoiding dependency hell. You can use a few versions of the application without introducing any dependency compatibility issues.
  • reliability. Official Docker images are more reliable than third party repositories.

Using Docker to install multiple versions of MySQL

MySQL has been used as an example in this post, but the process is almost the same for any kind of software. You can find the details about the official MySQL Docker images at the Docker Hub page.
You’ll need the following dependencies to achieve our goal:

  • Docker
  • systemd or equivalent
  • (optional) a build tool (GNU Make would match the requirements perfectly) – this
    example uses simple shell scripts.

The first step is to create a directory where the configuration files will be stored. A home directory will be a good choice:
mkdir -p ~/.docker/mysql/{5.6,5.7} (the location of the ). Two MySQL versions will be used as an example: 5.6 & 5.7.
Every container requires a Dockerfile, so creating those is the second step: touch ~/.docker/mysql/{5.6,5.7}/Dockerfile.
You can open Dockerfiles using any text editor: emacs, vim, gedit and so on.
~/.docker/mysql/5.6/Dockerfile

FROM mysql:5.6
ENV MYSQL_ALLOW_EMPTY_PASSWORD true
VOLUME /var/lib/mysql/5.6
EXPOSE 3306
CMD ["mysqld"]

~/.docker/mysql/5.7/Dockerfile

FROM mysql:5.7
ENV MYSQL_ALLOW_EMPTY_PASSWORD true
VOLUME /var/lib/mysql/5.7
EXPOSE 3307
CMD ["mysqld"]

Some explanation of the Dockerfiles content:

  • FROM specifies the image name & image tag used in the following format: name:tag
  • ENV sets a environment variable. In this example, an empty root user password is allowed.
  • VOLUME sets the location of mounted volume as database files should be stored on the host machine.
  • EXPOSE determines the port number that will be available from the container host.
  • CMD sets up the default entry point.

As we’re using multiple versions of MySQL, the volume path and exposed port number both need to be customized. This isn’t necessary if you’re using single instance.
After the Dockerfiles are ready, an automation tool will be required to build and run the containers. This example uses simple shell scripts, but any build tool can be used: touch ~/.docker/mysql/{5.6,5.7}/build.sh.
~/.docker/mysql/5.6/build.sh

#!/bin/bash
docker stop mysql-5.6
docker rm mysql-5.6
docker build -t mysql-5.6 .
docker run -d \
	-p 3306:3306 \
	-v /srv/mysql:/var/lib/mysql \
	--name mysql-5.6 \
	mysql-5.6
docker start mysql-5.6

~/.docker/mysql/5.7/build.sh

#!/bin/bash
docker stop mysql-5.7
docker rm mysql-5.7
docker build -t mysql-5.7 .
docker run -d \
	-p 3306:3306 \
	-v /srv/mysql:/var/lib/mysql \
	--name mysql-5.7 \
	mysql-5.7
docker start mysql-5.7

Some details about the build scripts:

  • docker stop command stops any running the container named mysql-5.6 or mysql-5.7
  • docker rm removes any existing container with the specified name
  • docker build builds a new image with the specified tag – in this example mysql-5.6 or mysql-5.7
  • docker run runs a container using a previously created image
  • docker start starts the newly created container

MySQL Docker – Almost there…

At this stage, MySQL Docker containers are fully functional and accessible from the host machine. They store MySQL user home directory on the host. There’s one issue with the containers – they do not start on the system boot. To start them, an init system or a cron job might be used. In this post, I’ll use systemd.
/etc/systemd/system/mysql-5.6.service

[Unit]
Description=MySQL 5.6 Docker container
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/bin/docker start -a mysql-5.6
ExecStop=/usr/bin/docker stop -t 2 mysql-5.6
[Install]
WantedBy=multi-user.target

/etc/systemd/system/mysql-5.7.service

[Unit]
Description=MySQL 5.7 Docker container
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/bin/docker start -a mysql-5.7
ExecStop=/usr/bin/docker stop -t 2 mysql-5.7
[Install]
WantedBy=multi-user.target

These newly created service units depend on Docker service. The services will always start after the docker service has been started. To start on system boot, you should enable the following services:

sudo systemctl enable mysql-5.6.service
sudo systemctl enable mysql-5.7.service

Now both MySQL containers should be started after system boot.
You can use this method as a replacement for the default system packages. Personally, I use it on all my development machines to install software that isn’t available in the system package repositories. I also use it to run multiple versions of the same server (PostgreSQL, MySQL, MongoDB, etc) for all non-dockerized applications I work on.
Why don’t you also check out our Introduction to Docker presentation?