SecuringSecuring
MySQL ServersMySQL Servers
Marian Marinov <mm@yuhu.biz>OSTconf Moscow
Who am I?
:)
Why would you need to 
secure your mysql 
installations?
Why?Why?
➢ Passwords stored in plain text
➢ E-Mail addresses
➢ Physical addresses
➢ Phone numbers
➢ Transaction information
➢ Sessions
➢ etc.
Passwords ought to be Passwords ought to be 
hashed in the DB... hashed in the DB... 
But this is not always But this is not always 
the case :(the case :(
Hashing had to be Hashing had to be 
implemented with implemented with 
bcrypt...bcrypt...
But they were But they were 
implemented with MD5 implemented with MD5 
without salt or all with without salt or all with 
the same salt.the same salt.
Sensitive data should be Sensitive data should be 
symmetrically encryptedsymmetrically encrypted
Problems:Problems:
­ emails ending with ­ emails ending with @tmp.com@tmp.com
­ phones starting with ­ phones starting with +4911+4911
­ addr. starting with ­ addr. starting with PatternPattern
Not so obvious locations for Not so obvious locations for 
sensitive data:sensitive data:
➢  logslogs
➢  temporary datatemporary data
➢  actual data directories (LOAD DATA)actual data directories (LOAD DATA)
➢  SELECT ... INTO OUTFILESELECT ... INTO OUTFILE
Now let's focus on the Now let's focus on the 
securing part of this talk :)securing part of this talk :)
Sensitive data in logsSensitive data in logs
➢  binary.logbinary.log ­ log_bin (bool) ­ log_bin (bool)
➢  log_bin_basenamelog_bin_basename
➢  relay.logrelay.log ­ relay_log (bool) ­ relay_log (bool)
➢  relay_log_basenamerelay_log_basename
➢  general.loggeneral.log ­ general_log (bool) ­ general_log (bool)
➢  general_log_filegeneral_log_file
➢  error.logerror.log ­ log_error (bool) ­ log_error (bool)
➢  log_error_verbosity (3)log_error_verbosity (3)
➢  log_statements_unsafe_for_binloglog_statements_unsafe_for_binlog
Sensitive data in logsSensitive data in logs
➢  slow.logslow.log ­ slow_query_log (bool) ­ slow_query_log (bool)
➢  slow_query_log_fileslow_query_log_file
➢  log_slow_admin_statementslog_slow_admin_statements
➢  log_slow_slave_statementslog_slow_slave_statements
➢  long_query_timelong_query_time
Sensitive data in Sensitive data in 
temporary folderstemporary folders::
➢  tmpdirtmpdir  
➢  temporary tablestemporary tables
➢  any temp dataany temp data
➢  innodb_tmpdirinnodb_tmpdir
➢  temp sort files temp sort files 
➢  slave_load_tmpdirslave_load_tmpdir
➢  replicationreplication
➢  LOAD DATALOAD DATA
Sensitive data in the data Sensitive data in the data 
directories – LOAD DATA/XMLdirectories – LOAD DATA/XML
local_infilelocal_infile
One can use the LOAD One can use the LOAD 
DATA/XML statement to DATA/XML statement to 
actually read your binary actually read your binary 
data files into tables...data files into tables...
secure_file_privsecure_file_priv
The FILE privilege...The FILE privilege...
Sensitive data in the data Sensitive data in the data 
directoriesdirectories
    SELECT ... INTO OUTFILESELECT ... INTO OUTFILE
Create new files:Create new files:
    init_fileinit_file, , local_infilelocal_infile  
andand my.cnf my.cnf
    secure_file_privsecure_file_priv  && && FILEFILE
Chrooting the MySQL Chrooting the MySQL 
daemondaemon
 chroot=/var/lib/mysql chroot=/var/lib/mysql
