认证方式的使用

HTTP and cookie authentication modes are recommended in a multi-user environment where you want to give users access to their own database and don’t want them to play around with others. Nevertheless, be aware that MS Internet Explorer seems to be really buggy about cookies, at least till version 6. Even in a single-user environment, you might prefer to use HTTP or cookie mode so that your user/password pair are not in clear in the configuration file.

HTTP and cookie authentication modes are more secure: the MySQL login information does not need to be set in the phpMyAdmin configuration file (except possibly for the $cfg['Servers'][$i]['controluser']). However, keep in mind that the password travels in plain text unless you are using the HTTPS protocol. In cookie mode, the password is stored, encrypted with the AES algorithm, in a temporary cookie.

Then each of the true users should be granted a set of privileges on a set of particular databases. Normally you shouldn’t give global privileges to an ordinary user unless you understand the impact of those privileges (for example, you are creating a superuser). For example, to grant the user real_user with all privileges on the database user_base:

  1. GRANT ALL PRIVILEGES ON user_base.* TO 'real_user'@localhost IDENTIFIED BY 'real_password';

现在用户可以做什么已经完全被 MySQL 用户管理系统所控制了。在 HTTP 或 cookie 认证方式下,您不需要填写 $cfg['Servers'] 中的 user/password 设置。

参见

1.32 Can I use HTTP authentication with IIS?, 1.35 Can I use HTTP authentication with Apache CGI?, 4.1 I’m an ISP. Can I setup one central copy of phpMyAdmin or do I need to install it for each customer?, 4.2 What’s the preferred way of making phpMyAdmin secure against evil access?, 4.3 I get errors about not being able to include a file in /lang or in /libraries.

HTTP 认证方式

注解

There is no way to do proper logout in HTTP authentication, most browsers will remember credentials until there is no different successful authentication. Because of this, this method has a limitation that you can not login with the same user after logout.

Cookie 认证方式

  • Username and password are stored in cookies during the session and password is deleted when it ends.
  • 在该认证方式下,用户可以真正的退出 phpMyAdmin 并用相同的用户再次登录(在 HTTP 认证方式 方式当中是不可行的)。
  • If you want to allow users to enter any hostname to connect (rather than only servers that are configured in config.inc.php), see the $cfg['AllowArbitraryServer'] directive.
  • 需求 一节中我们提到过,可选的 openssl 扩展可以显著提高访问速度,但不是必须的。

Signon 认证方式

The very basic example of saving credentials in a session is available as examples/signon.php:

  1. <?php
  2. /**
  3. * Single signon for phpMyAdmin
  4. *
  5. * This is just example how to use session based single signon with
  6. * phpMyAdmin, it is not intended to be perfect code and look, only
  7. * shows how you can integrate this functionality in your application.
  8. */
  9. declare(strict_types=1);
  10. /* Use cookies for session */
  11. ini_set('session.use_cookies', 'true');
  12. /* Change this to true if using phpMyAdmin over https */
  13. $secure_cookie = false;
  14. /* Need to have cookie visible from parent directory */
  15. session_set_cookie_params(0, '/', '', $secure_cookie, true);
  16. /* Create signon session */
  17. $session_name = 'SignonSession';
  18. session_name($session_name);
  19. // Uncomment and change the following line to match your $cfg['SessionSavePath']
  20. //session_save_path('/foobar');
  21. @session_start();
  22. /* Was data posted? */
  23. if (isset($_POST['user'])) {
  24. /* Store there credentials */
  25. $_SESSION['PMA_single_signon_user'] = $_POST['user'];
  26. $_SESSION['PMA_single_signon_password'] = $_POST['password'];
  27. $_SESSION['PMA_single_signon_host'] = $_POST['host'];
  28. $_SESSION['PMA_single_signon_port'] = $_POST['port'];
  29. /* Update another field of server configuration */
  30. $_SESSION['PMA_single_signon_cfgupdate'] = ['verbose' => 'Signon test'];
  31. $_SESSION['PMA_single_signon_HMAC_secret'] = hash('sha1', uniqid(strval(rand()), true));
  32. $id = session_id();
  33. /* Close that session */
  34. @session_write_close();
  35. /* Redirect to phpMyAdmin (should use absolute URL here!) */
  36. header('Location: ../index.php');
  37. } else {
  38. /* Show simple form */
  39. header('Content-Type: text/html; charset=utf-8');
  40. echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
  41. echo '<!DOCTYPE HTML>
  42. <html lang="en" dir="ltr">
  43. <head>
  44. <link rel="icon" href="../favicon.ico" type="image/x-icon">
  45. <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
  46. <meta charset="utf-8">
  47. <title>phpMyAdmin single signon example</title>
  48. </head>
  49. <body>';
  50. if (isset($_SESSION['PMA_single_signon_error_message'])) {
  51. echo '<p class="error">';
  52. echo $_SESSION['PMA_single_signon_error_message'];
  53. echo '</p>';
  54. }
  55. echo '<form action="signon.php" method="post">
  56. Username: <input type="text" name="user" autocomplete="username"><br>
  57. Password: <input type="password" name="password" autocomplete="current-password"><br>
  58. Host: (will use the one from config.inc.php by default)
  59. <input type="text" name="host"><br>
  60. Port: (will use the one from config.inc.php by default)
  61. <input type="text" name="port"><br>
  62. <input type="submit">
  63. </form>
  64. </body>
  65. </html>';
  66. }

