簡體   English   中英

如何在 PHP 中保護數據庫密碼?

[英]How to secure database passwords in PHP?

當 PHP 應用程序建立數據庫連接時,它當然通常需要傳遞登錄名和密碼。 如果我為我的應用程序使用單一的、最低權限的登錄名,那么 PHP 需要在某處知道該登錄名和密碼。 保護該密碼的最佳方法是什么? 似乎只是在 PHP 代碼中編寫它並不是一個好主意。

一些人將此誤讀為關於如何在數據庫中存儲密碼的問題。 那是錯的。 它是關於如何存儲讓您訪問數據庫的密碼。

通常的解決方案是將密碼從源代碼中移到配置文件中。 然后讓系統管理員負責管理和保護該配置文件。 這樣開發人員不需要知道任何關於生產密碼的信息,並且在你的源代碼控制中沒有密碼記錄。

如果您托管在其他人的服務器上並且在您的 webroot 之外沒有訪問權限,您始終可以將您的密碼和/或數據庫連接放在一個文件中,然后使用 .htaccess 鎖定該文件:

<files mypasswdfile>
order allow,deny
deny from all
</files>

最安全的方法是根本沒有在 PHP 代碼中指定的信息。

如果您使用 Apache,則意味着在 httpd.conf 或虛擬主機文件文件中設置連接詳細信息。 如果這樣做,您可以不帶參數調用 mysql_connect(),這意味着 PHP 永遠不會輸出您的信息。

這是在這些文件中指定這些值的方式:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

然后你像這樣打開你的 mysql 連接:

<?php
$db = mysqli_connect();

或者像這樣:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));

將它們存儲在 Web 根目錄之外的文件中。

對於極其安全的系統,我們在配置文件中加密數據庫密碼(它本身由系統管理員保護)。 在應用程序/服務器啟動時,應用程序會提示系統管理員輸入解密密鑰。 然后從配置文件中讀取數據庫密碼,解密並存儲在內存中以備將來使用。 仍然不是 100% 安全,因為它存儲在已解密的內存中,但您必須在某個時候稱其為“足夠安全”!

此解決方案是通用的,因為它對開源和閉源應用程序都很有用。

  1. 為您的應用程序創建操作系統用戶。 http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. 使用密碼為該用戶創建一個(非會話)操作系統環境變量
  3. 以該用戶身份運行應用程序

好處:

  1. 您不會意外地將密碼檢查到源代碼管理中,因為您不能
  2. 您不會意外搞砸文件權限。 嗯,你可能會,但它不會影響這個。
  3. 只能由 root 或該用戶讀取。 無論如何,root 都可以讀取您的所有文件和加密密鑰。
  4. 如果您使用加密,您如何安全地存儲密鑰?
  5. 適用於 x 平台
  6. 確保不要將 envvar 傳遞給不受信任的子進程

這個方法是 Heroku 推薦的,非常成功。

如果可以在存儲憑據的同一文件中創建數據庫連接。 在連接語句中內聯憑據。

mysql_connect("localhost", "me", "mypass");

否則最好在 connect 語句之后取消設置憑據,因為不在內存中的憑據無法從內存中讀取;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  

以前我們將數據庫用戶/密碼存儲在配置文件中,但此后已進入偏執模式——采用深度防御策略。

如果您的應用程序受到威脅,用戶將擁有對您的配置文件的讀取權限,因此破解者有可能讀取此信息。 配置文件也可能陷入版本控制,或在服務器上復制。

我們已經切換到在 Apache VirtualHost 中設置的環境變量中存儲用戶/密碼。 這個配置只能被 root 讀取——希望你的 Apache 用戶沒有以 root 身份運行。

與此相反的是,現在密碼在全局 PHP 變量中。

為了降低這種風險,我們采取了以下預防措施:

  • 密碼是加密的。 我們擴展 PDO 類以包含解密密碼的邏輯。 如果有人閱讀了我們建立連接的代碼,那么很明顯連接是使用加密密碼而不是密碼本身建立的。
  • 加密的密碼從全局變量移動到私有變量應用程序立即執行此操作以減少該值在全局空間中可用的窗口。
  • phpinfo()被禁用。 PHPInfo 是一個簡單的目標,可以了解所有內容,包括環境變量。

如果您使用的是 PostgreSQL,那么它會自動在~/.pgpass查找密碼。 有關更多信息,請參閱手冊

您的選擇是有限的,因為您說訪問數據庫需要密碼。 一種通用方法是將用戶名和密碼存儲在單獨的配置文件而不是主腳本中。 然后確保將其存儲在主網絡樹之外。 那是如果存在 Web 配置問題,使您的 php 文件僅顯示為文本而不是被執行,則您沒有公開密碼。

