Làm thế nào để bảo mật mật khẩu cơ sở dữ liệu trong PHP?


404

Khi một ứng dụng PHP tạo kết nối cơ sở dữ liệu, thông thường nó cần phải vượt qua đăng nhập và mật khẩu. Nếu tôi đang sử dụng một lần đăng nhập cấp phép tối thiểu cho ứng dụng của mình, thì PHP cần biết thông tin đăng nhập và mật khẩu đó ở đâu đó. Cách tốt nhất để bảo mật mật khẩu đó là gì? Có vẻ như chỉ viết nó trong mã PHP không phải là một ý tưởng tốt.


1
Để hoàn toàn an toàn, bạn sẽ cần thiết lập kết nối ssl, nếu không, bất kỳ ai trên mạng của bạn vẫn có thể đánh hơi được mật khẩu bạn nhập.
Charles Ma

1
Bạn có nghĩa là mật khẩu người dùng hoặc mật khẩu cơ sở dữ liệu được sử dụng trong chuỗi kết nối?
Ozgur Ozcitak

4
Mật khẩu cơ sở dữ liệu được sử dụng trong chuỗi kết nối. Cảm ơn!
dùng18359

Câu trả lời:


238

Một số người đọc sai điều này như một câu hỏi về cách lưu trữ mật khẩu trong cơ sở dữ liệu. Điều đó là sai. Đó là về cách lưu trữ mật khẩu cho phép bạn truy cập cơ sở dữ liệu.

Giải pháp thông thường là chuyển mật khẩu ra khỏi mã nguồn vào một tệp cấu hình. Sau đó rời khỏi quản trị và bảo mật tệp cấu hình đó cho quản trị viên hệ thống của bạn. Bằng cách đó, các nhà phát triển không cần biết gì về mật khẩu sản xuất và không có bản ghi mật khẩu nào trong kiểm soát nguồn của bạn.


8
Cảm ơn. Nếu tôi hiểu điều này một cách chính xác, thì tệp php sẽ có tệp đính kèm vào tệp cấu hình, cho phép nó sử dụng mật khẩu. ví dụ: tôi tạo một tệp có tên 'app1_db_cfg.php' lưu tên đăng nhập, pword và tên db. Sau đó, trang application.php của tôi bao gồm 'app1_db_cfg.php' và tôi đang kinh doanh!
dùng18359

28
Tôi đồng ý rằng cấu hình cần phải được bảo vệ đúng cách. Tuy nhiên, biết làm thế nào là việc của quản trị viên hệ thống chứ không phải nhà phát triển. Tôi không đồng ý về giá trị của mã hóa mạnh trong trường hợp này. Nếu bạn không thể bảo vệ tệp cấu hình của mình, điều gì khiến bạn nghĩ rằng bạn có thể bảo vệ các khóa của mình?
dùng11318

10
Tôi thích sử dụng tài khoản cơ sở dữ liệu chỉ được phép truy cập cơ sở dữ liệu từ máy chủ web. Và sau đó tôi không bận tâm đến việc mã hóa cấu hình, tôi chỉ lưu trữ bên ngoài web root.
gnud

11
Tôi sử dụng biến môi trường apache để đặt đường dẫn sao cho đường dẫn đến tệp không xác định trong mã nguồn. Điều này cũng độc đáo cho phép có một mật khẩu khác để phát triển và sản xuất dựa trên những gì cài đặt Apache có trên máy chủ
geedew

15
Xin lưu ý rằng ngay cả các tệp được lưu trữ bên ngoài thư mục có thể truy cập web phải được đọc bởi tập lệnh sử dụng chúng. Nếu ai đó bao gồm tệp đó, sau đó kết xuất dữ liệu từ tệp, họ sẽ thấy mật khẩu.
Rick Mac Gillis

104

Nếu bạn đang lưu trữ trên máy chủ của người khác và không có quyền truy cập bên ngoài webroot của mình, bạn luôn có thể đặt mật khẩu và / hoặc kết nối cơ sở dữ liệu vào một tệp rồi khóa tệp bằng .htaccess:

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

