スマートスタイル TECH BLOG

MySQL で クライアントと SSL/TLS を使った暗号化接続を行う

一般的にはデータベースでは機密性の高いデータを管理することが多く、セキュリティについても十分に注意を払った設計を行う必要があります。
今回は MySQLサーバーとクライアントとの接続に SSL/TLS を使った暗号化した接続を行う方法をご紹介したいと思います。

参考:MySQL :: MySQL 5.7 Reference Manual :: 6.4 Using Encrypted Connections

MySQL の SSL/TLS について

MySQLではSSL/TLSのライブラリとして OpenSSL と yaSSL がサポートされていますが、インストールの方法やバージョンによって組み込まれるライブラリが異なります。

バイナリ ライブラリ
MySQL 8.0 OpenSSL
MySQL 5.7以前の商用版 OpenSSL
MySQL 5.7以前のCommunity yaSSL

MySQL5.7以前の Community Edition でも ソースからコンパイルすると OpenSSL が使えます。

OpenSSL と yaSSL では以下のような違いがあります。(MySQL 5.7.21の場合)

OpenSSL yaSSL
暗号化方式 45種類 16種類
バージョン TLS1.2 TLS1.1 TLS1.0 TLS1.1 TLS1.0

大きな違いとしてはOpenSSLのみ最新のTLS1.2を使うことができることと
yaSSLの場合、暗号利用モードに脆弱性を含むCBC (Cipher Block Chaining)が暗号化方式として有効になっている点です。
TLS1.1、1.0ではPOODLEと呼ばれる脆弱性を含んでいるため、セキュリティを重要視するならTLS1.2を利用することが望ましいです。

参考
MySQL :: MySQL 5.7 Reference Manual :: 6.4.4 OpenSSL Versus yaSSL
ImperialViolet – The POODLE bites again

サーバー設定

ここからのセクションは MySQL 5.7 の商用版を使っています。基本的な動作はコミュニティ版と同じです。

暗号鍵の作成

暗号鍵の作成は OpenSSL コマンドを使って生成する方法もありますが、MySQL 5.7.6 からは mysql_ssl_rsa_setup コマンドが同梱されており、こちらを使うと簡単に必要な鍵を生成することができます。

また、初回起動時に systemd の設定を見ると、自動的に鍵生成が行われます。

MySQL のデータディレクトリ以下に適切なファイル名で生成されるので、my.cnf に設定を追加しなくても、SSL/TLS 設定が有効になります。

ここでは、改めて暗号鍵を再作成するところから始めます。
まずは、データディレクトリの鍵ファイルを削除します

mysql_ssl_rsa_setup を実行して再度鍵ファイルを生成します

MySQLのデータディレクトリに以下のような鍵ファイルが作成されます。

ここで生成されるCA(Certification Authority、認証局)は自己認証局です。
鍵の有効期間は10年で作成されます。

my.cnf に暗号鍵のパスを指定します。

MySQLを再起動します。

SSL/TLS が有効になっているかを確認します。

セキュリティの強化

現状の設定ではTLSのバージョンは1.0から1.2まで使用することができます。

ここではmy.cnf を設定変更してTLSのバージョンを1.2のみに設定変更します。

MySQLを再起動します。

設定変更を確認

クライアント設定

MySQLではユーザー設定でSSL/TLSによる接続方法を指定しない限り、クライアント側はどのように接続するかを決めることができます。

MySQLコマンドでは--ssl-modeで指定することができます。

オプション SSL/TLS接続
PREFFERED 優先(デフォルト)
REQUIRED 必須
DISABLED 使用しない
VERIFY_CA 必須 CA鍵による検証も行う
VERIFY_IDENTITY 必須 クライアント認証も行う

REQUIRED による接続

サーバー認証を行わず単純に通信を暗号化したい場合です。
この場合、中間者攻撃(man-in-the-middle attack)に対しては有効ではありません。

DISABLEDによる接続

SSL/TLSを使わずに接続する場合です。

VERIFY_CAによる接続

サーバー認証を行なって接続する場合です。

VERIFY_IDENTITY による接続

サーバー認証とクライアント認証(相互認証)を行って接続する場合です。
MySQLサーバーへ接続するクライアントも鍵による認証を行います。

