Using Secure Connections

This section describes how to set up secure connections between MySQL clients and the server using the Secure Sockets Layer (SSL) protocol. It also decribes a way to set up SSH on Windows.

Basics

Beginning with version 4.0.0, MySQL has support for SSL encrypted connections. To understand how MySQL uses SSL, it's necessary to explain some basic SSL and X509 concepts. People who are already familiar with them can skip this part.

By default, MySQL uses unencrypted connections between the client and the server. This means that someone could watch all your traffic and look at the data being sent or received. They could even change the data while it is in transit between client and server. Sometimes you need to move information over public networks in a secure fashion; in such cases, using an unencrypted connection is unacceptable.

SSL is a protocol that uses different encryption algorithms to ensure that data received over a public network can be trusted. It has mechanisms to detect any change, loss or replay of data. SSL also incorporates algorithms to recognize and provide identity verification using the X509 standard.

Encryption is the way to make any kind of data unreadable. In fact, today's practice requires many additional security elements from encryption algorithms. They should resist many kind of known attacks like just messing with the order of encrypted messages or replaying data twice.

X509 is a standard that makes it possible to identify someone on the Internet. It is most commonly used in e-commerce applications. In basic terms, there should be some company (called a ``Certificate Authority'') that assigns electronic certificates to anyone who needs them. Certificates rely on asymmetric encryption algorithms that have two encryption keys (a public key and a secret key). A certificate owner can prove his identity by showing his certificate to other party. A certificate consists of its owner's public key. Any data encrypted with this public key can be decrypted only using the corresponding secret key, which is held by the owner of the certificate.

MySQL doesn't use encrypted connections by default, because doing so would make the client/server protocol much slower. Any kind of additional functionality requires the computer to do additional work and encrypting data is a CPU-intensive operation that requires time and can delay MySQL main tasks. By default MySQL is tuned to be fast as possible.

If you need more information about SSL, X509, or encryption, you should use your favorite Internet search engine and search for keywords in which you are interested.

Requirements

To get secure connections to work with MySQL you must do the following:

  1. Install the OpenSSL library. We have tested MySQL with OpenSSL 0.9.6. http://www.openssl.org/.

  2. Configure MySQL with --with-vio --with-openssl.

  3. If you are using an old MySQL installation, you have to update your mysql.user table with some new SSL-related columns. This is necessary if your grant tables date from a version prior to MySQL 4.0.0. The procedure is described in Upgrading-grant-tables.

  4. You can check if a running mysqld server supports OpenSSL by examining if SHOW VARIABLES LIKE 'have_openssl' returns YES.

Setting Up SSL Certificates for MySQL

Here is an example for setting up SSL certificates for MySQL:

DIR=`pwd`/openssl
PRIV=$DIR/private
mkdir $DIR $PRIV $DIR/newcerts
cp /usr/share/ssl/openssl.cnf $DIR
replace ./demoCA $DIR -- $DIR/openssl.cnf
# Create necessary files: $database, $serial and $new_certs_dir 
# directory (optional)
touch $DIR/index.txt
echo "01" > $DIR/serial
#
# Generation of Certificate Authority(CA)
#
openssl req -new -x509 -keyout $PRIV/cakey.pem -out $DIR/cacert.pem \
    -config $DIR/openssl.cnf
# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# ................++++++
# .........++++++
# writing new private key to '/home/monty/openssl/private/cakey.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be incorporated
# into your certificate request.
# What you are about to enter is what is called a Distinguished Name or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL admin
# Email Address []:
#
# Create server request and key
#
openssl req -new -keyout $DIR/server-key.pem -out \
    $DIR/server-req.pem -days 3600 -config $DIR/openssl.cnf
# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# ..++++++
# ..........++++++
# writing new private key to '/home/monty/openssl/server-key.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be incorporated
# into your certificate request.
# What you are about to enter is what is called a Distinguished Name or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL server
# Email Address []:
# 
# Please enter the following 'extra' attributes
# to be sent with your certificate request
# A challenge password []:
# An optional company name []:
#
# Remove the passphrase from the key (optional)
#
openssl rsa -in $DIR/server-key.pem -out $DIR/server-key.pem
#
# Sign server cert
#
openssl ca  -policy policy_anything -out $DIR/server-cert.pem \
    -config $DIR/openssl.cnf -infiles $DIR/server-req.pem
# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Enter PEM pass phrase:
# Check that the request matches the signature
# Signature ok
# The Subjects Distinguished Name is as follows
# countryName           :PRINTABLE:'FI'
# organizationName      :PRINTABLE:'MySQL AB'
# commonName            :PRINTABLE:'MySQL admin'
# Certificate is to be certified until Sep 13 14:22:46 2003 GMT (365 days)
# Sign the certificate? [y/n]:y
# 
# 
# 1 out of 1 certificate requests certified, commit? [y/n]y
# Write out database with 1 new entries
# Data Base Updated
#
# Create client request and key
#
openssl req -new -keyout $DIR/client-key.pem -out \
    $DIR/client-req.pem -days 3600 -config $DIR/openssl.cnf
# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# .....................................++++++
# .............................................++++++
# writing new private key to '/home/monty/openssl/client-key.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be incorporated
# into your certificate request.
# What you are about to enter is what is called a Distinguished Name or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL user
# Email Address []:
# 
# Please enter the following 'extra' attributes
# to be sent with your certificate request
# A challenge password []:
# An optional company name []:
#
# Remove a passphrase from the key (optional)
#
openssl rsa -in $DIR/client-key.pem -out $DIR/client-key.pem
#
# Sign client cert
#
openssl ca  -policy policy_anything -out $DIR/client-cert.pem \
    -config $DIR/openssl.cnf -infiles $DIR/client-req.pem
# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Enter PEM pass phrase:
# Check that the request matches the signature
# Signature ok
# The Subjects Distinguished Name is as follows
# countryName           :PRINTABLE:'FI'
# organizationName      :PRINTABLE:'MySQL AB'
# commonName            :PRINTABLE:'MySQL user'
# Certificate is to be certified until Sep 13 16:45:17 2003 GMT (365 days)
# Sign the certificate? [y/n]:y
# 
# 
# 1 out of 1 certificate requests certified, commit? [y/n]y
# Write out database with 1 new entries
# Data Base Updated
#
# Create a my.cnf file that you can use to test the certificates
#
cnf=""
cnf="$cnf [client]"
cnf="$cnf ssl-ca=$DIR/cacert.pem"
cnf="$cnf ssl-cert=$DIR/client-cert.pem"
cnf="$cnf ssl-key=$DIR/client-key.pem"
cnf="$cnf [mysqld]"
cnf="$cnf ssl-ca=$DIR/cacert.pem"
cnf="$cnf ssl-cert=$DIR/server-cert.pem"
cnf="$cnf ssl-key=$DIR/server-key.pem"
echo $cnf | replace " " '
' > $DIR/my.cnf
#
# To test MySQL
mysqld --defaults-file=$DIR/my.cnf &
mysql --defaults-file=$DIR/my.cnf

You can also test your setup by modifying the above my.cnf file to refer to the demo certificates in the mysql-source-dist/SSL direcory.

SSL GRANT Options

MySQL can check X509 certificate attributes in addition to the normal username/password scheme. All the usual options are still required (username, password, IP address mask, database/table name).

