【问题标题】:Does MySQL / MariaDB hash database passwords for PHP (7.x) mysqli_connect?MySQL / MariaDB 是否为 PHP (7.x) mysqli_connect 散列数据库密码?
【发布时间】:2018-09-29 05:24:56
【问题描述】:

请原谅初学者的问题。欢迎提出建议、链接和进一步阅读。

我担心网页的安全性并寻找最佳实践。 当使用 PHP 连接到 MariaDB/MySQL 数据库时,大多数建议将数据库密码放在 PHP 页面(或包含的页面)上。这安全吗?有更好的“最佳实践”吗?

我搜索了文档、Stack Overflow 和带有“哈希密码 MySQL MariaDB PHP7”等关键字的互联网,但答案都是关于客户端登录到网页,而不是 PHP 直接与 MariaDB 交互。 MySQL Docs 表示密码经过哈希处理以进行存储,但这对我的 PHP 文件没有帮助。 PHP docs 没有提供太多有用的信息,也没有实际示例。

所以,我的问题:

  1. HTTP 用户下载我的源文件并查看这些密码的风险有多高? (我意识到 PHP 会解析页面,因此一般用户不会看到原始代码或无法下载 PHP——而 ssh、PHP、MariaDB 等的安全性是一个单独的问题。)

    李>
  2. 我知道我可以散列密码,但是如果密码就在同一页面上,这有什么用? (或者我错过了什么?)

  3. 将数据库变量放在文件中更好/更安全,还是使用 include("super-sensitive-info.php") 并把变量 那里?我可以(应该)散列或加密那个文件还是 密码,并且仍然可以使用?我可以(我应该)隐藏这个文件吗? .super-sensitive-info.php),然后使用服务器安全来限制访问?

  4. 而且,使用特殊字符给我带来了麻烦,例如$password = "pa$$w@rd"; 应该看起来像 $password = "pa\$\$w\@rd";,按照典型的代码在引号中的做法?还是我错过了我不应该在 SQL 中使用特殊字符的备忘录?

创建一个简单的例子,假设我有两个文件,看起来像这样。有没有更好的办法?还是这个?

super-sensitive-info.php

$user = "username"
$password = "password" 
// $password = "pa\$\$w\@rd"; // (e.g. if database pw is "pa$$w@rd"?
$database_name = "database_name"

// I can hash it, but this seems only useful for client logins and such,
// unless I can hash this entire file....
// $hashed_password = password_hash($password, PASSWORD_DEFAULT);

index.php

include("super-sensitive-info.php")

$db = mysqli_connect('localhost',$user,$password,$database_name)
    or die('Error connecting to MySQL server: ' . mysqli_connect_error());

$query = "SELECT * FROM episodes";

【问题讨论】:

  • 您可以将配置文件移到 Web 可访问目录之外。如果您的密码中有$s,请确保您使用单引号进行封装。

标签: php mysql mariadb websecurity


【解决方案1】:

有关一些最佳实践,请查看最常用的框架代码。

简而言之,@chris85 提出了最重要的几点。通常它具有文件夹结构:

config/config.local.php
public/index.php

