はじめに
MySQLの機能レベルで ブルートフォースアタック への対策を講じようとした場合、一般的には、以下のような対策が考えられます。
- アカウントパスワードに様々な文字種を使用し、桁数を長めに設定する。
- bind_address で、接続元ホストを制限する。
- max_connect_errors を適切な値に設定し、指定回数、連続して正常に接続できなかった場合に、以降、そのホストからの接続を拒否する。
- FAILED_LOGIN_ATTEMPTSを設定して、指定回数、連続して正常に接続できなかった場合に、そのユーザを一定期間ロックする。
- CONNECTION_CONTROL プラグイン を使用して、指定回数、連続して正常に接続できなかった場合に、そのユーザからの接続レスポンスを遅延させる。
上記の 3. については、正常なMySQLプロトコルで接続された場合には、パスワード違いによる認証エラー等が発生したとしてもカウントされませんので、ブルートフォースアタック に意味をなさない可能性があります。
また、4.については MySQL 8.0.19 からの機能となり、以下の記事でもご紹介しておりますので、よろしければご確認下さい。
そして、今回は、5. について記事を記載したいと思います。
CONNECTION_CONTROL プラグイン
CONNECTION_CONTROL プラグイン とは、ユーザ単位で、指定した回数を連続して接続失敗した場合に、サーバからの接続レスポンスを遅延させるプラグインです。
このプラグインは、MySQL 5.7.17 以降のバージョンで使用可能ですが、あくまで応答を遅延させるだけなので、完全な対策というよりは、リスクを軽減させる目的であることをご認識ください。
それでは、実際に使用してみたいと思います。
まずは、CONNECTION_CONTROL
プラグインをインストールします。
エラー情報を保持する為に、 CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
プラグインも一緒にインストールする必要があります。
1 2 3 4 5 |
mysql> INSTALL PLUGIN CONNECTION_CONTROL SONAME 'connection_control.so'; Query OK, 0 rows affected (0.00 sec) mysql> INSTALL PLUGIN CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS SONAME 'connection_control.so'; Query OK, 0 rows affected (0.00 sec) |
以下のように、プラグインのインストールを確認します。
1 2 3 4 5 6 7 8 9 |
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS -> WHERE PLUGIN_NAME LIKE 'connection%'; +------------------------------------------+---------------+ | PLUGIN_NAME | PLUGIN_STATUS | +------------------------------------------+---------------+ | CONNECTION_CONTROL | ACTIVE | | CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS | ACTIVE | +------------------------------------------+---------------+ 2 rows in set (0.00 sec) |
インストールした後は、CONNECTION_CONTROL
プラグインに関する設定を確認してみましょう。
デフォルトでは、以下のように設定されています。
1 2 3 4 5 6 7 8 9 |
mysql> SHOW VARIABLES LIKE 'connection_control%'; +-------------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------------+------------+ | connection_control_failed_connections_threshold | 3 | | connection_control_max_connection_delay | 2147483647 | | connection_control_min_connection_delay | 1000 | +-------------------------------------------------+------------+ 3 rows in set (0.00 sec) |
パラメータ | 説明 | デフォルト値 |
---|---|---|
connection_control_failed_connections_threshold | 接続応答の遅延を発生させるまでの許容する接続エラー回数 | 3 |
connection_control_max_connection_delay | 最大遅延時間(ミリ秒) | 2147483647 |
connection_control_min_connection_delay | 最小遅延時間(ミリ秒) | 1000 |
上記のパラメータ設定から 3回目までの接続エラーはすぐにレスポンスを返しますが、4回目の接続エラー時に1秒の遅延を発生させます。
以降の接続エラーごとに 遅延時間が1秒増加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# for i in {1..7}; do time mysql -u user01 -ppassword ; done mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m0.034s user 0m0.004s sys 0m0.002s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m0.005s user 0m0.004s sys 0m0.000s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m0.007s user 0m0.005s sys 0m0.000s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m1.005s user 0m0.001s sys 0m0.003s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m2.007s user 0m0.003s sys 0m0.002s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m3.008s user 0m0.006s sys 0m0.000s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m4.008s user 0m0.004s sys 0m0.002s |
遅延を発生させた回数は、Connection_control_delay_generated
ステータス変数で確認できます。
この情報は、MySQLの再起動及び、 connection_control_failed_connections_threshold
変数の値を変更すると、クリアされます。
1 2 3 4 5 6 7 |
mysql> SHOW STATUS LIKE 'Connection_control_delay_generated'; +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | Connection_control_delay_generated | 4 | +------------------------------------+-------+ 1 row in set (0.00 sec) |
また、CONNECTION_CONTROL プラグインを有効にすると、接続エラーとなったユーザごとに、エラー回数を INFORMATION_SCHEMA.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
テーブルに保持しています。
こちらも、MySQLの再起動及び、 connection_control_failed_connections_threshold
変数の値を変更すると、レコードが削除されますが、さらに接続が正常に完了したユーザについても、削除されます。
1 2 3 4 5 6 7 |
mysql> SELECT * FROM INFORMATION_SCHEMA.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS; +--------------+-----------------+ | USERHOST | FAILED_ATTEMPTS | +--------------+-----------------+ | 'user01'@'%' | 7 | +--------------+-----------------+ 1 row in set (0.00 sec) |
もう一度、次は、以下のように各変数を変更して、再度、確認してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
mysql> SET GLOBAL connection_control_failed_connections_threshold = 2; Query OK, 0 rows affected (0.00 sec) mysql> SET GLOBAL connection_control_max_connection_delay = 4000; Query OK, 0 rows affected (0.00 sec) mysql> SET GLOBAL connection_control_min_connection_delay = 2000; Query OK, 0 rows affected (0.00 sec) mysql> SHOW VARIABLES LIKE 'connection_control%'; +-------------------------------------------------+-------+ | Variable_name | Value | +-------------------------------------------------+-------+ | connection_control_failed_connections_threshold | 2 | | connection_control_max_connection_delay | 4000 | | connection_control_min_connection_delay | 2000 | +-------------------------------------------------+-------+ 3 rows in set (0.00 sec) |
それでは、1回目と同様に実行してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# for i in {1..7}; do time mysql -u user01 -ppassword ; done mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m0.008s user 0m0.007s sys 0m0.000s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m0.005s user 0m0.001s sys 0m0.003s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m2.006s user 0m0.002s sys 0m0.002s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m2.006s user 0m0.004s sys 0m0.001s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m3.006s user 0m0.003s sys 0m0.002s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m4.006s user 0m0.002s sys 0m0.002s mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'user01'@'localhost' (using password: YES) real 0m4.006s user 0m0.004s sys 0m0.001s |
想定では、以下のような挙動になると考えておりました。
1,2回目 | 3回目 | 4回目 | 5回目 | 6回目 | 7回目 |
---|---|---|---|---|---|
遅延なし | 2秒 | 3秒 | 4秒 | 4秒 | 4秒 |
しかし、実際には、3回目、4回目ともに 2秒 の遅延という不可解な挙動となりました。
1,2回目 | 3回目 | 4回目 | 5回目 | 6回目 | 7回目 |
---|---|---|---|---|---|
遅延なし | 2秒 | 2秒 | 3秒 | 4秒 | 4秒 |
確かに、リファレンスの 6.4.2.1 Connection-Control プラグインのインストール には、以下のような記載があり、よく理解できない挙動について記載がありますが、具体的な算出式については記載がありません。
・ connection_control_min_connection_delay および connection_control_max_connection_delay が 1500 および 20000 の場合、4 番目および後続の失敗した接続の調整済遅延は 1500 ミリ秒、2000 ミリ秒、3000 ミリ秒などで、最大 20000 ミリ秒です。
・ connection_control_min_connection_delay および connection_control_max_connection_delay が 2000 および 3000 の場合、4 番目以降に失敗した接続の調整済遅延は 2000 ミリ秒、2000 ミリ秒および 3000 ミリ秒で、後続のすべての失敗した接続も 3000 ミリ秒遅延します。
そこで、ソースコードを確認してみました。
– GitHub / mysql-server/plugin/connection_control/connection_delay.h
具体的な遅延時間の計算方法は、以下のようになっている事が分かります。
MAX(遅延発生回数 × 1000 ms, connection_control_min_connection_delay),
connection_control_max_connection_delay
)
先程の実行例で、3回目(遅延発生回数=1)、4回目(遅延発生回数=2) がともに2秒となったことが頷けます。
遅延を制御する上で、変数を変更しても想定通りに動作しない場合は、上記の式を念頭においておけば、理解できるかと思います。
まとめ
今回の検証で、ブルートフォースアタックの攻撃速度を低下させ、リスクを軽減する効果が見込めることが理解できたのではないでしょうか。
あまり知られていない CONNECTION_CONTROL プラグインですが、コミュニティ版でも使用することができます。
しかし、対策として十分なものではないので、アクセス元を制限する等といった最低限の対策を実施した上で、CONNECTION_CONTROL プラグインの使用を検討頂ければと思います。
他にも MySQL を使用にあたり、セキュリティ面で考慮すべき事項が Security in MySQL にまとめられていますので、気になる方は目を通しておくとよいでしょう。