2011-06-23 55 views
43

我有一個簡單的網站,我使用PDO建立了與Mysql服務器的連接。爲什麼PDO在連接失敗時打印我的密碼?

$dbh = new PDO('mysql:host=localhost;dbname=DB;port=3306', 'USER', 
'SECRET',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 

我在我的網站上有一些流量,服務器連接數達到了限制,網站拋出這個錯誤,我的PLAIN密碼!

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[08004] [1040] Too many connections' in /home/domain/html/index.php:xxx Stack trace: #0 /home/domain/html/index.php(64): PDO->__construct('mysql:host=loca...', 'USER', 'SECRET', Array) #1 {main} thrown in /home/domain/html/index.php on line 64

諷刺的是,我切換到PDO出於安全考慮,所以這真的讓我震驚,因爲這個確切的錯誤是你可以挑起用簡單的HTTP洪水大多數網站非常容易。

我現在已經將我的連接包裝在try/catch塊中,但我認爲這是災難性的!

我是新來的PDO,所以我的問題是:我必須做什麼才能認爲是安全的?如何以安全的方式建立連接?是否還有其他已知的安全漏洞,像我必須注意的那樣?

+0

參見:http://stackoverflow.com/questions/5811834/why -would-this-be-poor-php-code/5811853#5811853對於使用動態表/數據庫/列名稱時,以及如何堵住那個洞。 – Johan

+0

我完全同意關閉生產中的錯誤,嘗試/捕捉和類似的東西,但考慮如果你有一個程序員的離岸「團隊」,密碼不應該被「初級」程序員所知,這就如你所說一個「災難性」的安全漏洞。更何況,新手程序員根本不在乎關閉錯誤。有了這個說法,我很困惑這個決定揭露密碼錯誤。 – IMB

+0

聖摩爾這是施克!哦,我的上帝!這絕對是無恥的!你需要更多的讚揚,只是爲了保持冷靜,不要進入CAPS RAGE。 – Sharky

回答

16

無論如何,您應該在PHP.ini中有display_errors = off以避免此問題。揭示這些細節的錯誤來自許多地方,除了PDO之外。

是的,你也應該在try/catch塊中。

您也可以$pdo->setAttribute(PDO::ERRMODE_SILENT),但您需要手動檢查錯誤代碼,而不是使用try/catch塊。有關更多錯誤常量,請參閱http://php.net/manual/en/pdo.setattribute.php

+12

好吧,我明白,但我仍然認爲默認應該是安全的一面... –

+2

@Joe,那麼你應該把它與PDO開發者。它看起來沒有問題,像這樣從堆棧中返回信息。一旦你意識到這一點,這不是一個問題。當然,try/catch會在某些應用程序中被遺忘......不可避免地,這對某些人來說是一個問題......你說得對。 – Brad

+1

這兩個建議似乎都不適合我。當連接失敗時,錯誤堆棧將顯示在純文本密碼可見的屏幕上。我正在使用PHP ActiveRecord。 –

6

好吧,這讓我咯咯地笑了一下,使用錯誤報告是爲了調試目的,它可以讓你快速找到並解決問題。

當你在一個實時環境中時,你的服務器應該只配置爲內部日誌記錄,而不是直接輸出,所以基本上你需要關閉你的php.ini內的錯誤輸出。

display_errors = Off 

但是,當您處於測試環境中時,此堆棧僅僅是一個幫助您的工具,並且是可配置的。

當在實時環境中發生錯誤時,它們將被記錄,所以您應該始終檢查您的日誌文件,然後相應地進行修復。

人們可能會指定您可以管理您的PHP應用程序中的錯誤,但通過個人偏好我認爲這是錯誤的方式去配置您的網絡服務器和MySQL/MsSQL的INI和配置文件將導致管理更加尖銳。

如果您的應用程序是公共應用程序,那麼在應用程序內處理錯誤也是一個好主意,因爲大部分客戶端可能在共享主機上,並且不能完全訪問服務器配置。

+0

你不想在你的日誌文件中輸入密碼...... – HackSlash

7

簡單的解決方法是趕上PDOException通過PDO構造函數拋出:

try { 
    $dbh = new PDO('mysql:host=localhost;dbname=DB;port=3306', 'USER', 
    'SECRET',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 
} catch (PDOException $e) { 
    throw new Exception('Could not connect to database'); 
} 
+0

......這就是讓開發者沒有錯誤信息,否則會幫助他們解決問題。 –

+1

獲取異常「無法連接到數據庫」會使開發人員沒有任何信息?我不這麼認爲 – Matthias

+3

基本概念不好。沒有人應該將簡單的密碼放入對象中並將其保存在內存中。正確的解決方案是更改PDO代碼,而不是將簡單密碼放入異常消息中。我認爲這是PDO本身的錯誤和安全漏洞。 – nagylzs

1

我們使用編碼的用戶名和密碼,並解碼這些在PDO構造,那麼我們趕上PDOException並拋出一個新的PDOException與老例外其消息,以便跟蹤將只顯示編碼的用戶名和密碼。

爲PHP良好的加密庫是:化解/ PHP-加密

https://github.com/defuse/php-encryption

示例代碼:

<?php 
class myPDOWrapper extends PDO 
    { 

     public function __construct(string $dns, string $encodedUser, string $encodedPassword) 
     { 
      try { 
       parent::__construct($dns, $this->decodeFunction($encodedUser), $this->decodeFunction($encodedPassword), 
        [ 
         PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 
        ] 
       ); 
      } 
      catch (PDOException $exception) { 
       throw new PDOException($exception->getMessage()); 
      } 
     } 

     private function decodeFunction(string $encoded): string 
     { 
      return \Defuse\Crypto\Crypto::decrypt($encoded, $this->decodeKey()); 
     } 

     private function decodeKey(): \Defuse\Crypto\Key 
     { 
      static $key = null; 

      if(null === $key) { 
       $key = \Defuse\Crypto\Key::loadFromAsciiSafeString(getenv('MY_PDO_DECODE_KEY')); 
      } 

      return $key; 
     } 
    }