除此之外,您處於正確的行上,對正在使用的帳戶的訪問權限最小。 添加到那個

  • 不要將用戶名/密碼組合用於其他任何用途
  • 將數據庫服務器配置為僅接受來自該用戶的 Web 主機的連接(如果數據庫位於同一台計算機上,則 localhost 甚至更好)這樣即使公開了憑據,它們也不會對任何人有用,除非他們有其他訪問權限機器。
  • 混淆密碼(即使 ROT13 也可以),如果某些人確實可以訪問該文件,它不會提供太多防御,但至少可以防止隨意查看它。

彼得

我們是這樣解決的:

  1. 在服務器上使用 memcache,從其他密碼服務器打開連接。
  2. 將密碼(甚至所有已加密的 password.php 文件)和解密密鑰保存到 memcache。
  3. 該網站調用保存密碼文件密碼的內存緩存密鑰,並在內存中解密所有密碼。
  4. 密碼服務器每 5 分鍾發送一個新的加密密碼文件。
  5. 如果您在您的項目中使用加密的 password.php,您將進行審核,以檢查該文件是否被外部接觸或查看。 發生這種情況時,您可以自動清理內存,並關閉服務器以進行訪問。

將數據庫密碼放在一個文件中,使其對提供文件的用戶只讀。

除非您有某種方法只允許 php 服務器進程訪問數據庫,否則您幾乎可以做到這一點。

另一個技巧是使用一個 PHP 單獨的配置文件,如下所示:

<?php exit() ?>

[...]

Plain text data including password

這不會阻止您正確設置訪問規則。 但是如果您的網站被黑,“require”或“include”只會在第一行退出腳本,因此獲取數據更加困難。

然而,永遠不要將配置文件放在可以通過 Web 訪問的目錄中。 您應該有一個“Web”文件夾,其中包含您的控制器代碼、css、圖片和 js。 就這樣。 其他任何內容都在脫機文件夾中。

如果您談論的是數據庫密碼,而不是來自瀏覽器的密碼,那么標准做法似乎是將數據庫密碼放在服務器上的 PHP 配置文件中。

您只需要確保包含密碼的 php 文件對其具有適當的權限。 即它應該只能由 Web 服務器和您的用戶帳戶讀取。

通常的做法是將它放入某個配置文件中。 只要確保你:

  1. 禁止從網絡外的任何服務器訪問數據庫,
  2. 注意不要意外地向用戶顯示密碼(在錯誤消息中,或通過 PHP 文件意外地作為 HTML 等提供。)

最好的方法是根本不存儲密碼!
例如,如果您在 Windows 系統上連接到 SQL Server,則可以使用集成身份驗證連接到數據庫,無需密碼,使用當前進程的標識。

如果你需要一個密碼時,先進行加密連接,使用強大的加密(例如,使用AES-256,然后保護加密密鑰,或使用非對稱加密,並有操作系統保護證書),然后將其存儲在一個具有強 ACL 的配置文件(在 web 目錄之外)。

實際上,最佳做法是將數據庫憑據存儲在環境變量中,因為:

  • 這些憑據取決於環境,這意味着您在 dev/prod 中不會擁有相同的憑據。 將它們存儲在所有環境的同一個文件中是錯誤的。
  • 憑證與業務邏輯無關,這意味着登錄名和密碼在您的代碼中無關。
  • 您可以在不創建任何業務代碼類文件的情況下設置環境變量,這意味着您永遠不會犯將憑證文件添加到 Git 中的提交的錯誤。
  • 環境變量是超級全局變量:您可以在代碼中的任何地方使用它們,而無需包含任何文件。

如何使用它們?

  • 使用 $_ENV 數組:
    • 設置: $_ENV['MYVAR'] = $myvar
    • 得到echo $_ENV["MYVAR"]
  • 使用php函數:
    • 使用putenv("MYVAR=$myvar");函數設置 - putenv("MYVAR=$myvar");
    • 使用getenv 函數- getenv('MYVAR');
  • 在 vhosts 文件和 .htaccess 中,但不建議這樣做,因為它在另一個文件中,並且通過這種方式無法解決問題。

您可以輕松地刪除包含所有環境變量的文件,例如 envvars.php 並執行它( php envvars.php )並刪除它。 這有點老派,但它仍然有效,並且您在服務器中沒有任何帶有憑據的文件,並且代碼中沒有憑據。 由於它有點費力,框架做得更好。

Symfony 示例(好吧,不僅是 PHP) Symfony 等現代框架建議使用環境變量,並將它們存儲在 .env 未提交文件中或直接存儲在命令行中,這意味着您可以這樣做:

文件:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM