MySQLのパスワードを隠蔽する

2017年7月24日

WordPressのバックアップに書いたとおり、コマンドラインからMySQLを操作する際には-uオプションに続けてユーザー名と、-pオプションに続けてパスワードを指定する必要があります。

mysql_config_editorを使う

後ろの方に色々書きましたが、MySQL 5.6.6以降ならmysql_config_editor一択!MySQLのユーティリティを使えばOKです。

$ mysql_config_editor set –host=localhost –user=root –password
Enter password:
$ ll .mylogin.cnf
-rw——-  1 user  user  136 Dec  5 19:13 .mylogin.cnf

このようにsetコマンドに続けてmysqlコマンドに指定するオプションを指定するとホームディレクトリに.mylogin.cnfファイルを作ってくれます。.mylogin.cnfファイルは暗号化されているうえ、ログインユーザー以外のアクセスが許可されていないので安心です。

ファイルの中身を見るときはprintコマンドを使います。

$ mysql_config_editor print –all
[client]
user = root
password = *****
host = localhost

.my.cnfを使う

残念ながら上記機能はMariaDBにはないので、ホームディレクトリに.my.cnfを置いて対応します。

$ ll .my.cnf
-rw-------  1 user  user  45 Jan 12  2019 .my.cnf
$ cat .my.cnf
[client]
user=root
password="P@ssW0rd"

.mylogin.cnfとほとんど同じフォーマットです。パスワードは暗号化されていませんが、ファイルのアクセス権を自分だけにしておけばまぁ大丈夫でしょう。

パスワードを暗号化する

普通にシェルでパスワードまで指定してしまうとコマンド履歴に残ってしまうので、セキュリティ上よろしくありません。対話形式で実行する場合、パスワードは都度入力するようにした方がよさそうです。

問題は各種スクリプト。

シェルスクリプトの場合はQiita記事「シェスクリプトのパスワードを暗号化する」にあるようにopensslを利用して暗号化したものを実行時復号してやることで、スクリプトファイルにパスワードを平文で書いてしまうことを回避できます。

手順は次のとおり。

鍵ファイルの作成と設置

ssh-keygen

パスワード暗号化ファイルの作成と設置

echo 'password' | openssl rsautl -encrypt -inkey ~/.ssh/id_rsa > password.rsa

※ パスワードに$が入っているとシェル変数展開されてしまうのでechoはシングルクォートで括りましょう。

シェルスクリプトで復号処理を記述

mysql -uUSERNAME -p `openssl rsautl -decrypt -inkey ~/.ssh/id_rsa -in password.rsa`

パスワードを別ファイルにする

2018年1月29日追記

PHP7.1でPDOを使うためには別途php71-pdo_mysqlをインストールする必要があります。忘れずにpkg installしておきましょう。

phpでMySQLを操作する場合PDOオブジェクトを使いますが、オブジェクト生成の際にパスワードを平文で書くことになります。

<?php
$dbh = new PDO('mysql:dbname=DBNAME;host=HOSTNAME', 'USERNAME', 'PASSWORD');

通常phpファイルはそのままブラウザに表示されることはありませんが、ちょっと気になる。そこでphpのrequire_onceを使うことで平文のパスワード部分を分離し、ブラウザがアクセスできない場所に移動させることが可能です。

http(s)アクセスさせたくない情報

<?php
// ドキュメントルートより上に置けばhttp(s)アクセスできない
// たとえば/hidden/login_info.phpなど
$dsn = 'mysql:dbname=DBNAME;host=HOSTNAME';
$user = 'USERNAME';
$password = 'PASSWORD';
?>

php本体

<?php
// 実行ファイル本体はドキュメントルート下に配置される
// たとえば/usr/local/www/index.phpなど
require_once('/hidden/login_info.php');
$dbh = new PDO($dsn, $user, $password);

読み取り専用ユーザーを作る

…他にも手法はあるようですが、データベースの内容自体は表示してしまうわけだし、読み取り権限以外を剥奪したユーザーならパスワードなしでもよくね?と思っちゃいました。

CREATE USER 'readonly'@'localhost';
GRANT SELECT ON *.dbname TO 'readonly'@'localhost';

ユーザー作成時にIDENTIFIED BY以降を指定しないことでパスワードレスのユーザーを作り、GRANT SELECTでdbnameの全テーブルについてSELECT以外の操作を拒否します。

これならphpファイルに平文のパスワードを書かなくて済みます。データの登録や編集操作がない場合にはこんな解もあるのかなと。