Alternatively, you can also use this way to integrate with OpenID as shown in examples/openid.php:

  1. <?php
  2. /**
  3. * Single signon for phpMyAdmin using OpenID
  4. *
  5. * This is just example how to use single signon with phpMyAdmin, it is
  6. * not intended to be perfect code and look, only shows how you can
  7. * integrate this functionality in your application.
  8. *
  9. * It uses OpenID pear package, see https://pear.php.net/package/OpenID
  10. *
  11. * User first authenticates using OpenID and based on content of $AUTH_MAP
  12. * the login information is passed to phpMyAdmin in session data.
  13. */
  14. declare(strict_types=1);
  15. if (false === @include_once 'OpenID/RelyingParty.php') {
  16. exit;
  17. }
  18. /* Change this to true if using phpMyAdmin over https */
  19. $secure_cookie = false;
  20. /**
  21. * Map of authenticated users to MySQL user/password pairs.
  22. */
  23. $AUTH_MAP = [
  24. 'https://launchpad.net/~username' => [
  25. 'user' => 'root',
  26. 'password' => '',
  27. ],
  28. ];
  29. // phpcs:disable PSR1.Files.SideEffects,Squiz.Functions.GlobalFunction
  30. /**
  31. * Simple function to show HTML page with given content.
  32. *
  33. * @param string $contents Content to include in page
  34. *
  35. * @return void
  36. */
  37. function Show_page($contents)
  38. {
  39. header('Content-Type: text/html; charset=utf-8');
  40. echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
  41. echo '<!DOCTYPE HTML>
  42. <html lang="en" dir="ltr">
  43. <head>
  44. <link rel="icon" href="../favicon.ico" type="image/x-icon">
  45. <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
  46. <meta charset="utf-8">
  47. <title>phpMyAdmin OpenID signon example</title>
  48. </head>
  49. <body>';
  50. if (isset($_SESSION['PMA_single_signon_error_message'])) {
  51. echo '<p class="error">' . $_SESSION['PMA_single_signon_message'] . '</p>';
  52. unset($_SESSION['PMA_single_signon_message']);
  53. }
  54. echo $contents;
  55. echo '</body></html>';
  56. }
  57. /**
  58. * Display error and exit
  59. *
  60. * @param Exception $e Exception object
  61. *
  62. * @return void
  63. */
  64. function Die_error($e)
  65. {
  66. $contents = "<div class='relyingparty_results'>\n";
  67. $contents .= '<pre>' . htmlspecialchars($e->getMessage()) . "</pre>\n";
  68. $contents .= "</div class='relyingparty_results'>";
  69. Show_page($contents);
  70. exit;
  71. }
  72. // phpcs:enable
  73. /* Need to have cookie visible from parent directory */
  74. session_set_cookie_params(0, '/', '', $secure_cookie, true);
  75. /* Create signon session */
  76. $session_name = 'SignonSession';
  77. session_name($session_name);
  78. @session_start();
  79. // Determine realm and return_to
  80. $base = 'http';
  81. if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
  82. $base .= 's';
  83. }
  84. $base .= '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'];
  85. $realm = $base . '/';
  86. $returnTo = $base . dirname($_SERVER['PHP_SELF']);
  87. if ($returnTo[strlen($returnTo) - 1] !== '/') {
  88. $returnTo .= '/';
  89. }
  90. $returnTo .= 'openid.php';
  91. /* Display form */
  92. if ((! count($_GET) && ! count($_POST)) || isset($_GET['phpMyAdmin'])) {
  93. /* Show simple form */
  94. $content = '<form action="openid.php" method="post">
  95. OpenID: <input type="text" name="identifier"><br>
  96. <input type="submit" name="start">
  97. </form>';
  98. Show_page($content);
  99. exit;
  100. }
  101. /* Grab identifier */
  102. if (isset($_POST['identifier']) && is_string($_POST['identifier'])) {
  103. $identifier = $_POST['identifier'];
  104. } elseif (isset($_SESSION['identifier']) && is_string($_SESSION['identifier'])) {
  105. $identifier = $_SESSION['identifier'];
  106. } else {
  107. $identifier = null;
  108. }
  109. /* Create OpenID object */
  110. try {
  111. $o = new OpenID_RelyingParty($returnTo, $realm, $identifier);
  112. } catch (Throwable $e) {
  113. Die_error($e);
  114. }
  115. /* Redirect to OpenID provider */
  116. if (isset($_POST['start'])) {
  117. try {
  118. $authRequest = $o->prepare();
  119. } catch (Throwable $e) {
  120. Die_error($e);
  121. }
  122. $url = $authRequest->getAuthorizeURL();
  123. header('Location: ' . $url);
  124. exit;
  125. }
  126. /* Grab query string */
  127. if (! count($_POST)) {
  128. [, $queryString] = explode('?', $_SERVER['REQUEST_URI']);
  129. } else {
  130. // I hate php sometimes
  131. $queryString = file_get_contents('php://input');
  132. }
  133. /* Check reply */
  134. try {
  135. $message = new OpenID_Message($queryString, OpenID_Message::FORMAT_HTTP);
  136. } catch (Throwable $e) {
  137. Die_error($e);
  138. }
  139. $id = $message->get('openid.claimed_id');
  140. if (empty($id) || ! isset($AUTH_MAP[$id])) {
  141. Show_page('<p>User not allowed!</p>');
  142. exit;
  143. }
  144. $_SESSION['PMA_single_signon_user'] = $AUTH_MAP[$id]['user'];
  145. $_SESSION['PMA_single_signon_password'] = $AUTH_MAP[$id]['password'];
  146. $_SESSION['PMA_single_signon_HMAC_secret'] = hash('sha1', uniqid(strval(rand()), true));
  147. session_write_close();
  148. /* Redirect to phpMyAdmin (should use absolute URL here!) */
  149. header('Location: ../index.php');

