当PHP应用程序进行数据库连接时,当然通常需要传递登录名和密码。如果我对应用程序使用单一的、最小权限的登录,那么PHP需要知道该登录名和密码。保护密码的最佳方法是什么?似乎用PHP代码编写它不是个好主意。
- 为了完全安全,您需要建立一个SSL连接,否则网络上的任何人都可以嗅探您输入的密码。
- 您是指连接字符串中使用的用户密码还是数据库密码?
- 连接字符串中使用的数据库密码。谢谢!
有几个人把这理解为一个关于如何在数据库中存储密码的问题。那是错误的。它是关于如何存储允许您访问数据库的密码。
通常的解决方案是将密码从源代码移到配置文件中。然后由系统管理员负责管理和保护该配置文件。这样,开发人员就不需要知道任何有关生产密码的信息,并且在源代码管理中也没有密码记录。
- 谢谢。如果我正确理解了这一点,那么PHP文件将在配置文件中包含一个include,允许它使用密码。例如,我创建了一个名为"app1_db_cfg.php"的文件,它存储登录名、pword和db名称。然后我的application.php页面包含"app1_db_cfg.php",我就开始工作了!
- 是的,我通常会定义("db_name","mydb");等等,在更多的页面上定义您将要使用的任何内容也很方便,稍后您可能会更改这些内容。
- 只将密码保存在配置文件中并不安全。它需要适当的保护,使用强大的ACL和具有适当保护密钥的强加密…请看下面我的帖子。
- 我同意配置需要得到适当的保护。然而,了解如何做到这一点是系统管理员的工作,而不是开发人员的工作。在这种情况下,我不同意强加密的价值。如果你不能保护你的配置文件,你为什么认为你可以保护你的密钥?
- 我更喜欢使用只允许从Web服务器访问数据库的数据库帐户。然后我就不需要加密配置了,我只是把它存储在web根目录之外。
- @Bentilly,这就是强大的密钥管理的切入点,这绝对应该是开发人员的责任,而不是管理人员的责任——尽管管理人员在这里也有一些任务。
- @所以当你不暴露敏感数据的时候就不需要加密了?不加密,因为你不认为任何没有特权的人会得到访问对我来说听起来很奇怪-这使得我的签证上的密码没用,因为没有人应该得到它。编辑:对不起,有人挖了一根旧线
- @gnut:"我只是把它存储在web根目录之外。".webroot外的字符串有什么帮助?正如我在现代开放源码脚本中看到的那样,我要求包含db密码的配置文件位于根目录中。我不喜欢这样,我想知道我是否会麻烦。
- @马修拉帕蒂…实际上,我正在解决常量中的密码问题,因为其他开发人员可以简单地执行get_defined_constants()。
- 我使用一个apache环境变量来设置路径,这样即使文件的路径在源代码中也是未知的。这也很好地允许根据服务器上的Apache设置为开发和生产使用不同的密码。
- 请记住,即使存储在Web可访问目录之外的文件也必须由使用它们的脚本读取。如果有人包含该文件,那么从该文件中转储数据,他们将看到密码。
- 对于所有问我如何保护自己不受他人伤害的人来说,答案是要么自己管理整个公司,要么你必须信任至少一个人。
- @Henk对此没有解决办法。您必须信任或小心将要进入生产服务器的所有脚本的内容。
- @Rickmacgillis If someone includes that file, then dumps the data from the file, they will see the password你怎么处理这个问题?
- @Tonix这个问题更多的是开源软件的问题,因为您将了解该文件的变量或布局。因此,对于设置这些变量,define是一个坏主意。(例如,wordpress使用的是不安全的方法,并且它在Web可访问目录中。)我指出的问题是,如果有人能够上传文件,他们可以发现该文件中的密码。但是,即使有人可以轻松地转储使用define创建的密码,laravel的.env或基于数组的配置文件也只是稍微好一些。每个文件都容易受到攻击。
- 要首先避免此问题,请使用密码服务器并查询服务器以获取所需的信息。AWS KMS可以通过在文件系统中对密码进行加密来进一步保护您的密码,并且只能使用Redis在内存中对其进行解密。网址:aws.amazon.com/kms
- 同样,如果有人可以在你的网站上放置一个文件并运行它,你会遇到比丢失密码更大的问题。那个文件可以做任何事情。
如果您托管在其他人的服务器上,并且在您的Webroot之外没有访问权限,则可以始终将密码和/或数据库连接放在文件中,然后使用.htaccess锁定文件:
1 2 3 4
| <files mypasswdfile>
order allow,deny
deny from all
</files> |
- 谢谢,这正是我要找的。
- 很有用,如果它是真正安全的,尽管看起来shell登录仍然可以访问。
- 当然,但是如果有人可以访问shell,那么您的整个帐户都会受到损害。
- 没有真正的解决办法。任何人都可以使用文件中的转储函数,将文件上载到生产服务器并执行它。你掌握了生产服务器的所有秘密!
- 这是一种糟糕的做法,因为您可能会意外地将凭据提交到存储库。
- @如果一个不友好的人可以将一个文件上传到服务器并执行它,那么服务器就没有正确配置。
- @Porlune:开发人员应该让他们的版本控制系统忽略密码文件,即使用.gitignore。但是是的,应该注意包含敏感数据的文件。
最安全的方法是根本不要在PHP代码中指定信息。
如果您使用的是Apache,这意味着在httpd.conf或虚拟主机文件中设置连接详细信息。如果这样做,就可以不带参数调用mysql_connect(),这意味着PHP永远不会输出您的信息。
以下是在这些文件中指定这些值的方式:
1 2 3
| php_value mysql.default.user myusername
php_value mysql.default.password mypassword
php_value mysql.default.host server |
号
然后打开MySQL连接,如下所示:
或者像这样:
。
- 请检查ini-get("默认值")php.net/manual/en/class.mysqli.php的正确值。
- 可以在他们的.htaccess文件中使用这个吗?
- @用户1193509是。
- 是的,但是任何用户(或者滥用写得很糟糕的PHP脚本的黑客)都可以通过ini_get()读取密码。
- @marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()你怎么处理这个问题?
- marki555说,可以运行PHP代码的攻击者也可以调用PHP函数,这显然是正确的,不可能做些什么。我还想补充一点,我不再遵循我自己在这个答案中给出的建议,而是使用环境变量。不过,其概念类似:不要将凭证存储在代码中,而是以某种方式注入它们。使用ini_get()或getenv()并不重要。
- @Tonix已经写过了,如果"好"脚本可以访问数据库密码,那么"坏"脚本也可以。因此,您唯一的选择是检测这些脚本,并且不允许它们运行,例如使用mod_securityApache模块,尽管正确地调整规则并不容易。
- @marki555我可以考虑使用单个数据库连接入口点,在这里我读取数据库的密码和用户名,并将它们传递到连接引擎,以便获得数据库连接,然后取消设置这些变量。在这一点上,我需要注意每个人对代码库的推送,并确保该入口点文件没有任何更改,并且没有人试图以某种方式转储数据库的密码。够了吗?
- 将pass-in配置文件放在根目录之外,将其暴露于可以从网站中的任何位置注入和执行的ini_get()或getenv()会更安全。
- @deepblue如果你可以注入ini_get(),你也可以注入file_get_contents(anypath)。只要php有办法获取密码,任何恶意代码也会有办法。
- 我认为这是一个非常糟糕的主意,如果服务器有一个phpinfo()浮动,这将泄漏您的密码。
将它们存储在Web根目录之外的文件中。
- 而且,正如其他地方提到的,在源代码管理之外。
- 我们可以把它包括进去吗?例如,在PHP中,我们可以执行include('../otherDirectory/configfile.conf')吗?
- 你们都建议在WWWROOT之外存储凭证。好的,我了解安全背景。但它应该如何存储在版本控制中呢(示例配置)?通常,wwwroot是git repo的根,所以如果有任何外部的东西,它将在vc之外。想象一下,新开发人员试图建立一个本地的开发实例——他怎么知道"把这个文件复制到外面并填写"这样的魔力呢?
对于非常安全的系统,我们在配置文件中加密数据库密码(该文件本身由系统管理员保护)。在应用程序/服务器启动时,应用程序会提示系统管理员提供解密密钥。然后从配置文件中读取数据库密码,解密并存储在内存中以备将来使用。仍然不是100%安全,因为它存储在解密的内存中,但您必须在某个时刻称之为"足够安全"!
- 如果管理员死了怎么办?
- @Radumurzea这太荒谬了。你什么时候听说过SysAdmins会死?他们就像麦当劳一样,不知从何处出现/消失!
- @RaduMurzea只有2个或更多的管理员,然后您就有了类似于RAID阵列的奇偶校验。每次不止一个驱动器出现故障的几率要低得多。
- 服务器什么时候重新启动呢?那么唤醒管理员让他们输入密码所需的时间呢?等等。哈哈。
- IAM 100%同意,这是OracleWebLogic用boot.properties完成的。
- 不知道"存储在内存"是什么意思。PHP Web应用程序通常不会将任何内容存储在内存中超过响应单个请求查看页面所需的时间。
- @bdsl redis或memcache
- @元素11只是要确保他们不会一起开车去麦当劳吃午饭!
此解决方案是通用的,因为它对开放源代码和封闭源代码应用程序都很有用。
为应用程序创建操作系统用户。请参阅http://en.wikipedia.org/wiki/principle-of-least-u特权
使用密码为该用户创建(非会话)OS环境变量
以该用户身份运行应用程序
优势:
您不会意外地将密码检查到源代码管理中,因为您不能
您不会意外地破坏文件权限。嗯,你可能会,但这不会影响到这个。
只能由根用户或该用户读取。根可以读取所有文件和加密密钥。
如果使用加密,如何安全地存储密钥?
工程X平台
确保不要将envvar传递给不受信任的子进程
这个方法是由非常成功的Heroku提出的。
如果可以在存储凭据的同一文件中创建数据库连接。在connect语句中内联凭据。
号
否则,最好在connect语句后取消设置凭据,因为不在内存中的凭据无法从内存中读取;)
1 2 3
| include("/outside-webroot/db_settings.php");
mysql_connect("localhost", $db_user, $db_pass);
unset ($db_user, $db_pass); |
- 如果有人能进入记忆,你就完蛋了。这是毫无意义的假保安。在webroot之外(或者至少受.htaccess保护,如果您没有超过webroot的访问权限)是唯一安全的选项。
- @这就像是说,仅仅因为有人可以用乙炔火炬切断你的网络运营中心的锁,这意味着这扇门也是假的安全。将敏感信息限制在尽可能小的范围内总是有意义的。
- 回音$db_用户或打印$db_通行证怎么样?即使是同一团队的开发人员也不应该能够计算出生产凭证。代码不应包含关于登录信息的任何可打印内容。
您的选择是有限的,正如您所说,您需要密码来访问数据库。一种通用的方法是将用户名和密码存储在单独的配置文件中,而不是主脚本中。然后一定要将其存储在主Web树之外。也就是说,如果存在Web配置问题,使您的PHP文件只显示为文本而不是执行,那么您还没有暴露密码。
除此之外,您在正确的线路上,对正在使用的帐户的访问权限最小。加上这个
- 不要将用户名/密码组合用于其他任何内容
- 将数据库服务器配置为仅接受来自该用户的Web主机的连接(如果数据库在同一台计算机上,则localhost更好),这样即使凭据公开,也不会对任何人使用它们,除非它们具有对该计算机的其他访问权。
- 混淆密码(即使rot13也可以),如果某些人确实访问了该文件,它不会起到太大的保护作用,但至少它会阻止随意查看该文件。
彼得
如果您使用的是PostgreSQL,那么它会在~/.pgpass中自动查找密码。有关更多信息,请参阅手册。
以前我们把db user/pass存储在一个配置文件中,但后来又进入了偏执模式——采用了深度防御策略。
如果您的应用程序受到威胁,那么用户将具有对您的配置文件的读取权限,因此可能有黑客读取此信息。配置文件也可以被版本控制捕获,或者在服务器周围复制。
我们已经切换到存储在ApacheVirtualHost中设置的用户/传递环境变量。这个配置只能由根目录读取——希望您的Apache用户没有以根目录运行。
这样做的缺点是,现在密码在一个全局php变量中。
为了减轻这种风险,我们采取了以下预防措施:
- 密码已加密。我们扩展了pdo类以包含用于解密密码的逻辑。如果有人读取了我们建立连接的代码,那么很明显连接是用加密密码而不是密码本身建立的。
- 加密的密码将从全局变量移动到一个私有变量中。应用程序会立即执行此操作,以减少该值在全局空间中可用的窗口。
- phpinfo()被禁用。phpinfo是获取包括环境变量在内的所有内容的简单目标。
将数据库密码放在文件中,使其对提供文件的用户为只读。
除非您有一些只允许PHP服务器进程访问数据库的方法,否则这几乎是您所能做的。
如果您谈论的是数据库密码,而不是来自浏览器的密码,那么标准做法似乎是将数据库密码放在服务器上的php配置文件中。
您只需要确保包含密码的PHP文件对其具有适当的权限。也就是说,它只能由Web服务器和您的用户帐户读取。
- 不幸的是,php-config文件可以被phpinfo()读取,如果有人碰巧在后面留下了一些测试脚本,幸运的攻击者将能够读取密码。最好将连接密码保存在Web服务器根目录之外的文件中。然后,访问它的唯一方法是使用shell或执行任意代码,但在这种情况下,所有安全性都将丢失。
最好的办法是根本不存储密码!例如,如果您使用的是Windows系统,并且连接到SQL Server,则可以使用集成身份验证,使用当前进程的标识,在没有密码的情况下连接到数据库。
如果您确实需要使用密码进行连接,请首先使用强加密(例如使用AES-256,然后保护加密密钥,或者使用非对称加密并让操作系统保护证书)对其进行加密,然后将其存储在具有强ACL的配置文件(在Web目录之外)中。
- 再次加密密码没有意义。可以获取未加密密码的人也可以获取解密密码所需的任何密码短语。但是,使用acls&;htaccess是一个好主意。
- @我想你可能误解了"再次加密"是什么意思?这只是一个加密。而且,您不希望使用密码(供人使用)对其进行加密,而是使用强大的密钥管理(例如,受操作系统保护),这样简单地访问文件系统就不会授予对密钥的访问权限。
- 加密不是神奇的-您可以将密码存储在那里,而不是用ACL保护AES密钥。访问AES密钥和解密的密码没有区别,在此上下文中的加密只是蛇油。
- @马里奥维拉斯什么?如果密码是加密的,加密密钥受操作系统保护,有什么区别呢?加密不是魔术-它只是把所有的秘密压缩成更小的加密密钥。在这种情况下,它将所有的秘密都转移到操作系统中,这几乎不是什么蛇毒。
- @贪婪的操作系统怎么能保护密钥而不是数据本身呢?答:它可以同时保护两者,所以加密并没有真正的帮助。如果只存储了数据,并且加密密钥是从一个必须由用户键入的密码派生出来的,那就不同了。
把它放在某个配置文件中通常是这样做的。只要确保你:
禁止从网络之外的任何服务器访问数据库,
注意不要意外地向用户显示密码(在错误消息中,或通过php文件意外地被用作html等)。
我们以这种方式解决了这个问题:
使用服务器上的memcache,并打开与其他密码服务器的连接。
保存到memcache的密码(甚至是所有加密的password.php文件)和解密密钥。
网站,调用保存密码文件密码的memcache密钥并在内存中解密所有密码。
密码服务器每5分钟发送一个新的加密密码文件。
如果在您的项目中使用encrypted password.php,您将进行一次审计,检查这个文件是外部接触的还是查看的。当发生这种情况时,您可以自动清理内存,并关闭服务器进行访问。
另一个技巧是使用一个php独立的配置文件,其外观如下:
1 2 3 4 5
| <?php exit() ?>
[...]
Plain text data including password |
这并不妨碍您正确设置访问规则。但是,如果您的网站被黑客攻击,"require"或"include"只会在第一行退出脚本,因此更难获取数据。
不过,不要让配置文件位于可以通过Web访问的目录中。您应该有一个"web"文件夹,其中包含您的控制器代码、CSS、图片和JS。这就是全部。脱机文件夹中还有其他内容。
- 但是PHP脚本如何读取存储在文件中的凭证呢?
- 您使用fopen(),就像对常规文本文件一样。
- @e-satis好吧,做require/include会阻止黑客,但是怎么做fopen呢?
- "这不会阻止您正确设置访问规则"