3
Cảm ơn, đó chính xác là những gì tôi đang tìm kiếm.
David Gladfelter

28
Chắc chắn, nhưng nếu ai đó có quyền truy cập shell, toàn bộ tài khoản của bạn đã bị xâm phạm.
kellen

4
Đây là thực tế xấu vì bạn có thể vô tình cam kết thông tin đăng nhập của bạn vào một kho lưu trữ.
Porlune

2
@Ankit: Nếu người không thân thiện có thể tải tệp lên máy chủ và thực thi thì máy chủ không được cấu hình đúng cách.
kellen

6
@Porlune: Nhà phát triển nên làm cho hệ thống kiểm soát phiên bản của họ bỏ qua tệp mật khẩu, tức là bằng cách sử dụng .gitignore. Nhưng có, cần cẩn thận với các tệp có chứa dữ liệu nhạy cảm.
kellen

45

Cách an toàn nhất là không có thông tin được chỉ định trong mã PHP của bạn.

Nếu bạn đang sử dụng Apache, điều đó có nghĩa là đặt chi tiết kết nối trong tệp tệp httpd.conf hoặc máy chủ ảo của bạn. Nếu bạn làm điều đó, bạn có thể gọi mysql_connect () không có tham số, điều đó có nghĩa là PHP sẽ không bao giờ xuất thông tin của bạn.

Đây là cách bạn chỉ định các giá trị này trong các tệp đó:

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

Sau đó, bạn mở kết nối mysql của bạn như thế này:

<?php
$db = mysqli_connect();

Hoặc như thế này:

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

1
Vui lòng kiểm tra các giá trị thích hợp của ini_get ( 'giá trị mặc định') php.net/manual/en/class.mysqli.php
Val

4
có, nhưng bất kỳ người dùng nào (hoặc một hacker lạm dụng tập lệnh php viết sai) đều có thể đọc mật khẩu qua ini_get().
Marki555

1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Làm thế nào để bạn đối phó với điều này?
tonix

2
Marki555 đang nói rằng một kẻ tấn công có thể chạy mã PHP cũng có thể gọi các hàm PHP, điều này rõ ràng là đúng và không thể làm gì đó. Tôi cũng muốn nói thêm rằng tôi không còn làm theo lời khuyên mà tôi đưa ra trong câu trả lời này mà thay vào đó sử dụng các biến môi trường. Khái niệm này tương tự nhau: Đừng lưu trữ thông tin đăng nhập của bạn trong mã, nhưng hãy tiêm chúng bằng cách nào đó. Nó không thực sự quan trọng nếu bạn sử dụng ini_get()hoặc getenv().
Lars Nyström

2
@DeepBlue Nếu bạn có thể tiêm ini_get (), bạn cũng có thể tiêm file_get_contents (anypath). Miễn là php có cách lấy mật khẩu, thì mã độc cũng vậy.
varesa

40

Lưu trữ chúng trong một tập tin bên ngoài web root.


29
Và cũng, như đã đề cập ở nơi khác, ngoài kiểm soát nguồn.
Nông dân Frank

6
chúng tôi sẽ có thể bao gồm nó? ví dụ trong PHP chúng ta có thể làm gì include('../otherDirectory/configfile.conf')?
mtk

1
Tất cả các bạn đều đề nghị lưu trữ thông tin đăng nhập bên ngoài wwwroot. Ok, tôi hiểu nền tảng bảo mật. Nhưng làm thế nào nó nên được lưu trữ trong kiểm soát phiên bản sau đó (cấu hình mẫu)? Thông thường wwwroot là gốc của git repo, vì vậy nếu có bất cứ thứ gì bên ngoài - nó sẽ nằm ngoài VC. Hãy tưởng tượng nhà phát triển mới đang cố gắng thiết lập một thể hiện cục bộ để phát triển - làm thế nào anh ta biết phép thuật như "lấy tệp này, sao chép nó ra bên ngoài và điền vào"?
Bố già

@TheGod lương Ý tưởng là một nhà phát triển mới nên có thông tin đăng nhập riêng cho môi trường phát triển của riêng họ. Mặc dù là một cách thực hành tốt để có một readme với các hướng dẫn hoặc nhận xét trong mã cho biết bạn nên cấu hình nó như thế nào (nhưng không phải là dữ liệu thực tế).
PhoneixS

@TheGod lương, tập tin readme?
Pacerier

35

Đối với các hệ thống cực kỳ an toàn, chúng tôi mã hóa mật khẩu cơ sở dữ liệu trong một tệp cấu hình (chính nó được bảo mật bởi quản trị viên hệ thống). Khi khởi động ứng dụng / máy chủ, ứng dụng sẽ nhắc quản trị viên hệ thống về khóa giải mã. Mật khẩu cơ sở dữ liệu sau đó được đọc từ tệp cấu hình, được giải mã và được lưu trong bộ nhớ để sử dụng trong tương lai. Vẫn không an toàn 100% vì nó được lưu trữ trong bộ nhớ được giải mã, nhưng bạn phải gọi nó là 'đủ an toàn' tại một số điểm!


85
Nếu quản trị viên chết thì sao?
Radu Murzea

36
@RaduMurzea thật nực cười. Khi bạn đã nghe nói về Quản trị viên Sys chết? Họ giống như McDonalds, họ chỉ xuất hiện / biến mất khỏi hư không!
ILikeTacos

13
@Radu Murzea Chỉ cần có 2 quản trị viên trở lên, thì bạn có tính chẵn lẻ như một mảng đột kích. Cơ hội của nhiều hơn một ổ đĩa bị lỗi tại một thời điểm thấp hơn nhiều.
tử11

5
Khi máy chủ khởi động lại thì sao? Sẽ mất bao nhiêu thời gian để đánh thức quản trị viên để khiến họ nhập mật khẩu vào..etc.etc. lol
John Hunt

1
Không chắc chắn ý của bạn là 'được lưu trong bộ nhớ'. Các ứng dụng web PHP thường không lưu trữ bất cứ thứ gì trong bộ nhớ lâu hơn thời gian cần thiết để đáp ứng một yêu cầu riêng lẻ để xem một trang.
bdsl

15

Giải pháp này là chung, trong đó nó hữu ích cho cả ứng dụng nguồn mở và đóng.

  1. Tạo một người dùng hệ điều hành cho ứng dụng của bạn. Xem http://en.wikipedia.org/wiki/Principl_of_least_priv đặc quyền
  2. Tạo biến môi trường HĐH (không phiên) cho người dùng đó bằng mật khẩu
  3. Chạy ứng dụng như người dùng đó

Ưu điểm:

  1. Bạn sẽ không kiểm tra mật khẩu của mình để kiểm soát nguồn một cách tình cờ, vì bạn không thể
  2. Bạn sẽ không vô tình làm hỏng quyền truy cập tập tin. Vâng, bạn có thể, nhưng nó sẽ không ảnh hưởng đến điều này.
  3. Chỉ có thể được đọc bởi root hoặc người dùng đó. Root có thể đọc tất cả các tập tin và khóa mã hóa của bạn bằng mọi cách.
  4. Nếu bạn sử dụng mã hóa, làm thế nào bạn lưu trữ khóa một cách an toàn?
  5. Hoạt động nền tảng x
  6. Hãy chắc chắn không vượt qua envvar cho các tiến trình con không tin cậy

Phương pháp này được đề xuất bởi Heroku, người rất thành công.


11

nếu có thể tạo kết nối cơ sở dữ liệu trong cùng một tệp nơi thông tin đăng nhập được lưu trữ. Nội tuyến các thông tin trong câu lệnh kết nối.

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

Mặt khác, tốt nhất là bỏ đặt thông tin đăng nhập sau câu lệnh kết nối, vì thông tin đăng nhập không có trong bộ nhớ, không thể đọc được từ bộ nhớ ;)

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