Chrooting will:Chrooting will:
➢ restrict FS access to the chroot dir
➢ prevent read/write to system files
➢ require SSL certs in the chroot dir
➢ restrict, where the temporary files can be
created
➢ restrict the pid and log file locations
Firewalling the MySQLFirewalling the MySQL
➢ DO NOT PUT MySQL on unrestricted public
interfaces
# iptables -N mysql
# iptables -A mysql -j ACCEPT -s IP_1
# iptables -A mysql -j ACCEPT -s NET_1
# iptables -A mysql -j DROP
# iptables -A INPUT -j mysql -p tcp --dport 3306
Firewalling the MySQLFirewalling the MySQL
➢ Only disallow specific user (app_userapp_user)
# iptables -A OUTPUT -j DROP -p tcp --dport 3306 -m
owner ! --uid-owner app_userapp_user
Firewalling the MySQLFirewalling the MySQL
➢ or more then one user, but not everyone:
# iptables -N mysql_out
# iptables -A mysql_out -j ACCEPT -m owner --uid-owner
app_user1app_user1
# iptables -A mysql_out -j ACCEPT -m owner --uid-owner
app_user2app_user2
# iptables -A mysql_out -j DROP
# iptables -I OUTPUT -j mysql_out -p tcp --dport 3306
Firewalling the MySQLFirewalling the MySQL
➢ or you want only one specific user, to be
restricted from MySQL
# iptables -A OUTPUT -j DROP -p tcp --dport 3306 -m
owner --uid-owner dev_user1dev_user1
Access to the MySQL Access to the MySQL 
socketsocket
The effects of:The effects of:
# chmod 600 /var/lib/mysql/mysql.sock# chmod 600 /var/lib/mysql/mysql.sock
- Only root & mysql have access to it- Only root & mysql have access to it
- restrict all users- restrict all users
- use sudo for devs- use sudo for devs
dev_user1 ALL=(mysql) PASSWD:/usr/bin/mysqldev_user1 ALL=(mysql) PASSWD:/usr/bin/mysql
The socket protection:The socket protection:
Your app needs access to the socket, so:Your app needs access to the socket, so:
# groupadd# groupadd web_appweb_app
# usermod -a -G# usermod -a -G web_appweb_app mysqlmysql
# usermod -a -G# usermod -a -G web_appweb_app app_userapp_user
# chmod 660 /var/lib/mysql/mysql.sock# chmod 660 /var/lib/mysql/mysql.sock
# chgrp# chgrp web_appweb_app /var/lib/mysql/mysql.sock/var/lib/mysql/mysql.sock
MySQL authenticationMySQL authentication
➢ never leave a user without a password
➢ try not use the % in the host part of an account
➢ hostnames instead of IPs for user
authentication and set skip_name_resolve
➢ do not set old_passwords=0
➢ (pre mysql 4.1, hashing func. was producing
16bytes hash string)
secure_auth is used to control if 
old_passwords=1(pre 4.1 hashing) can 
be used by clients
After 5.6.5, secure_auth is enabled 
by default
MySQL authenticationMySQL authentication
MySQL authenticationMySQL authentication
mysql> SELECT PASSWORD('mypass');mysql> SELECT PASSWORD('mypass');
+--------------------++--------------------+
| PASSWORD('mypass') || PASSWORD('mypass') |
+--------------------++--------------------+
| 6f8c114b58f2ce9e || 6f8c114b58f2ce9e |
+--------------------++--------------------+
- try to avoid the mysql_native_password plugin(which- try to avoid the mysql_native_password plugin(which
produces 41bytes hash string)produces 41bytes hash string)
mysql> SELECT PASSWORD('mypass');mysql> SELECT PASSWORD('mypass');
+-------------------------------------------++-------------------------------------------+
| PASSWORD('mypass') || PASSWORD('mypass') |
+-------------------------------------------++-------------------------------------------+
| *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 || *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
+-------------------------------------------++-------------------------------------------+
The mysql­unsha1 attack 
y = SHA1(password)
On every connection the server sends
a salt(s) and the client computes a
session token(x)
x = y XOR SHA1(s + SHA1(y) )
the server will verify it with:
SHA1(x XOR SHA1(s + SHA1(y) )) =
SHA1(y)
MySQL authenticationMySQL authentication
Now if you can sniff the salt(x) and 
have access to the SHA1(password), 
you don't need the password :)
MySQL authenticationMySQL authentication
Finally, the security of the hashed 
passwords...
On 12th of Jun this year, Percona 
published this blog post
➢ 8 chars cracked for 2h and less 
then 20$
➢ 8 chars for 2.8y if you use 
sha256 auth plugins
  
MySQL authenticationMySQL authentication
You may also want to consider moving 
your authentication out of MySQL.
For example on external LDAP server 
or using PAM.
MySQL authenticationMySQL authentication
➢ SUPER
➢ REPLICATION
➢ CLIENT
➢ SLAVE – can dump all of your data
➢ FILE – can read and write on the 
FS
Account securityAccount security
Now let's go over some Now let's go over some 
options, that I consider options, that I consider 
related to securityrelated to security
➢  chroot (we already covered that one)chroot (we already covered that one)
 old_passwords & secure_auth (we already  old_passwords & secure_auth (we already 
covered these)covered these)
 local_inifile & init_file local_inifile & init_file
 plugin­dir plugin­dir
 skip­grant­tables skip­grant­tables
 skip_networking skip_networking
 skip_show_database skip_show_database
  secure_file_privsecure_file_priv
 safe­user­create safe­user­create
  allow­suspicious­udfsallow­suspicious­udfs
  automatic_sp_privilegesautomatic_sp_privileges
 tmpdir = save_load_tmpdir tmpdir = save_load_tmpdir
 default_tmp_storage_engine  default_tmp_storage_engine 
 internal_tmp_disk_storage_engine internal_tmp_disk_storage_engine
MySQL SQL SecurityMySQL SQL Security
➢ SQL SECURITY
➢ DEFINER vs. INVOKER
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1()
SQL SECURITY DEFINERDEFINER
BEGIN
UPDATE t1 SET counter = counter + 1;
END;
➢ Triggers and evnets are always executed with
definer's context
Data encryption at restData encryption at rest
    In 2016, both In 2016, both MariaDBMariaDB  
and and PerconaPercona published  published 
information on how to information on how to 
encrypt your DB.encrypt your DB.
  This comes built­in in   This comes built­in in 
MySQL 5.7MySQL 5.7..
Disk encryption in MySQL Disk encryption in MySQL 
is supported ONLY by is supported ONLY by 
InnoDB and XtraDBInnoDB and XtraDB
storage enginesstorage engines
Other limitationsOther limitations
➢ Galera gcache is not encrypted
➢ .frm files are not encrypted
➢ mysqlbinlogs can no longer read the files
➢ Percona XtraBackup can't backup encrypted
data
➢ Audit plugin can't create encrypted output
➢ general and slow logs, can't be encrypted
➢ error.log is not encrypted
However I prefer using However I prefer using 
ecryptfs  r LUKS, so I оecryptfs  r LUKS, so I о
can keep all the data can keep all the data 
and logs encrypted, not and logs encrypted, not 
only the data inside the only the data inside the 
MySQL DataBasesMySQL DataBases
QuestionsQuestions
Marian Marinov <mm@yuhu.biz>OSTconf Moscow

Securing your MySQL server