web-dev-qa-db-ja.com

PHP 7.4&MySQL:cache_sha2_password長い(20c)パスワードを拒否する

UPDATE:

23.02.2020:バグが修正されました PHP 7.4.3 =。

23.12.2019:影響を受けるパスワードを見つけました。以下の私の答えを参照してください。長いパスワードが拒否される理由への回答は、まだありがたいです。


免責事項:異なるパスワードを設定するだけで約2時間試しました。以下のパスワードで問題が発生することを確信しています。それは他のパスワードで動作します。私はそれを修正する方法を知っています:別のパスワードを使用してください。なぜ機能しないのか知りたい。そのような矛盾は受け入れられないからです。

システムで問題を再現できます。


最近PHP 7.4およびMySQL 8に切り替えられました。デフォルトではcaching_sha2_passwordを使用します。 validating の後に実際にPHPでサポートされていることを確認できませんでした。ランダムに生成されたパスワードで機能するようにするため、再度PHP 7.3 with mysql_native_passwordを使用しました。

今、私は新しいサーバーをセットアップし、それが機能したので、問題がどこにあるのかを見つけようとしたので、他のサーバーでcaching_sha2_passwordを使用できます。

MySQLrootを使用してmysqlシェル経由)

ALTER USER 'test'@'localhost' IDENTIFIED WITH caching_sha2_password BY '';
FLUSH PRIVILEGES;
QUIT

[〜#〜] php [〜#〜]

const DB_Host = '127.0.0.1';
const DB_USERNAME = 'test';
const DB_PASSWORD = '';
const DB_NAME = 'test_db';
$mysqli = new mysqli(DB_Host, DB_USERNAME, DB_PASSWORD, DB_NAME);

TEST(再現する)

php db.php

エラー

PHP警告:mysqli :: __ construct():(HY000/1045):/db.phpの5行目で、ユーザー 'test' @ 'localhost'(パスワード:YESを使用)のアクセスが拒否されました

回避策:おかしいことが実行されています。これは、いくつかの非常識な理由により、これを再度修正します:

mysql -u test -p
  # Enter password
  QUIT

パスワードを再設定すると、問題が再び発生します。

私が使用したパスワードに基づいて失敗したことに気づきました。そのため、サポートされていない文字や貼り付けの問題の可能性があると思いました。

私は元のパスワード(40文字)を次のように要約しました(20文字):

このパスワードはそれを破ります:l0QDEptp*L6tNo28ey^8

短い組み合わせはすべて問題なく機能します。このパスワードは、たとえば次のように機能します。l0QDEptp*L6tNo28ey^と、次のパスワード:0QDEptp*L6tNo28ey^8

重要:このパブリックパスワードは安全な環境でのみテストしてください!

問題を再現できる場合、またはこれについて何か考えがある場合(解決策/考えられる理由)、私に知らせてください。

注:この問題は、ランダムに生成されたすべてのパスワードで実際に発生します。パスワードは40文字で、特殊文字(例:%^ $!)が含まれています。比較的一般的ないくつかの組み合わせがこの問題を引き起こしていると思います。

画像:デモMySQL 8 & PHP 7.4 Authentication issue


MySQLバージョン:mysql Ver 8.0.18-0ubuntu0.19.10.1 for Linux on aarch64((Ubuntu))
PHPバージョン:PHP 7.4.1(cli)(build:Dec 18 2019 14: 44:55)(NTS)
PHPバグレポート:ここ
MySQLバグレポート:ここ

5
Minding

この問題は、19文字を超えるパスワードでのみ発生します。 MySQL Shell(mysql -u test -p)。

PHPテストスクリプト:

<?php
    # Static
    const DB_Host = '127.0.0.1';
    const DB_USER = 'test';
    const DB_NAME = 'test_db';
    const INITIAL_PW = 'Test123+++!!!';

    # Variable
    const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-!^$?#%';
    //const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    # At least one special char is required, because of my security configuration.
    #  Due to this restriction the script may fail randomly - only 'Access Denied' is important.
    const REQUIRED_SPECIAL_CHAR = '$';
    # Any length below 20 works - 20 and upwards fails.
    const PASSWORD_LENGTH = 20;
    # Number of iterations
    const ITERATIONS = 10;

    # Test
    $pw = INITIAL_PW;
    for($i = 0; $i < ITERATIONS; $i++) {
        $mysqli = new mysqli(DB_Host, DB_USER, $pw, DB_NAME);
        if($mysqli->connect_errno !== 0) {
            echo('Failed after '.$i.' iterations.'.PHP_EOL);
            echo('Password: '.$pw.PHP_EOL);
            exit;
        }
        $pw = getPassword(PASSWORD_LENGTH);
        $mysqli->query("ALTER USER 'test'@'localhost' IDENTIFIED WITH caching_sha2_password BY '$pw'") OR DIE('Failed to set password (after '.$i.' iterations): '.$mysqli->error.PHP_EOL);
        $mysqli->query('FLUSH PRIVILEGES') OR DIE('Failed to flush: '.$mysqli->error.PHP_EOL);
        $mysqli->close() OR DIE('Failed to close: '.$mysqli->error.PHP_EOL);
    }
    echo('Done.'.PHP_EOL);

    # Helper
    function getPassword(int $length) {
        $pw = '';
        for($i = 1; $i < $length; $i++)
            $pw .= CHARS[Rand(0, strlen(CHARS) - 1)];
        $pw .= REQUIRED_SPECIAL_CHAR;
        return $pw;
    }
?>

なぜこれは長いパスワードで発生するのですか? [〜#〜] idk [〜#〜](おそらくキャッシュ制限?)

1
Minding