9
Nếu ai đó có quyền truy cập vào bộ nhớ, dù sao bạn cũng bị lừa. Đây là bảo mật giả vô nghĩa. Bên ngoài webroot (hoặc ít nhất được bảo vệ bởi .htaccess nếu bạn không có quyền truy cập phía trên webroot của mình) là lựa chọn an toàn duy nhất.
uliwitness

2
@uliwitness - Điều đó giống như nói rằng chỉ vì ai đó có thể cắt khóa của trung tâm điều hành mạng của bạn bằng đèn pin acetylene có nghĩa là cửa cũng là bảo mật giả. Giữ thông tin nhạy cảm ràng buộc trong phạm vi chặt chẽ nhất có thể luôn luôn có ý nghĩa.
Luke A. Leber

1
Làm thế nào về echo $ db_user hoặc in $ db_pass? Ngay cả các nhà phát triển trong cùng một nhóm cũng không thể tìm ra thông tin đăng nhập sản xuất. Mã này không chứa gì có thể in được về thông tin đăng nhập.
Mohammed Joraid

8

Sự lựa chọn của bạn bị hạn chế như bạn nói bạn cần mật khẩu để truy cập cơ sở dữ liệu. Một cách tiếp cận chung là lưu trữ tên người dùng và mật khẩu trong một tệp cấu hình riêng biệt thay vì tập lệnh chính. Sau đó hãy chắc chắn lưu trữ bên ngoài cây web chính. Đó là nếu có một vấn đề cấu hình web khiến các tệp php của bạn được hiển thị đơn giản dưới dạng văn bản thay vì được thực thi, bạn không bị lộ mật khẩu.

Ngoài ra, bạn đang ở đúng dòng với quyền truy cập tối thiểu cho tài khoản đang được sử dụng. Thêm vào đó

  • Không sử dụng kết hợp tên người dùng / mật khẩu cho bất cứ điều gì khác
  • Định cấu hình máy chủ cơ sở dữ liệu để chỉ chấp nhận kết nối từ máy chủ web cho người dùng đó (localhost thậm chí còn tốt hơn nếu DB ở trên cùng một máy) Theo cách đó, ngay cả khi thông tin đăng nhập bị lộ, họ không thể sử dụng cho bất kỳ ai trừ khi họ có quyền truy cập khác vào máy móc.
  • Làm xáo trộn mật khẩu (thậm chí ROT13 sẽ làm) nó sẽ không bảo vệ nhiều nếu một số người có quyền truy cập vào tệp, nhưng ít nhất nó sẽ ngăn việc xem thông thường.

Peter


8

Nếu bạn đang sử dụng PostgreSQL, thì nó sẽ ~/.pgpasstự động tìm mật khẩu. Xem hướng dẫn để biết thêm thông tin.


8

Trước đây chúng tôi đã lưu trữ người dùng / pass DB trong một tệp cấu hình, nhưng kể từ đó đã đạt đến chế độ hoang tưởng - áp dụng chính sách Phòng thủ trong Độ sâu .

Nếu ứng dụng của bạn bị xâm phạm, người dùng sẽ có quyền truy cập đọc vào tệp cấu hình của bạn và do đó có khả năng một kẻ bẻ khóa đọc thông tin này. Các tệp cấu hình cũng có thể bị cuốn vào kiểm soát phiên bản hoặc sao chép xung quanh các máy chủ.

Chúng tôi đã chuyển sang lưu trữ người dùng / pass trong các biến môi trường được đặt trong Apache Virtualhost. Cấu hình này chỉ có thể đọc được bằng root - hy vọng người dùng Apache của bạn không chạy bằng root.

Con lừa với điều này là bây giờ mật khẩu nằm trong biến PHP toàn cầu.