There are different possibilities to limit connections:

  • Without any SSL or X509 options, all kind of encrypted/unencrypted connections are allowed if the username and password are valid.

  • REQUIRE SSL option limits the server to allow only SSL encrypted connections. Note that this option can be omitted if there are any ACL records which allow non-SSL connections.

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret' REQUIRE SSL;
      
  • REQUIRE X509 means that the client should have a valid certificate but we do not care about the exact certificate, issuer or subject. The only restriction is that it should be possible to verify its signature with one of the CA certificates.

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret' REQUIRE X509;
      
  • REQUIRE ISSUER 'issuer' places a restriction on connection attempts: The client must present a valid X509 certificate issued by CA 'issuer'. Using X509 certificates always implies encryption, so the SSL option is unneccessary.

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret'
          -> REQUIRE ISSUER 'C=FI, ST=Some-State, L=Helsinki,
          '> O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com';
      
  • REQUIRE SUBJECT 'subject' requires clients to have valid X509 certificate with subject 'subject' on it. If the client presents a certificate that is valid but has a different 'subject', the connection is disallowed.

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret'
          -> REQUIRE SUBJECT 'C=EE, ST=Some-State, L=Tallinn,
          '> O=MySQL demo client certificate,
          '> CN=Tonu Samuel/Email=tonu@mysql.com';
      
  • REQUIRE CIPHER 'cipher' is needed to assure enough strong ciphers and keylengths will be used. SSL itself can be weak if old algorithms with short encryption keys are used. Using this option, we can ask for some exact cipher method to allow a connection.

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret'
          -> REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';
      

    The SUBJECT, ISSUER, and CIPHER options can be combined in the REQUIRE clause like this:

      mysql> GRANT ALL PRIVILEGES ON test.* TO root@localhost
          -> IDENTIFIED BY 'goodsecret'
          -> REQUIRE SUBJECT 'C=EE, ST=Some-State, L=Tallinn,
          '> O=MySQL demo client certificate,
          '> CN=Tonu Samuel/Email=tonu@mysql.com'
          -> AND ISSUER 'C=FI, ST=Some-State, L=Helsinki,
          '> O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com'
          -> AND CIPHER 'EDH-RSA-DES-CBC3-SHA';
      

    Starting from MySQL 4.0.4 the AND keyword is optional between REQUIRE options.

    The order of the options does not matter, but no option can be specified twice.

SSL Command-line Options

The following table lists options that are used for specifying the use of SSL, certificate files, and key files. These options are available beginning with MySQL 4.0. They may be given on the command line or in option files.

--ssl For the server, specifies that the server allows SSL connections. For a client program, allows the client to connect to the server using SSL. This option itself is not sufficient to cause an SSL connection to be used. You must also specify the --ssl-ca, --ssl-cert, and --ssl-key options. Note that this option doesn't require an SSL connection. For example, if the server or client are compiled without SSL support, a normal unencrypted connection will be used. The secure way to ensure that a SSL connection will be used is to create an account on the server that includes a REQUIRE SSL clause in the GRANT statement. Then use this account to connect to the server, with both a server and client that have SSL support enabled. You can use this option to indicate that the connection should not use SSL. Do this by specifying the option as --skip-ssl or --ssl=0.
--ssl-ca=file_name The path to a file with a list of trusted SSL CAs.
--ssl-capath=directory_name The path to a directory that contains trusted SSL CA certificates in pem format.
--ssl-cert=file_name The name of the SSL certificate file to use used for establishing a secure connection.
--ssl-cipher=cipher_list A list of allowable ciphers to use for SSL encryption. cipher_list has the same format as the openssl ciphers command. Example: --ssl-cipher=ALL:-AES:-EXP
--ssl-key=file_name The name of the SSL key file to use used for establishing a secure connection.

Connecting to MySQL Remotely from Windows with SSH

Here is a note about how to connect to get a secure connection to remote MySQL server with SSH (by David Carlson ):

  1. Install an SSH client on your Windows machine. As a user, the best non-free one I've found is from SecureCRT from http://www.vandyke.com/. Another option is f-secure from http://www.f-secure.com/. You can also find some free ones on Google at http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/.

  2. Start your Windows SSH client. Set Host_Name = yourmysqlserver_URL_or_IP. Set userid=your_userid to log in to your server. This userid value may not be the same as the username of your MySQL account.

  3. Set up port forwarding. Either do a remote forward (Set local_port: 3306, remote_host: yourmysqlservername_or_ip, remote_port: 3306 ) or a local forward (Set port: 3306, host: localhost, remote port: 3306).

  4. Save everything, otherwise you'll have to redo it the next time.

  5. Log in to your server with the SSH session you just created.

  6. On your Windows machine, start some ODBC application (such as Access).

  7. Create a new file in Windows and link to MySQL using the ODBC driver the same way you normally do, except type in localhost for the MySQL host server---not yourmysqlservername.

You should now have an ODBC connection to MySQL, encrypted using SSH.