config/*.local.php 添加到 git 忽略:

$ echo "config/*.local.php">>.gitignore

config.php:

return [
  'db' => [
    'username' => '...',
    ...
  ]
];

index.php:

$config = require '../config.php';
$db = DbConnect($config['db']);
echo json_encode($db->getAllEpisodes());

从公共文件夹提供您的页面:

$ php -S localhost:8000 -t ./public/

【讨论】:

  • 这与我想要的非常接近。我无法使用您的语法让它工作,但我确实让它的工作方式略有不同。关于 gitignore 的好点。谢谢。
【解决方案2】:

您将身份验证实体(通常是服务器)验证提供给它的密码的方式与需要证明其凭据的实体(通常是客户端)存储其密码的方式混淆了。服务器,在您的示例中,mysql 数据库将密码存储为哈希值 - 因此即使数据泄露,也无法确定原始密码是什么。一个重要的特性是,当客户端希望进行身份验证时,它必须显示密码的明文,以便服务器可以重复散列过程。如果密码在客户端上经过哈希处理并发送到服务器,则验证将基于客户端提供的内容与服务器上存储的内容之间的精确匹配。明文的散列成为密码 - 这是very insecure

在 PHP/MySQL 实例的情况下,是的,您的 PHP 需要密码的明文,并且需要将其提供给数据库以进行身份​​验证。还有其他方法,但这些通常仅适用于您在身份验证两端控制代码的情况。因此,密码的明文可能比散列密码更容易暴露。

你不能存储 PHP 用来连接数据库哈希的密码。

在考虑保护明文的方法之前,您应该尽量减少可以使用明文的上下文。 MySQL 可以使用 x509 证书进行身份验证(这在 PHP 端由 mysqli 支持),但这实际上只是一个非常大的密码。最好在 mysql 中配置帐户,使其只能从特定地址(或单个 PHP/mysql 节点的 localhost)访问。

GRANT ALL ON yourdb.* TO 'phpuser'@'192.168.0.%';

..但如果您不控制基础架构,则不是很方便。

HTTP 用户下载我的源文件的风险有多高

当您知道如何以及由谁管理基础架构时,这很难量化。但是您似乎忽略了可能泄露数据的其他途径。

至于保护密码……

  • 正如其他人所说,如果您将密码存储在文件中,那么最好确保该文件位于文档根目录之外。

  • 将包含密码的文件命名为 .php 扩展名应该意味着如果网络服务器确实直接指向该文件,它将尝试执行它,而不是将内容返回给 http 客户端。虽然试图隐藏文件是默默无闻的安全,因此不是一个好主意,sign-posting 密码的存在不是一个好习惯。

  • 在 Apache(和其他一些网络服务器)的情况下,在文件名前加上“.ht”前缀通常会阻止网络服务器直接访问它

  • 您可以将 mysql 用户名和密码存储为 PHP ini setting(因此也可以存储在 .htaccess 文件中)。这是攻击者寻找密码的一个相当明显的地方 - 但在某些情况下可能是合适的。

加密密码只是意味着您需要找到安全的地方来存储加密密钥,而不是安全的地方来存储密码。

我是否错过了我不应该在 SQL 中使用特殊字符的备忘录?

您的数据库密码通常不会出现在 SQL 语句中(GRANT...IDENTIFIED BY.... 除外)。无论如何,只要对特殊字符进行了适当的转义,您就可以使用它们。但是特殊字符对于密码来说并不重要——一些系统坚持使用它们的原因是因为人类选择了容易猜到的密码。与使用 ASCII 字符集中的可打印字符随机生成的密码相比,自然语言单词的每个字符的熵大约只有一半 - 因此,10 个字符的随机密码与基于单词的 20 个字符的密码一样强。计算机非常擅长记住大量数据。在这种情况下使用随机密码是一种很好的做法。

如果您需要记住手动访问数据库的密码,请为此使用单独的帐户。

有时最好不要将密码保存在文件系统上——这样可以避免密码出现在上传到版本控制系统和备份中的风险。其他可以放密码的地方是环境,或者共享内存。 Linux 有一个很好的虚拟 HSM 功能,kernel key storage,但每次你想检索密码以连接到数据库时都在 shell 中运行是相当低效的(AFAIK 没有桥接 API 的 PHP 扩展)

【讨论】:

  • “但您似乎忽略了可能泄露数据的其他途径。” -- 这里是指SSH和其他开放端口吗?诚然,对于这个特定的问题,我并没有考虑它们,但它们在其他地方已经得到了很好的解决。 :) “您混淆了方式...... [验证实体与证明其凭据的实体]” - 是的,我混淆了他们。谢谢你的澄清。
  • SSH 和其他开放端口甚至都没有触及表面 - 我已经在此处的答案中写了比平常更多的内容 - 甚至解决了明显的路线(你似乎仍然没有意识到) 会花费我 很多 更长的时间。
  • 是的,感谢您的额外回答。我的问题是关于一个非常小而具体的问题,我没想到它会引发关于一般安全性的讨论。如果您对我可能遗漏的任何“明显路线”有具体建议、链接或进一步阅读,我想听听它们。再次感谢您的时间和帮助。
【解决方案3】:

您错过了 PHP 的一个非常重要的安全性:“绑定”或“转义”来自用户(或被黑 url)的参数,然后放入 SQL 查询中。

阅读“SQL 注入”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    相关资源
    最近更新 更多