Để giảm thiểu rủi ro này, chúng tôi có các biện pháp phòng ngừa sau:

  • Mật khẩu được mã hóa. Chúng tôi mở rộng lớp PDO để bao gồm logic để giải mã mật khẩu. Nếu ai đó đọc mã nơi chúng tôi thiết lập kết nối, thì rõ ràng kết nối đó sẽ được thiết lập bằng mật khẩu được mã hóa chứ không phải mật khẩu.
  • Mật khẩu được mã hóa được chuyển từ các biến toàn cục sang biến riêng . Ứng dụng thực hiện việc này ngay lập tức để giảm cửa sổ có giá trị trong không gian toàn cầu.
  • phpinfo()bị vô hiệu hóa. PHPInfo là một mục tiêu dễ dàng để có được cái nhìn tổng quan về mọi thứ, bao gồm các biến môi trường.

6

Đặt mật khẩu cơ sở dữ liệu trong một tệp, làm cho nó chỉ đọc cho người dùng phục vụ các tệp.

Trừ khi bạn có một số phương tiện chỉ cho phép quá trình máy chủ php truy cập cơ sở dữ liệu, đây là tất cả những gì bạn có thể làm.


5

Nếu bạn đang nói về mật khẩu cơ sở dữ liệu, trái ngược với mật khẩu đến từ trình duyệt, thì thông lệ tiêu chuẩn dường như là đặt mật khẩu cơ sở dữ liệu trong tệp cấu hình PHP trên máy chủ.

Bạn chỉ cần chắc chắn rằng tệp php chứa mật khẩu có quyền thích hợp trên nó. Tức là nó chỉ có thể đọc được bởi máy chủ web và tài khoản người dùng của bạn.


1
Thật không may, tập tin cấu hình PHP có thể được đọc bởi phpinfo () và nếu ai đó tình cờ để lại một số tập lệnh kiểm tra phía sau kẻ tấn công may mắn sẽ có thể đọc mật khẩu. Thay vào đó, tốt nhất là để lại mật khẩu kết nối trong một tệp bên ngoài root máy chủ web. Sau đó, cách duy nhất để truy cập nó là bằng shell hoặc bằng cách thực thi mã tùy ý, nhưng trong kịch bản đó, tất cả bảo mật đều bị mất.
MarioVilas

5

Chỉ cần đặt nó vào một tập tin cấu hình ở đâu đó là cách nó thường được thực hiện. Chỉ cần chắc chắn rằng bạn:

  1. không cho phép truy cập cơ sở dữ liệu từ bất kỳ máy chủ nào bên ngoài mạng của bạn,
  2. Cẩn thận không vô tình hiển thị mật khẩu cho người dùng (trong thông báo lỗi hoặc thông qua các tệp PHP vô tình được phục vụ dưới dạng HTML, vân vân.)

5

Chúng tôi đã giải quyết nó theo cách này:

  1. Sử dụng memcache trên máy chủ, với kết nối mở từ máy chủ mật khẩu khác.
  2. Lưu vào memcache mật khẩu (hoặc thậm chí tất cả tệp password.php được mã hóa) cộng với khóa giải mã.
  3. Các trang web, gọi khóa memcache giữ mật khẩu tệp mật khẩu và giải mã tất cả các mật khẩu.
  4. Máy chủ mật khẩu gửi một tệp mật khẩu được mã hóa mới cứ sau 5 phút.
  5. Nếu bạn sử dụng password.php được mã hóa trong dự án của mình, bạn sẽ thực hiện kiểm toán, kiểm tra xem tệp này có được chạm bên ngoài không - hoặc được xem. Khi điều này xảy ra, bạn có thể tự động dọn dẹp bộ nhớ, cũng như đóng máy chủ để truy cập.

4

Một mẹo bổ sung là sử dụng tệp cấu hình riêng biệt của PHP trông giống như sau:

<?php exit() ?>

[...]

Plain text data including password

Điều này không ngăn bạn đặt quy tắc truy cập đúng cách. Nhưng trong trường hợp trang web của bạn bị hack, một "yêu cầu" hoặc "bao gồm" sẽ thoát khỏi tập lệnh ở dòng đầu tiên để lấy dữ liệu thậm chí còn khó hơn.