If you intend to pass the credentials using some other means than, you have to implement wrapper in PHP to get that data and set it to $cfg['Servers'][$i]['SignonScript']. There is a very minimal example in examples/signon-script.php:

  1. <?php
  2. /**
  3. * Single signon for phpMyAdmin
  4. *
  5. * This is just example how to use script based single signon with
  6. * phpMyAdmin, it is not intended to be perfect code and look, only
  7. * shows how you can integrate this functionality in your application.
  8. */
  9. declare(strict_types=1);
  10. // phpcs:disable Squiz.Functions.GlobalFunction
  11. /**
  12. * This function returns username and password.
  13. *
  14. * It can optionally use configured username as parameter.
  15. *
  16. * @param string $user User name
  17. *
  18. * @return array
  19. */
  20. function get_login_credentials($user)
  21. {
  22. /* Optionally we can use passed username */
  23. if (! empty($user)) {
  24. return [
  25. $user,
  26. 'password',
  27. ];
  28. }
  29. /* Here we would retrieve the credentials */
  30. return [
  31. 'root',
  32. '',
  33. ];
  34. }

参见

$cfg['Servers'][$i]['auth_type'], $cfg['Servers'][$i]['SignonSession'], $cfg['Servers'][$i]['SignonCookieParams'], $cfg['Servers'][$i]['SignonScript'], $cfg['Servers'][$i]['SignonURL'], Example for signon authentication

Config 认证方式

  • This mode is sometimes the less secure one because it requires you to fill the $cfg['Servers'][$i]['user'] and $cfg['Servers'][$i]['password'] fields (and as a result, anyone who can read your config.inc.php can discover your username and password).
  • ISPs, multi-user installations 一节中将会说明如何保护您的配置文件。
  • 为了让该认证方式更加安全,您还可以考虑使用主机认证的 $cfg['Servers'][$i]['AllowDeny']['order']$cfg['Servers'][$i]['AllowDeny']['rules'] 指令。
  • 与 cookie 和 http 不同,在访问 phpMyAdmin 时 config 认证方式不会要求用户登录。虽然设计如此但这将导致任意用户都能访问。我们建议使用某些方式进行限制,如一个含有要求 HTTP 认证指令的 .htaccess 文件或者从路由器或防火墙设置禁止特定的 HTTP 访问(上述方法均不属于本文档的范围,但可以很容易地通过 Google 搜索到)。

