herokuでMySQL(ClearDB)をSSLで暗号化して使う

昨日の「herokuでPHPからMySQL(ClearDB)を使う」で

なお、SSL設定をしていませんので通信は暗号化されていませんので注意してください。

と書きました。

今日は、暗号化していない場合、MySQLはどんな通信をしているかを、パケットキャプチャして確認してみたいと思います。

ということで、mysqlコマンドでログインしてSQL文を発行してみます。

$ mysql --host=us-cdbr-iron-east-01.cleardb.net --user=b16d3f52562f99 --password=1dab1fd2 heroku_43749156d41f0d5
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22500816
Server version: 5.5.40-log MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT * FROM user;
+----+-------+---------------------+
| id | name  | data_created        |
+----+-------+---------------------+
|  1 | user1 | 2014-12-12 04:14:53 |
|  2 | user2 | 2014-12-12 04:15:01 |
|  3 | user3 | 2014-12-12 04:15:06 |
+----+-------+---------------------+
3 rows in set (0.20 sec)

mysql> 

上記の通信をWiresharkでキャプチャして確認してみます。

▼ユーザ名とデータベース名が見えてます。 MySQLの通信のパケットキャプチャ

▼発行したSQL文も見えてます。 MySQLの通信のパケットキャプチャ

▼SELECTの結果もすべて見えます。 MySQLの通信のパケットキャプチャ

はい、ということで、もし、パケットキャプチャが可能なら、ユーザ名、データベース名、発行したすべてのSQL文、そしてその結果セットのすべてを簡単に取得できます。

SSLの設定

herokunにログインし、AppsのResourceのAdd-onsの「ClearDB MySQL Database」をクリックします。

ClearDB Database Dashboardが表示されますので、SSL CertificatesからPEM FormatのClearDB CA Certificate(cleardb-ca.pem)をダウンロードします。

ClearDB Database DashboardのSSL Certificates

my.cnfの[client]セクションにダウンロードしたファイルを設定します。

[client]
ssl-ca   = /path/to/cleardb-ca.pem

これでmysqlコマンドからSSLが使えるようになります。接続し直して、以下のコマンドを実行してみます。

mysql> status;

SSLの値が以下のように「Cipher in use is DHE-RSA-AES256-SHA」に変わっており、暗号化通信になっていることがわかります。

SSL:            Cipher in use is DHE-RSA-AES256-SHA

あるいは、以下でもわかります。

mysql> SHOW STATUS LIKE 'ssl_cipher';
+---------------+--------------------+
| Variable_name | Value              |
+---------------+--------------------+
| Ssl_cipher    | DHE-RSA-AES256-SHA |
+---------------+--------------------+
1 row in set (0.20 sec)

PDOでの設定

以下のようにPDOのコンストラクタにPDO::MYSQL_ATTR_SSL_CAをオプションで指定します。

<?php

$db = parse_url($_SERVER['CLEARDB_DATABASE_URL']);
$db['dbname'] = ltrim($db['path'], '/');
$dsn = "mysql:host={$db['host']};dbname={$db['dbname']};charset=utf8";

$options = array(
    PDO::MYSQL_ATTR_SSL_CA   => __DIR__ . '/../ssl/cleardb-ca.pem'
);

try {
    $db = new PDO($dsn, $db['user'], $db['pass'], $options);
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $sql = "SHOW STATUS LIKE 'ssl_cipher'";
    $prepare = $db->prepare($sql);
    $prepare->execute();

    echo '<pre>';
    $prepare->execute();
    $result = $prepare->fetchAll(PDO::FETCH_ASSOC);
    print_r(h($result));
    echo "\n";
    echo '</pre>';
} catch (PDOException $e) {
    echo 'Error: ' . h($e->getMessage());
}

function h($var)
{
    if (is_array($var)) {
        return array_map('h', $var);
    } else {
        return htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
    }
}

ブラウザからアクセスすると、以下のように「DHE-RSA-AES256-SHA」で暗号化通信していることがわかります。

Array
(
    [0] => Array
        (
            [Variable_name] => Ssl_cipher
            [Value] => DHE-RSA-AES256-SHA
        )

)

クライアント証明書を使う場合

ClearDB Database Dashboardから、SSL CertificatesのPEM FormatのClient CertificateとClient Private Keyをダウンロードします。

key.pemファイルをherokuで使えるように変換します。

$ openssl rsa -in b16d3f52562f99-key.pem -out cleardb_id-key-no-password.pem

my.cnfの[client]セクションに以下の設定を追加します。

[client]
ssl-key  = /etc/mysql/cleardb_id-key-no-password.pem
ssl-cert = /etc/mysql/b16d3f52562f99-cert.pem

PDOの場合は、以下のように追加します。

--- a/public/index.php
+++ b/public/index.php
@@ -5,7 +5,9 @@ $db['dbname'] = ltrim($db['path'], '/');
 $dsn = "mysql:host={$db['host']};dbname={$db['dbname']};charset=utf8";

 $options = array(
-    PDO::MYSQL_ATTR_SSL_CA   => __DIR__ . '/../ssl/cleardb-ca.pem'
+    PDO::MYSQL_ATTR_SSL_CA   => __DIR__ . '/../ssl/cleardb-ca.pem',
+    PDO::MYSQL_ATTR_SSL_KEY  => __DIR__ . '/../ssl/cleardb_id-key-no-password.pem',
+    PDO::MYSQL_ATTR_SSL_CERT => __DIR__ . '/../ssl/b16d3f52562f99-cert.pem',
 );

 try {

参考

関連

Date: 2014/12/12

Tags: heroku, mysql, php, database