Tuy nhiên, đừng bao giờ để các tệp cấu hình trong một thư mục có thể được truy cập qua web. Bạn nên có một thư mục "Web" chứa mã điều khiển, css, hình ảnh và js. Đó là tất cả. Bất cứ điều gì khác đi trong các thư mục ngoại tuyến.


nhưng làm thế nào để tập lệnh php đọc thông tin đăng nhập được lưu trong tệp?
Christopher Mahan

3
Bạn sử dụng fopen (), giống như cho một tệp văn bản thông thường.
e-satis

2
@ e-satis ok nó sẽ ngăn hacker làm require/ includenhưng làm thế nào để ngăn chặn fopen?
dmnc

"điều này không ngăn bạn thiết lập quy tắc truy cập đúng cách"
e-satis

@ e-satis, điều này khá thông minh. tự hỏi tại sao không ai nghĩ về nó Tuy nhiên , vẫn dễ bị ảnh hưởng bởi các vấn đề sao chép biên tập. feross.org/cmsploit
Pacerier

4

Cách tốt nhất là không lưu trữ mật khẩu!
Ví dụ: nếu bạn đang sử dụng hệ thống Windows và kết nối với SQL Server, bạn có thể sử dụng Xác thực tích hợp để kết nối với cơ sở dữ liệu mà không cần mật khẩu, sử dụng danh tính của quy trình hiện tại.

Nếu bạn cần kết nối với mật khẩu, trước tiên hãy mã hóa nó, sử dụng mã hóa mạnh (ví dụ: sử dụng AES-256, sau đó bảo vệ khóa mã hóa hoặc sử dụng mã hóa bất đối xứng và để HĐH bảo vệ chứng chỉ), sau đó lưu trữ nó trong một tập tin cấu hình (bên ngoài thư mục web) với ACL mạnh .


3
Không có điểm trong việc mã hóa mật khẩu một lần nữa . Ai đó có thể nhận được mật khẩu không được mã hóa cũng có thể nhận được bất kỳ mật khẩu nào cần thiết để giải mã mật khẩu. Tuy nhiên, sử dụng ACL & .htaccess là một ý tưởng tốt.
uliwitness

2
@uliwitness Tôi nghĩ bạn có thể đã hiểu lầm - ý bạn là gì khi "mã hóa lại "? Nó chỉ là một mã hóa. Và bạn không muốn sử dụng cụm mật khẩu (dành cho mục đích sử dụng của con người) để mã hóa nó, quản lý khóa khá mạnh, ví dụ như được bảo vệ bởi HĐH, theo cách đơn giản là việc truy cập hệ thống tệp sẽ không cấp quyền truy cập vào khóa.
AviD

3
Mã hóa không phải là phép thuật - thay vì bảo vệ khóa AES bằng ACL, bạn chỉ có thể lưu mật khẩu ở đó. Không có sự khác biệt giữa việc truy cập khóa AES hoặc mật khẩu được giải mã, mã hóa trong ngữ cảnh này chỉ là dầu rắn.
MarioVilas

@MarioVilas whaat? Nếu mật khẩu được mã hóa, với khóa mã hóa được bảo vệ bởi HĐH, làm thế nào không có sự khác biệt? Mã hóa không phải là phép thuật - nó chỉ thu gọn tất cả bí mật vào khóa mã hóa nhỏ hơn. Rất khó tin, trong bối cảnh này, nó chỉ chuyển tất cả những gì bí mật vào HĐH.
AviD

6
@AviD làm thế nào mà HĐH có thể bảo vệ khóa mà không phải là dữ liệu? Trả lời: nó có thể bảo vệ cả hai, vì vậy mã hóa không thực sự giúp ích. Sẽ khác nếu chỉ có dữ liệu được lưu trữ và khóa mã hóa được lấy, ví dụ, từ mật khẩu mà người dùng phải nhập .
MarioVilas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.