Locking Down
Your MySQL
Database
Server
@stoker David.Stokes@Percona.com
1
Open Source Advocate
MySQL Community Team 11 years
Author of MySQL & JSON - A Practical Programming Guide
About me
2
Bonus: More slides on this topic at
https://slideshare.net/davidmstokes
deck than be covered in this time slot
Why This Talk?
3
Databases are
‘different’
4
Lots of ‘bad’ information on
how to secure a database but
you still need access to it!
Learning How To Learn
● Interpreting error messages
● ‘What the *#%& does that mean?’ moments
○ What is the computer trying to tell me?
○ How do you solve that?!?
○ One of the few cases where extensive exposure
to toddlers is beneficial
● Comprehension
○ ‘Seat time’ versus ‘learning curve’
● Action or active inaction
● Is that good or bad? That depends!
○ Sadly very few rules where x is always bad
5
6
And the technology keeps marching forward too!
7
Need to handled properly
to secure your MySQL
server - at the same time!
Many levels
8
Some Basics!
1. Never have database server directly accessible from the Internet.
2. You will software updated.
3. Keep database network traffic isolated.
4. Not everyone needs the root password.
5. Isolate schemas/databases by project/function, do not let them mix &
match
6. Practice recovery from backups
7. Make useful backups.
8. Monitor you instances.
9. Reject bad queries, projects ‘tossed over the wall’.
10.Know your company rules on data privacy, data retention, and security -
AND FOLLOW THEM!
9
Do NOT use the root account for
any and everything!
Passwords
1. Do not have anonymous accounts
without passwords
2. Use complex passwords - UC, LC,
special characters
3. Expire passwords
Password
Complexity
10
11
Complexity
The LOW policy tests password length only. Passwords must be at least 8 characters long. To
change this length, modify validate_password.length.
The MEDIUM policy adds the conditions that passwords must contain at least 1 numeric
character, 1 lowercase character, 1 uppercase character, and 1 special (nonalphanumeric)
character. To change these values, modify validate_password.number_count,
validate_password.mixed_case_count, and validate_password.special_char_count.
The STRONG policy adds the condition that password substrings of length 4 or longer must not
match words in the dictionary file, if one has been specified. To specify the dictionary file, modify
validate_password.dictionary_file.
Use a dictionary file to keep out passwords like ‘password’, ‘thebossisajerk’, ‘Passw()rd’, or
‘incorrect’
12
Example
SQL > create user 'Foo'@'%' IDENTIFIED BY RANDOM PASSWORD;
+------+------+----------------------+
| user | host | generated password |
+------+------+----------------------+
| Foo | % | Ld]5/Fkn[Kk29/g/M;>n |
+------+------+----------------------+
1 row in set (0.0090 sec)
Another Example
SQL > ALTER USER 'Foo'@'%' IDENTIFIED BY RANDOM PASSWORD;
+------+------+----------------------+
| user | host | generated password |
+------+------+----------------------+
| Foo | % | !rN<NCxjE5ncC6mB*2:@ |
+------+------+----------------------+
Let server generate password
13
Secondary Passwords
ALTER USER 'dave'@'deardave.xyz' IDENTIFIED BY 'deardave2' RETAIN CURRENT PASSWORD;
In the mysql.user table there is now a User_attribute column:
{"additional_password": "$A$005$;H7u001bu001bu0006<`qFRUtNRxT
Zu0003Ya/iej8Az8LoXGTv.dtf9K3RdJuaLFtXZHBs3/DntG2"}
ALTER USER 'dave'@'deardave'xyz' DISCARD OLD PASSWORD
14
[mysqld]
password_history=6
password_reuse_interval=365
Password reuse
15
Audit your accounts
on a regular basis!!!
16
Personnel will not advise you of staff changes
and the DBA.SRE needs to check that those who
have access to schemas really need that access!
Know who needs
access!
17
bob@’%’
!=
bob@192.168.%.%
Accounts ..
18
MySQL will authenticate users at the first match
Which may not be the right match
bob@yourcompany.com != bob@192.168.%.%
These two accounts are seen as two separate accounts
(with possibly different privileges)
Promiscuity
19
Login process
1. Is your system allowed to connect to server?
2. Is your account allowed to connect to server?
3. Is your account restricted from server?
4. Does account have privileges to connect?
5. Does your account have privileges to connect to
columns/tables/schemas?
20
Identify accounts
CREATE USER 'dstokes'@'localhost'
IDENTIFIED by 'S3cr3t!'
COMMENT '{ "user" : "Dave" }';
And the information is stored in a column named User_attributes.
select User_attributes from user WHERE User='dstokes'G
*************************** 1. row ***************************
User_attributes: {"metadata": {"comment": "{ "user" : "Dave"
}"}}
alter user 'jack'@'localhost'
ATTRIBUTE '{ "foo" : "Example" }';
SELECT User_attributes from user where User='jack';
+-------------------------------------------------+
| User_attributes |
+-------------------------------------------------+
| {"metadata": {"foo": "Example", "test": "yes"}} |
+-------------------------------------------------+
21
Has been turned on by default
since MySQL 8.0 was released
SSL/TLS
Will generate certificates if you do not specify your own!
MySQL 8.0
22
23
Learn to say ‘NO!’
Privileges
24
Use your privileges wisely
Do not give out SUPER or GRANT privs unless you have to!
Do not use the same accounts for separate projects
Consider separate account/password for read versus
write
Use ROLES, do not copy someone else’s account
25
CREATE ROLE 'app_developer', 'app_read', 'app_write';
GRANT ALL ON app_db.* TO 'app_developer';
GRANT SELECT ON app_db.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';
Create accounts
GRANT 'app_developer' TO 'dev1'@'localhost';
GRANT 'app_read' TO 'read_user1'@'localhost',
'read_user2'@'localhost';
GRANT 'app_read', 'app_write' TO 'rw_user1'@'localhost';
26
Do you need it?
Encryption
27
A handful of options:
Data security is a concern for institutions and organizations.
Transparent Data Encryption (TDE) or Data at Rest Encryption encrypts data
files.
Data at rest is any data which is not accessed or changed frequently, stored
on different types of storage devices.
Encryption ensures that if an unauthorized user accesses the data files from
the file system, the user cannot read contents.
28
If you encrypt your data
on disk, you should also
make your logs save too!
Do not forget the logs!
29
Yup!
SELinux
1. Yes, you need to make backups
2. Yes, you need to be able to restore a) server, b)
schema, c) table, & d) row
3. Offsite storage
4. Cross training staff
5. What is your retention time
6. How much can you lose?
Backups/Recover
30
31
● Snapshots
● MySQL Dump / MySQL Pump
● MySQL Shell Utilities
● Percona XtraBackup
● MySQL Enterprise Backup ($$$$)
1. Use UTF8MB4 Universally — Double check!
Character Sets &
Collations
32
33
MySQL localhost:33060+ ssl test SQL > show create table testG
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`ID` int NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT '',
`CountryCode` char(3) NOT NULL DEFAULT '',
PRIMARY KEY (`ID`),
KEY `Name` (`Name`),
KEY `Name_CountryCode` (`Name`,`CountryCode`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.0070 sec)
34
MySQL localhost:33060+ ssl test SQL > show create table testG
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`ID` int NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT '',
`CountryCode` char(3) NOT NULL DEFAULT '',
PRIMARY KEY (`ID`),
KEY `Name` (`Name`),
KEY `Name_CountryCode` (`Name`,`CountryCode`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.0070 sec)
35
Please pay attention to character sets
and collations when performing
upgrades. With MySQL 8.0 the old UTF8
was not the new UTF8MB4.
Character Sets /
Collations
36
Use the upgrade checker in
the MySQL Shell
mysqlsh> util.checkForServerUpgrade()
Cheaper to keep bad data out than have to fix it later
Keep out bad data
37
38
CREATE TABLE c1 (id INT NOT NULL,
CONSTRAINT id_gt_100 CHECK (('id' > 100))
);
A simple test with a value in range runs perfectly fine.
INSERT INTO c1 (id) VALUES (10000);
Query OK, 1 row affected (0.0037 sec)
But you will receive an error if the value of 'is' is less than 100.
INSERT INTO c1 (id) VALUES (10);
ERROR: 3819: Check constraint 'id_gt_100' is
violated.
39
CREATE TABLE c1 (id INT NOT NULL,
CONSTRAINT id_gt_100 CHECK (('id' > 100))
);
A simple test with a value in range runs perfectly fine.
INSERT INTO c1 (id) VALUES (10000);
Query OK, 1 row affected (0.0037 sec)
But you will receive an error if the value of 'is' is less than 100.
INSERT INTO c1 (id) VALUES (10);
ERROR: 3819: Check constraint 'id_gt_100' is
violated.
Hint - name your
constraints to be able
to track them down
quickly.
40
set @s='{"type": "object",
"properties": {
"myage": {
"type" : "number",
"minimum": 28,
"maximum": 99
}
}
}';
JSON Document Validation
set @d='{ "myage": 33}';
select JSON_SCHEMA_VALID(@s,@d);
+--------------------------+
| JSON_SCHEMA_VALID(@s,@d) |
+--------------------------+
| 1 |
+--------------------------+
1 row in set (0.00 sec)
mysql> set @d='{ "myage": 16}';
Query OK, 0 rows affected (0.00 sec)
mysql> select JSON_SCHEMA_VALID(@s,@d);
+--------------------------+
| JSON_SCHEMA_VALID(@s,@d) |
+--------------------------+
| 0 |
+--------------------------+
41
CREATE TABLE `testx` (
`col` JSON,
CONSTRAINT `myage_inRange`
CHECK (JSON_SCHEMA_VALID('{"type": "object",
"properties": {
"myage": {
"type" : "number",
"minimum": 28,
"maximum": 99
}
},"required": ["myage"]
}', `col`) = 1)
);
mysql> insert into testx values('{"myage":27}');
ERROR 3819 (HY000): Check constraint 'myage_inRange' is
violated.
mysql> insert into testx values('{"myage":97}');
Query OK, 1 row affected (0.02 sec)
Do you know what your server is doing right now?
Monitor your servers
42
43
44
45
Test Drive
pmmdemo.percona.com
Many facets!
Replication
46
47
1. Use for backup
2. Use for HA – Group Replication, Replica
Sets, XtraDB Cluster
3. Copy data between data centers
4. You do not need to replicate everything –
be selective
Many facets!
Right Size
48
49
Does your working set fit
into available memory?
50
Use the right data type and the
right size:
Not all integers need to be
BIGINT and not all text data
need to be in VARCHAR(255)!
51
Only index the columns that
you need to or suffer
tremendous overhead!
Many facets!
Query Performance
52
You need to know how
to read a query plan.
Learn to use
EXPLAIN
53
ORMs are optimized for developers and not for
databases. They write bad queries, make
mistakes, and can introduce their own set of
overhead problems.
Learn to write good SQL!
ORMs are a NO-NO!
54
Plan to review your servers on a regular basis to assure that
‘mission creep’ is not interfering with the safety of your
data.
Audit Your Work!
55
Thank you!
56
David.Stokes @ Percona.com
@Stoker
slideshare.net/ davidmstokes

Locking Down Your MySQL Database.pptx

  • 1.
  • 2.
    Open Source Advocate MySQLCommunity Team 11 years Author of MySQL & JSON - A Practical Programming Guide About me 2 Bonus: More slides on this topic at https://slideshare.net/davidmstokes deck than be covered in this time slot
  • 3.
  • 4.
    Databases are ‘different’ 4 Lots of‘bad’ information on how to secure a database but you still need access to it!
  • 5.
    Learning How ToLearn ● Interpreting error messages ● ‘What the *#%& does that mean?’ moments ○ What is the computer trying to tell me? ○ How do you solve that?!? ○ One of the few cases where extensive exposure to toddlers is beneficial ● Comprehension ○ ‘Seat time’ versus ‘learning curve’ ● Action or active inaction ● Is that good or bad? That depends! ○ Sadly very few rules where x is always bad 5
  • 6.
    6 And the technologykeeps marching forward too!
  • 7.
    7 Need to handledproperly to secure your MySQL server - at the same time! Many levels
  • 8.
    8 Some Basics! 1. Neverhave database server directly accessible from the Internet. 2. You will software updated. 3. Keep database network traffic isolated. 4. Not everyone needs the root password. 5. Isolate schemas/databases by project/function, do not let them mix & match 6. Practice recovery from backups 7. Make useful backups. 8. Monitor you instances. 9. Reject bad queries, projects ‘tossed over the wall’. 10.Know your company rules on data privacy, data retention, and security - AND FOLLOW THEM!
  • 9.
    9 Do NOT usethe root account for any and everything! Passwords
  • 10.
    1. Do nothave anonymous accounts without passwords 2. Use complex passwords - UC, LC, special characters 3. Expire passwords Password Complexity 10
  • 11.
    11 Complexity The LOW policytests password length only. Passwords must be at least 8 characters long. To change this length, modify validate_password.length. The MEDIUM policy adds the conditions that passwords must contain at least 1 numeric character, 1 lowercase character, 1 uppercase character, and 1 special (nonalphanumeric) character. To change these values, modify validate_password.number_count, validate_password.mixed_case_count, and validate_password.special_char_count. The STRONG policy adds the condition that password substrings of length 4 or longer must not match words in the dictionary file, if one has been specified. To specify the dictionary file, modify validate_password.dictionary_file. Use a dictionary file to keep out passwords like ‘password’, ‘thebossisajerk’, ‘Passw()rd’, or ‘incorrect’
  • 12.
    12 Example SQL > createuser 'Foo'@'%' IDENTIFIED BY RANDOM PASSWORD; +------+------+----------------------+ | user | host | generated password | +------+------+----------------------+ | Foo | % | Ld]5/Fkn[Kk29/g/M;>n | +------+------+----------------------+ 1 row in set (0.0090 sec) Another Example SQL > ALTER USER 'Foo'@'%' IDENTIFIED BY RANDOM PASSWORD; +------+------+----------------------+ | user | host | generated password | +------+------+----------------------+ | Foo | % | !rN<NCxjE5ncC6mB*2:@ | +------+------+----------------------+ Let server generate password
  • 13.
    13 Secondary Passwords ALTER USER'dave'@'deardave.xyz' IDENTIFIED BY 'deardave2' RETAIN CURRENT PASSWORD; In the mysql.user table there is now a User_attribute column: {"additional_password": "$A$005$;H7u001bu001bu0006<`qFRUtNRxT Zu0003Ya/iej8Az8LoXGTv.dtf9K3RdJuaLFtXZHBs3/DntG2"} ALTER USER 'dave'@'deardave'xyz' DISCARD OLD PASSWORD
  • 14.
  • 15.
    15 Audit your accounts ona regular basis!!!
  • 16.
    16 Personnel will notadvise you of staff changes and the DBA.SRE needs to check that those who have access to schemas really need that access! Know who needs access!
  • 17.
  • 18.
    18 MySQL will authenticateusers at the first match Which may not be the right match bob@yourcompany.com != bob@192.168.%.% These two accounts are seen as two separate accounts (with possibly different privileges) Promiscuity
  • 19.
    19 Login process 1. Isyour system allowed to connect to server? 2. Is your account allowed to connect to server? 3. Is your account restricted from server? 4. Does account have privileges to connect? 5. Does your account have privileges to connect to columns/tables/schemas?
  • 20.
    20 Identify accounts CREATE USER'dstokes'@'localhost' IDENTIFIED by 'S3cr3t!' COMMENT '{ "user" : "Dave" }'; And the information is stored in a column named User_attributes. select User_attributes from user WHERE User='dstokes'G *************************** 1. row *************************** User_attributes: {"metadata": {"comment": "{ "user" : "Dave" }"}} alter user 'jack'@'localhost' ATTRIBUTE '{ "foo" : "Example" }'; SELECT User_attributes from user where User='jack'; +-------------------------------------------------+ | User_attributes | +-------------------------------------------------+ | {"metadata": {"foo": "Example", "test": "yes"}} | +-------------------------------------------------+
  • 21.
    21 Has been turnedon by default since MySQL 8.0 was released SSL/TLS
  • 22.
    Will generate certificatesif you do not specify your own! MySQL 8.0 22
  • 23.
    23 Learn to say‘NO!’ Privileges
  • 24.
    24 Use your privilegeswisely Do not give out SUPER or GRANT privs unless you have to! Do not use the same accounts for separate projects Consider separate account/password for read versus write Use ROLES, do not copy someone else’s account
  • 25.
    25 CREATE ROLE 'app_developer','app_read', 'app_write'; GRANT ALL ON app_db.* TO 'app_developer'; GRANT SELECT ON app_db.* TO 'app_read'; GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write'; Create accounts GRANT 'app_developer' TO 'dev1'@'localhost'; GRANT 'app_read' TO 'read_user1'@'localhost', 'read_user2'@'localhost'; GRANT 'app_read', 'app_write' TO 'rw_user1'@'localhost';
  • 26.
    26 Do you needit? Encryption
  • 27.
    27 A handful ofoptions: Data security is a concern for institutions and organizations. Transparent Data Encryption (TDE) or Data at Rest Encryption encrypts data files. Data at rest is any data which is not accessed or changed frequently, stored on different types of storage devices. Encryption ensures that if an unauthorized user accesses the data files from the file system, the user cannot read contents.
  • 28.
    28 If you encryptyour data on disk, you should also make your logs save too! Do not forget the logs!
  • 29.
  • 30.
    1. Yes, youneed to make backups 2. Yes, you need to be able to restore a) server, b) schema, c) table, & d) row 3. Offsite storage 4. Cross training staff 5. What is your retention time 6. How much can you lose? Backups/Recover 30
  • 31.
    31 ● Snapshots ● MySQLDump / MySQL Pump ● MySQL Shell Utilities ● Percona XtraBackup ● MySQL Enterprise Backup ($$$$)
  • 32.
    1. Use UTF8MB4Universally — Double check! Character Sets & Collations 32
  • 33.
    33 MySQL localhost:33060+ ssltest SQL > show create table testG *************************** 1. row *************************** Table: test Create Table: CREATE TABLE `test` ( `ID` int NOT NULL AUTO_INCREMENT, `Name` char(35) NOT NULL DEFAULT '', `CountryCode` char(3) NOT NULL DEFAULT '', PRIMARY KEY (`ID`), KEY `Name` (`Name`), KEY `Name_CountryCode` (`Name`,`CountryCode`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.0070 sec)
  • 34.
    34 MySQL localhost:33060+ ssltest SQL > show create table testG *************************** 1. row *************************** Table: test Create Table: CREATE TABLE `test` ( `ID` int NOT NULL AUTO_INCREMENT, `Name` char(35) NOT NULL DEFAULT '', `CountryCode` char(3) NOT NULL DEFAULT '', PRIMARY KEY (`ID`), KEY `Name` (`Name`), KEY `Name_CountryCode` (`Name`,`CountryCode`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.0070 sec)
  • 35.
    35 Please pay attentionto character sets and collations when performing upgrades. With MySQL 8.0 the old UTF8 was not the new UTF8MB4. Character Sets / Collations
  • 36.
    36 Use the upgradechecker in the MySQL Shell mysqlsh> util.checkForServerUpgrade()
  • 37.
    Cheaper to keepbad data out than have to fix it later Keep out bad data 37
  • 38.
    38 CREATE TABLE c1(id INT NOT NULL, CONSTRAINT id_gt_100 CHECK (('id' > 100)) ); A simple test with a value in range runs perfectly fine. INSERT INTO c1 (id) VALUES (10000); Query OK, 1 row affected (0.0037 sec) But you will receive an error if the value of 'is' is less than 100. INSERT INTO c1 (id) VALUES (10); ERROR: 3819: Check constraint 'id_gt_100' is violated.
  • 39.
    39 CREATE TABLE c1(id INT NOT NULL, CONSTRAINT id_gt_100 CHECK (('id' > 100)) ); A simple test with a value in range runs perfectly fine. INSERT INTO c1 (id) VALUES (10000); Query OK, 1 row affected (0.0037 sec) But you will receive an error if the value of 'is' is less than 100. INSERT INTO c1 (id) VALUES (10); ERROR: 3819: Check constraint 'id_gt_100' is violated. Hint - name your constraints to be able to track them down quickly.
  • 40.
    40 set @s='{"type": "object", "properties":{ "myage": { "type" : "number", "minimum": 28, "maximum": 99 } } }'; JSON Document Validation set @d='{ "myage": 33}'; select JSON_SCHEMA_VALID(@s,@d); +--------------------------+ | JSON_SCHEMA_VALID(@s,@d) | +--------------------------+ | 1 | +--------------------------+ 1 row in set (0.00 sec) mysql> set @d='{ "myage": 16}'; Query OK, 0 rows affected (0.00 sec) mysql> select JSON_SCHEMA_VALID(@s,@d); +--------------------------+ | JSON_SCHEMA_VALID(@s,@d) | +--------------------------+ | 0 | +--------------------------+
  • 41.
    41 CREATE TABLE `testx`( `col` JSON, CONSTRAINT `myage_inRange` CHECK (JSON_SCHEMA_VALID('{"type": "object", "properties": { "myage": { "type" : "number", "minimum": 28, "maximum": 99 } },"required": ["myage"] }', `col`) = 1) ); mysql> insert into testx values('{"myage":27}'); ERROR 3819 (HY000): Check constraint 'myage_inRange' is violated. mysql> insert into testx values('{"myage":97}'); Query OK, 1 row affected (0.02 sec)
  • 42.
    Do you knowwhat your server is doing right now? Monitor your servers 42
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
    47 1. Use forbackup 2. Use for HA – Group Replication, Replica Sets, XtraDB Cluster 3. Copy data between data centers 4. You do not need to replicate everything – be selective
  • 48.
  • 49.
    49 Does your workingset fit into available memory?
  • 50.
    50 Use the rightdata type and the right size: Not all integers need to be BIGINT and not all text data need to be in VARCHAR(255)!
  • 51.
    51 Only index thecolumns that you need to or suffer tremendous overhead!
  • 52.
  • 53.
    You need toknow how to read a query plan. Learn to use EXPLAIN 53
  • 54.
    ORMs are optimizedfor developers and not for databases. They write bad queries, make mistakes, and can introduce their own set of overhead problems. Learn to write good SQL! ORMs are a NO-NO! 54
  • 55.
    Plan to reviewyour servers on a regular basis to assure that ‘mission creep’ is not interfering with the safety of your data. Audit Your Work! 55
  • 56.
    Thank you! 56 David.Stokes @Percona.com @Stoker slideshare.net/ davidmstokes