2011-06-23 64 views
43

Tôi có một trang web đơn giản, nơi tôi thiết lập kết nối với máy chủ Mysql bằng PDO.Tại sao PDO in mật khẩu của tôi khi kết nối không thành công?

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

Tôi đã gặp phải một số lưu lượng truy cập trên trang web của mình và giới hạn kết nối máy chủ và trang web gửi lỗi này với mật khẩu PLAIN của tôi!

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

Trớ trêu thay tôi chuyển sang PDO vì lý do bảo mật, vì lỗi chính xác này là điều bạn có thể gây ra rất dễ dàng trên hầu hết các trang web sử dụng http lụt đơn giản.

Tôi hiện đã bao gồm kết nối của mình trong khối thử/nắm bắt, nhưng tôi vẫn nghĩ rằng điều này thật thảm khốc!

Tôi mới tham gia PDO và câu hỏi của tôi là: tôi phải làm gì để cân nhắc an toàn? Làm cách nào để thiết lập kết nối theo cách an toàn? Có lỗ hổng bảo mật nào khác được biết đến như cái này mà tôi phải biết không?

+0

Xem: http://stackoverflow.com/questions/5811834/why -would-this-be-poor-php-code/5811853 # 5811853 Đối với lỗ khi sử dụng tên bảng/db/cột động và cách cắm lỗ đó. – Johan

+0

Tôi hết lòng đồng ý với việc tắt các lỗi trong sản xuất, thử/nắm bắt và các công cụ như vậy nhưng hãy xem xét nếu bạn đang có một "nhóm" ra nước ngoài của những kẻ progammers, nơi mà các lập trình viên "cơ sở" không biết mật khẩu, như bạn đã nói một lỗ hổng bảo mật "thảm khốc". Chưa kể, những lập trình viên mới làm quen không quan tâm đến việc tắt các lỗi. Với điều đó đã nói, tôi bị bối rối bởi quyết định này để tiết lộ mật khẩu do lỗi. – IMB

+0

Moly thánh này là SICK! ÔI CHÚA ƠI! Điều này là hoàn toàn thái quá! Bạn cần nhiều upvotes chỉ để giữ cho mát mẻ của bạn và không đi vào CAPS RAGE. – Sharky

Trả lời

16

Bạn phải có display_errors = off trong PHP.ini của mình để tránh vấn đề này. Các lỗi tiết lộ các chi tiết như thế này đến từ nhiều nơi, ngoài PDO.

Có, bạn cũng nên có nó trong khối thử/nắm bắt.

Bạn cũng có thể $pdo->setAttribute(PDO::ERRMODE_SILENT), nhưng sau đó bạn cần phải kiểm tra mã lỗi theo cách thủ công thay vì sử dụng khối try/catch. Xem http://php.net/manual/en/pdo.setattribute.php để biết thêm các hằng số lỗi.

+12

ok tôi hiểu điều đó nhưng tôi vẫn nghĩ rằng mặc định phải là bên an toàn ... –

+2

@ Joe, sau đó bạn nên thực hiện điều đó với các nhà phát triển PDO. Tôi thấy không có vấn đề với nó trở về thông tin từ ngăn xếp như thế này. Một khi bạn nhận thức được nó, nó không phải là một vấn đề. Tất nhiên, thử/bắt sẽ bị lãng quên trên một số ứng dụng ... chắc chắn nó sẽ là một vấn đề đối với một số ... bạn đúng về điều đó. – Brad

+1

Cả hai đề xuất này dường như không hoạt động đối với tôi. Khi kết nối không thành công, ngăn xếp lỗi được in ra màn hình với mật khẩu văn bản thuần có thể nhìn thấy. Tôi đang sử dụng PHP ActiveRecord. –

6

Ok điều này làm tôi cười khúc khích một chút, việc sử dụng báo cáo lỗi là dành cho mục đích gỡ lỗi, nó cho phép bạn nhanh chóng tìm và khắc phục sự cố.

Khi bạn ở trong môi trường trực tiếp, máy chủ của bạn sẽ được cấu hình để chỉ ghi nhật ký nội bộ, chứ không phải đầu ra trực tiếp, vì vậy về cơ bản bạn sẽ cần tắt đầu ra lỗi trong số php.ini.

display_errors = Off 

Nhưng khi bạn ở trong môi trường thử nghiệm, ngăn xếp này chỉ đơn thuần là công cụ giúp bạn và có thể định cấu hình.

Khi lỗi xảy ra trong môi trường trực tiếp, chúng sẽ được ghi lại, vì vậy bạn nên luôn kiểm tra tệp nhật ký của mình và sau đó sửa lỗi tương ứng.

Mọi người có thể chỉ định rằng bạn có thể quản lý lỗi trong ứng dụng PHP nhưng theo sở thích cá nhân, tôi nghĩ đây là cách sai lầm, cấu hình INI và cấu hình tệp cho máy chủ web và MySQL/MsSQL của bạn quản lý cấp tính hơn. Nếu ứng dụng của bạn là một ứng dụng công cộng thì nó cũng sẽ là một ý tưởng tốt để xử lý các lỗi trong ứng dụng vì một tỷ lệ lớn các khách hàng có thể được chia sẻ lưu trữ và không có quyền truy cập đầy đủ vào cấu hình máy chủ.

+0

Bạn không muốn mật khẩu trong tệp nhật ký của mình ... – HackSlash

7

Simple workaround nó để bắt PDOException ném bởi PDO constructor:

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

... để lại nhà phát triển không có thông báo lỗi nếu không sẽ giúp họ giải quyết vấn đề. –

+1

Không nhận được ngoại lệ "Không thể kết nối với cơ sở dữ liệu" để lại nhà phát triển không có thông tin? Tôi không nghĩ như vậy – Matthias

+3

Khái niệm cơ sở là xấu. Không ai nên đặt một mật khẩu đơn giản vào một đối tượng và giữ nó trong bộ nhớ. Giải pháp chính xác sẽ là thay đổi mã PDO, chứ không phải đặt mật khẩu đơn giản vào thông điệp của một ngoại lệ. Tôi coi đây là lỗi và lỗ hổng bảo mật trong PDO. – nagylzs

1

Chúng tôi sử dụng mã hóa tên truy cập và mật khẩu, và giải mã những người trong constructor PDO, sau đó chúng tôi bắt PDOException và ném một PDOException mới với cái cũ ngoại trừ thông báo của nó, để dấu vết sẽ chỉ hiển thị tên người dùng và mật khẩu được mã hóa.

Một thư viện mã hóa tốt cho PHP là: xoa dịu/php-mã hóa

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

Ví dụ mã:

<?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; 
     } 
    } 
Các vấn đề liên quan