加固您的 phpMyAdmin 安装

The phpMyAdmin team tries hard to make the application secure, however there are always ways to make your installation more secure:

  • Follow our Security announcements and upgrade phpMyAdmin whenever new vulnerability is published.

  • Serve phpMyAdmin on HTTPS only. Preferably, you should use HSTS as well, so that you’re protected from protocol downgrade attacks.

  • Ensure your PHP setup follows recommendations for production sites, for example display_errors should be disabled.

  • Remove the test directory from phpMyAdmin, unless you are developing and need a test suite.

  • 从phpMyAdmin中删除``setup``目录,初始设置后你可能不会使用它。

  • 正确选择认证方式 - Cookie 认证方式 是共享主机的最好选择。

  • Deny access to auxiliary files in ./libraries/ or ./templates/ subfolders in your webserver configuration. Such configuration prevents from possible path exposure and cross side scripting vulnerabilities that might happen to be found in that code. For the Apache webserver, this is often accomplished with a .htaccess file in those directories.

  • Deny access to temporary files, see $cfg['TempDir'] (if that is placed inside your web root, see also Web server upload/save/import directories.

  • It is generally a good idea to protect a public phpMyAdmin installation against access by robots as they usually can not do anything good there. You can do this using robots.txt file in the root of your webserver or limit access by web server configuration, see 1.42 How can I prevent robots from accessing phpMyAdmin?.

  • In case you don’t want all MySQL users to be able to access phpMyAdmin, you can use $cfg['Servers'][$i]['AllowDeny']['rules'] to limit them or $cfg['Servers'][$i]['AllowRoot'] to deny root user access.

  • 为您的账户启用 双因素身份验证

  • Consider hiding phpMyAdmin behind an authentication proxy, so that users need to authenticate prior to providing MySQL credentials to phpMyAdmin. You can achieve this by configuring your web server to request HTTP authentication. For example in Apache this can be done with:

    1. AuthType Basic
    2. AuthName "Restricted Access"
    3. AuthUserFile /usr/share/phpmyadmin/passwd
    4. Require valid-user

    Once you have changed the configuration, you need to create a list of users which can authenticate. This can be done using the htpasswd utility:

    1. htpasswd -c /usr/share/phpmyadmin/passwd username
  • If you are afraid of automated attacks, enabling Captcha by $cfg['CaptchaLoginPublicKey'] and $cfg['CaptchaLoginPrivateKey'] might be an option.

  • Failed login attemps are logged to syslog (if available, see $cfg['AuthLog']). This can allow using a tool such as fail2ban to block brute-force attempts. Note that the log file used by syslog is not the same as the Apache error or access log files.

  • In case you’re running phpMyAdmin together with other PHP applications, it is generally advised to use separate session storage for phpMyAdmin to avoid possible session-based attacks against it. You can use $cfg['SessionSavePath'] to achieve this.

Using SSL for connection to database server

It is recommended to use SSL when connecting to remote database server. There are several configuration options involved in the SSL setup:

$cfg['Servers'][$i]['ssl']

Defines whether to use SSL at all. If you enable only this, the connection will be encrypted, but there is not authentication of the connection - you can not verify that you are talking to the right server.

$cfg['Servers'][$i]['ssl_key'] and $cfg['Servers'][$i]['ssl_cert']

This is used for authentication of client to the server.

$cfg['Servers'][$i]['ssl_ca'] and $cfg['Servers'][$i]['ssl_ca_path']

The certificate authorities you trust for server certificates. This is used to ensure that you are talking to a trusted server.

$cfg['Servers'][$i]['ssl_verify']

This configuration disables server certificate verification. Use with caution.

参见

Google Cloud SQL with SSL, $cfg['Servers'][$i]['ssl'], $cfg['Servers'][$i]['ssl_key'], $cfg['Servers'][$i]['ssl_cert'], $cfg['Servers'][$i]['ssl_ca'], $cfg['Servers'][$i]['ssl_ca_path'], $cfg['Servers'][$i]['ssl_ciphers'], $cfg['Servers'][$i]['ssl_verify']

Known issues

Users with column-specific privileges are unable to “Browse”

If a user has only column-specific privileges on some (but not all) columns in a table, “Browse” will fail with an error message.

As a workaround, a bookmarked query with the same name as the table can be created, this will run when using the “Browse” link instead. Issue 11922.

Trouble logging back in after logging out using ‘http’ authentication

When using the ‘http’ auth_type, it can be impossible to log back in (when the logout comes manually or after a period of inactivity). Issue 11898.