SECURITY AND USER MANAGEMENT IN MySQL.
SECURITY RISKS IN MySQL.
When thinking about security within a MySQL installation, you should consider a wide range of possible topics and how they affect the security of your MySQL server and related applications:
- Comes with multiple users or internet connections.
- Must fully protect the entire server host ,not just MySQL.
- Many types of security “attackts”.
- MySQL uses ACLs based security.
–Also support for SSL-encrypted connections.
- MySQL security risks come in many forms.
–Network security risks.
–Operating system security risks.
–FiIesystem security risks.
Secure MySQL Installation
This is the first recommended step after installing MySQL server, towards securing the database server. This script facilitates in improving the security of your MySQL server by asking you to:
- set a password for the root account, if you didn’t set it during installation.
- disable remote root user login by removing root accounts that are accessible from outside the local host.
- remove anonymous-user accounts and test database which by default can be accessed by all users, even anonymous users.
1 |
root@ip-172-31-14-134:~# mysql_secure_installation |
After running it, set the root password and answer the series of questions by entering [Yes/Y] and press [Enter].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MySQL to secure it, we'll need the current password for the root user. If you've just installed MySQL, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MySQL root user without the proper authorisation. You already have a root password set, so you can safely answer 'n'. Change the root password? [Y/n] y New password: Re-enter new password: Password updated successfully! Reloading privilege tables.. ... Success! By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist ... Failed! Not critical, keep moving... - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! All done! If you've completed all of the above steps, your MySQL installation should now be secure. Thanks for using MySQL! Cleaning up... |
Change MYSQL Default Port
The Port variable sets the MySQL port number that will be used to listen on TCP/ IP connections. The default port number is 3306 but you can change it under the [mysqld] section as shown.
1 |
Port=5000 |
Disable LOCAL INFILE in MySQL
As part of security hardening, you need to disable local_infile to prevent access to the underlying filesystem from within MySQL using the following directive under [mysqld]
section.
1 |
local-infile=0 |
Enable MySQL Logging
Logs are one of the best ways to understand what happens on a server, in case of any attacks, you can easily see any intrusion-related activities from log files. You can enable MySQL logging by adding the following variable under the [mysqld]
section.
1 |
log=/var/log/mysql.log |
Set Appropriate Permission on MySQL Files
Ensure that you have appropriate permissions set for all mysql server files and data directories. The /etc/my.conf file should only be writeable to root. This blocks other users from changing database server configurations.
1 |
# chmod 644 /etc/my.cnf |
Delete MySQL Shell History
All commands you execute on MySQL shell are stored by the mysql client in a history file: ~/.mysql_history. This can be dangerous, because for any user accounts that you will create, all usernames and passwords typed on the shell will recorded in the history file.
1 |
# cat /dev/null > ~/.mysql_history |
Don’t Run MySQL Commands from Command line.
As you already know, all commands you type on the terminal are stored in a history file, depending on the shell you are using (for example ~/.bash_history for bash). An attacker who manages to gain access to this history file can easily see any passwords recorded there.
It is strongly not recommended to type passwords on the command line, something like this:
1 2 |
root@ip-172-31-14-134:~# mysql -uroot -pROOT Enter password: |
When you check the last section of the command history file, you will see the password typed above.
1 |
# history |
1 2 |
root@ip-172-31-14-134:~# mysql -uroot -p Enter password: |
Define Application-Specific Database Users
For each application running on the server, only give access to a user who is in charge of a database for a given application. For example, if you have a wordpress site, create a specific user for the wordpress site database as follows.
1 2 3 4 5 6 7 8 9 10 11 12 |
root@ip-172-31-14-134:~# mysql -uroot -p -e "show databases" Enter password: +--------------------+ | Database | +--------------------+ | information_schema | | db1 | | db3 | | mysql | | performance_schema | | world | +--------------------+ |
Use Additional Security Plugins and Libraries
MySQL includes a number of security plugins for: authenticating attempts by clients to connect to mysql server, password-validation and securing storage for sensitive information, which are all available in the free version.
You can find more here: https://dev.mysql.com/doc/refman/5.7/en/security-plugins.html
Change MySQL Passwords Regularly
This is a common piece of information/application/system security advice. How often you do this will entirely depend on your internal security policy. However, it can prevent “snoopers” who might have been tracking your activity over an long period of time, from gaining access to your mysql server.
1 2 3 |
<span style="font-family: ProximaNovaBold, 'Helvetica Neue', Helvetica, Arial, sans-serif;"><b>mysql></b></span>USE mysql; <strong>mysql></strong> UPDATE user SET password=PASSWORD('<strong>YourPasswordHere</strong>') WHERE User='root' AND Host = 'localhost'; <strong>mysql></strong> FLUSH PRIVILEGES; |
Update MySQL Server Package Regularly
It is highly recommended to upgrade mysql/mariadb packages regularly to keep up with security updates and bug fixes, from the vendor’s repository. Normally packages in default operating system repositories are outdated.
1 2 |
# yum update # apt update |
After making any changes to the mysql/mariadb server, always restart the service.
1 |
# systemctl restart mysql #Debian/Ubuntu |
MySQL Server User Security
Setting up proper accounts and privileges is imperative.
User security consists of 5 levels of account access privileges.
- Level 1 –USER
- Level 2 –DB
- Level 3 –TABLES
- Level 4 –COLUMNS
- Level 5 –PROCS
How to create a user :
We need to grant privileges to the new user which we have created because the new user would not have privileges. We can use GRANT statement to grant privileges to the user account. Its syntax would be as follows:
1 2 3 4 5 |
GRANT privilege,[privilege],.. ON privilege_level TO user [IDENTIFIED BY password] [REQUIRE tsl_option] [WITH [GRANT_OPTION | resource_option]]; |
Explanation of the above syntax is as follows:
First, specify one or more privileges after the GRANT keyword. If we grant the user multiple privileges, each privilege is separated by a comma.
Next, specify the privilege_level that determines the level at which the privileges apply. MySQL supports global ( *.*), database ( database.*), table ( database.table) and column levels. If we use column privilege level, we must specify one or a list of the comma-separated column after each privilege.
Then, place the user that we want to grant privileges. If the user already exists, the GRANTstatement modifies its privilege. Otherwise, the GRANT statement creates a new user. The optional clause IDENTIFIED BY allows us to set a new password for the user.
After that, we specify whether the user has to connect to the database server over a secure connection such as SSL, X059, etc.
Finally, the optional WITH GRANT OPTION clause allows us to grant other users or remove from other users the privileges that we possess. In addition, we can use the WITH clause to allocate MySQL database server’s resource e.g., to set how many connections or statements that the user can use per hour. This is very helpful in the shared environments such as MySQL shared hosting.
Example:
In the example below we are creating a user and granting privileges to it:
1 2 3 4 |
<span class="pln">mysql</span><span class="pun">></span> <span class="kwd">use</span><span class="pln"> mysql </span><span class="typ">Database</span><span class="pln"> changed mysql</span><span class="pun">></span><span class="pln"> create user abcd@localhost identified </span><span class="kwd">by</span> <span class="str">'password123'</span><span class="pun">;</span> <span class="typ">Query</span><span class="pln"> OK</span><span class="pun">,</span> <span class="lit">0</span><span class="pln"> rows affected </span><span class="pun">(</span><span class="lit">0.04</span><span class="pln"> sec</span><span class="pun">)</span> |
The query below will give us the privileges for the new user account abcd@localhost.
1 2 3 4 5 6 7 |
<span class="pln">mysql</span><span class="pun">></span><span class="pln"> SHOW GRANTS FOR abcd@localhost</span><span class="pun">;</span> <span class="pun">+------------------------------------------+</span> <span class="pun">|</span> <span class="typ">Grants</span> <span class="kwd">for</span><span class="pln"> abcd@localhost </span><span class="pun">|</span> <span class="pun">+------------------------------------------+</span> <span class="pun">|</span><span class="pln"> GRANT USAGE ON </span><span class="pun">*.*</span><span class="pln"> TO </span><span class="str">'abcd'</span><span class="pun">@</span><span class="str">'localhost'</span> <span class="pun">|</span> <span class="pun">+------------------------------------------+</span> <span class="lit">1</span><span class="pln"> row </span><span class="kwd">in</span> <span class="kwd">set</span> <span class="pun">(</span><span class="lit">0.01</span><span class="pln"> sec</span><span class="pun">)</span> |
Now, to grant all the privileges to the abcd@localhost user account, we can use the following statement:
1 2 |
<span class="pln">mysql</span><span class="pun">></span><span class="pln"> GRANT ALL ON </span><span class="pun">*.*</span><span class="pln"> TO </span><span class="str">'abcd'</span><span class="pun">@</span><span class="str">'localhost'</span><span class="pln"> WITH GRANT OPTION</span><span class="pun">;</span> <span class="typ">Query</span><span class="pln"> OK</span><span class="pun">,</span> <span class="lit">0</span><span class="pln"> rows affected </span><span class="pun">(</span><span class="lit">0.05</span><span class="pln"> sec</span><span class="pun">)</span> |
Here, the ON *.* clause means all databases and all objects in the databases. The WITH GRANT OPTION allows abcd@localhost to grant privileges to other users.
Now if we will use the SHOW GRANTS statement again, we will see that the privileges of abcd@localhost have been updated.
1 2 3 4 5 6 7 |
<span class="pln">mysql</span><span class="pun">></span><span class="pln"> SHOW GRANTS FOR abcd@localhost</span><span class="pun">;</span> <span class="pun">+---------------------------------------------------------------------+</span> <span class="pun">|</span> <span class="typ">Grants</span> <span class="kwd">for</span><span class="pln"> abcd@localhost </span><span class="pun">|</span> <span class="pun">+---------------------------------------------------------------------+</span> <span class="pun">|</span><span class="pln"> GRANT ALL PRIVILEGES ON </span><span class="pun">*.*</span><span class="pln"> TO </span><span class="str">'abcd'</span><span class="pun">@</span><span class="str">'localhost'</span><span class="pln"> WITH GRANT OPTION </span><span class="pun">|</span> <span class="pun">+---------------------------------------------------------------------+</span> <span class="lit">1</span><span class="pln"> row </span><span class="kwd">in</span> <span class="kwd">set</span> <span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span> |
To Check user privileges
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
mysql> select * from mysql.user limit 1 \G *************************** 1. row *************************** Host: localhost User: root Password: *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B Select_priv: Y Insert_priv: Y Update_priv: Y Delete_priv: Y Create_priv: Y Drop_priv: Y Reload_priv: Y Shutdown_priv: Y Process_priv: Y File_priv: Y Grant_priv: Y References_priv: Y Index_priv: Y Alter_priv: Y Show_db_priv: Y Super_priv: Y Create_tmp_table_priv: Y Lock_tables_priv: Y Execute_priv: Y Repl_slave_priv: Y Repl_client_priv: Y Create_view_priv: Y Show_view_priv: Y Create_routine_priv: Y Alter_routine_priv: Y Create_user_priv: Y Event_priv: Y Trigger_priv: Y Create_tablespace_priv: Y ssl_type: ssl_cipher: x509_issuer: x509_subject: max_questions: 0 max_updates: 0 max_connections: 0 max_user_connections: 0 plugin: mysql_native_password authentication_string: password_expired: N 1 row in set (0.00 sec) |
Thank you for giving your valuable time to read the above information. Please click here to subscribe for further updates
KTEXPERTS is always active on below social media platforms.
Facebook : https://www.facebook.com/ktexperts/
LinkedIn : https://www.linkedin.com/company/ktexperts/
Twitter : https://twitter.com/ktexpertsadmin
YouTube : https://www.youtube.com/c/ktexperts
Instagram : https://www.instagram.com/knowledgesharingplatform
best hosting
Desire to say your article is really as amazing simply. The clarity in your
post is just cool and i can assume you are a specialist on this subject matter.
Well with your permission i want to to seize your RSS feed to keep updated
with forthcoming post. Thanks a lot a million and please carry on the
gratifying work.