参考 6.4.1 Configuring MySQL to Use Encrypted Connections

TLSバージョンと暗号化アルゴリズム

暗号化アルゴリズムはこのリストの先頭からクライアントとサーバーの両方で対応しているものが使われます。

現在の接続で使われている暗号とTLSのバージョンは以下のコマンドでわかります。

サーバーが対応している暗号化方式やプロトコルのバージョンから、クライアントは選択することになるため、悪意あるクライアントが最も弱い形式の暗号化方式を使うことでセキュリティ上の問題が発生する可能性があります。

my.cnf の設定でTLSのバージョンや使用できる暗号化方法を指定することができます。

MySQLのユーザー設定

MySQLのユーザーについても、SSL/TLS認証を必須にしない限り、クライアントがSSL/TLSによる接続を使わずに接続することが可能です(–ssl-mode=DISABLED)
そのため、MySQLのユーザーについても必要に応じて設定が必要です。

SSL/TLS認証を必須とするユーザーを作成する

SSL/TLS認証を使うとログインすることができます

SSL/TLS認証を使わずにログインしようとすると認証エラーとなります

クライアント認証(相互認証)を必須とする場合はX509を指定します。

クライアント認証を行わないとエラーになります。

クライアント鍵で認証を行うとログインすることができます。

PHPでSSL/TLS接続を使ってMySQLに接続する

今回は、 mysql_ssl_rsa_setup で生成された鍵を使ってPHPとMySQLをSSL/TLS接続する方法と、ベンチマークを行ってみたいと思います。

クライアント認証に必要な鍵ファイルはMySQLのデータディレクトリに以下のファイル名で生成されています。

PDO::MySQLを使った接続の場合、PHPのコードは以下のようになります。

mysql_ssl_rsa_setup で生成されたCAは自己認証局なので、 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT を無効にします。

SSL/TLS接続のベンチマーク

MySQLの接続処理は比較的軽量ですが、SSL/TLS接続は接続時のハンドシェイク処理にどうしても時間がかかってしまいます。今回はSSL/TLS接続を有効にした場合、どれくらい時間がかかるか計測してみました。

検証環境

検証で使用したマシンは、クライアント側(PHP)とサーバー側(MySQL)の2台の別筐体でローカルネットワークで繋がっています。

PHPのバージョン: 7.2.7
MySQLのバージョン: 5.7.22

ベンチマークのPHPコードでは、PDOを使って単純に接続と切断を1万回繰り返します。
また、接続方法については下記の3つの方法を試しました。

  • 暗号化無し
  • クライアント認証を含むSSL/TLS接続
  • クライアント認証を含むSSL/TLS接続 + 持続的接続

持続的接続はMySQLとの接続を閉じずに次の接続要求があった場合、再利用する方法です。
接続オプションで PDO::ATTR_PERSISTENT => true を指定すると有効になります。

参考: PHP: 接続、および接続の管理 – Manual

それぞれの接続方法を3回実行して掛かった時間の平均値は以下の通りです。

接続方法 時間
暗号化無し 7.6秒
SSL/TLS 9分47秒
SSL/TLS + 持続的接続 2.4秒

SSL/TLS接続は接続コストがかなり掛かっていることがわかります。ただし、持続的接続(PDO::ATTR_PERSISTENT)オプションを有効にすることで、暗号化しない接続よりも高速になることもわかりました。

SSL/TLSでセキュアな接続とパフォーマンスの両方が必要な場合は、持続的接続を使用することも検討してください。ただし、以下のページにあるようにいくつかの注意点もあるため、十分な検証を行ってから導入するようにしてください。

PHP: 持続的データベース接続 – Manual

まとめ

MySQL 5.7.6 以降では mysql_ssl_rsa_setup を使うことで簡単に自己認証局のCA鍵生成などを行うことができ、初回起動時に鍵生成が行われるのでデフォルトでSSL/TLSによる暗号化通信を利用することは可能ですが、設定としては十分ではありませんのでご自身のシステムのセキュリティ基準に応じて設定し直す必要があります。
また、アプリケーションからSSL/TLS接続を行う場合、接続にコストがかかるためパフォーマンスに問題が出る可能性もあるため、コネクションプーリングなどの導入も検討してください。


MySQL

 

Return Top