2011-07-05 77 views
33

Tôi có một trang web cộng đồng nhỏ và tôi cần triển khai một số chức năng mật khẩu bị quên. Tôi hiện đang lưu trữ mật khẩu trong DB, được mã hóa với MD5.PHP Quên mật khẩu Chức năng

Có thể sắp xếp 'giải mã' và gửi cho họ qua email hay tôi cần phải có trang đặt lại mật khẩu?

+5

Toàn bộ ý tưởng lưu trữ mật khẩu MD5 được mã hóa là bạn không thể giải mã chúng. Ngay cả khi ai đó đột nhập vào hệ thống của bạn và kết xuất DB họ không thể nhận được mật khẩu (trừ khi tất nhiên mật khẩu yếu, nhưng đó là một câu chuyện khác ...) –

Trả lời

127

Mật khẩu băm MD5 không thể hoàn nguyên. (MD5 là băm, và không thực sự mã hóa, do đó, có một sự khác biệt tinh tế). Và bạn chắc chắn sẽ muốn cung cấp một quy trình "đặt lại" mật khẩu (và không chỉ đơn giản là gửi mật khẩu qua email).

Để cung cấp cho bạn một công việc ở mức cao cho reset mật khẩu an toàn ...

  1. Khi người dùng yêu cầu để thiết lập lại mật khẩu của họ, làm cho họ nhập địa chỉ email của họ
  2. Đừng cho biết nếu email mà địa chỉ là hợp lệ hay không (chỉ cần nói với họ rằng một email đã được gửi đi). Điều này mở để tranh luận vì nó làm giảm khả năng sử dụng (nghĩa là tôi không biết mình đã đăng ký email nào) nhưng nó cung cấp ít thông tin hơn cho những người đang cố thu thập thông tin về những email thực sự được đăng ký trên trang web của bạn.
  3. Tạo mã thông báo (có thể băm dấu thời gian bằng muối) và lưu nó vào cơ sở dữ liệu trong hồ sơ của người dùng.
  4. Gửi email cho người dùng cùng với liên kết tới trang http s đặt lại của bạn (mã thông báo và địa chỉ email trong url).
  5. Sử dụng mã thông báo và địa chỉ email để xác thực người dùng.
  6. Cho phép họ chọn mật khẩu mới, thay thế mật khẩu cũ.
  7. Ngoài ra, bạn nên hết hạn các mã thông báo sau một khung thời gian nhất định, thường là 24 giờ.
  8. Tùy chọn, ghi lại số lần thử "quên" đã xảy ra và có thể triển khai nhiều chức năng phức tạp hơn nếu mọi người đang yêu cầu một tấn email.
  9. Tùy chọn, ghi lại (trong một bảng riêng biệt) địa chỉ IP của cá nhân yêu cầu đặt lại. Tăng số lượng từ IP đó. Nếu nó đạt đến nhiều hơn, ví dụ, 10 ... Bỏ qua các yêu cầu tương lai của họ.

Để cung cấp cho bạn một ít chi tiết hơn vào băm ...

Khi bạn băm một giá trị như một mật khẩu bằng cách sử dụng md5() trong PHP, giá trị cuối cùng sẽ là như nhau cho mật khẩu đó bất kể bạn chạy máy chủ nào. (Vì vậy, có một sự khác biệt mà chúng ta có thể thấy ngay lập tức giữa băm và mã hóa ... Không có khóa riêng tư/công khai nào liên quan).

Vì vậy, đây là nơi bạn sẽ thấy mọi người đề cập đến lỗ hổng đối với rainbow tables. Một giải thích rất cơ bản của một bảng cầu vồng là ... Bạn md5() băm một loạt các từ điển (mật khẩu yếu) để có được giá trị băm md5() của chúng. Đặt những người trong một bảng cơ sở dữ liệu (bảng cầu vồng).

Bây giờ, nếu bạn thỏa hiệp cơ sở dữ liệu của trang web, bạn có thể chạy mật khẩu băm của người dùng đối với bảng cầu vồng của bạn (về bản chất) "đảo ngược" hàm băm trở lại mật khẩu. (Bạn không thực sự "đảo ngược" băm ... Nhưng bạn có được ý tưởng).

Đó là nơi "ăn mặn" mật khẩu của bạn là phương pháp hay nhất. Điều này có nghĩa là (một lần nữa, ý tưởng rất cơ bản ở đây) mà bạn thêm một giá trị ngẫu nhiên vào mật khẩu của người dùng trước khi bạn băm nó. Bây giờ, khi bảng cầu vồng chạy trên cơ sở dữ liệu của bạn, nó không dễ dàng "đảo ngược" bởi vì md5() của "mật khẩu" khác với "password384746".

Đây là một SO Q/A tốt đẹp sẽ hữu ích. Secure hash and salt for PHP passwords

+1

Thankyou Jared, thực sự giàu thông tin! – Liam

+1

@Jared Cobb: Bạn có ý nghĩa gì với 8? – testing

+2

@testing Câu hỏi hay ... Nó rất giống với điểm 9, ngoại trừ trong trường hợp này, kẻ tấn công đang sử dụng mạng bot, proxy hoặc phương thức robin tròn khác để đánh bạn từ một địa chỉ IP khác nhau mỗi lần. Ví dụ: nếu hệ thống của bạn phát hiện thấy sự gia tăng lớn "Yêu cầu đã quên" đang diễn ra trong vòng vài phút hoặc vài giờ, bạn có thể xem xét tạm thời làm chậm hoặc tắt tính năng này. (Tất nhiên, ngưỡng của bạn sẽ được xác định bởi phán đoán chủ quan của riêng bạn về kích thước cơ sở người dùng của bạn và những gì được coi là khối lượng "bình thường"). –

2

MD5 được dự định là băm một chiều. Bạn sẽ cần phải yêu cầu họ đặt lại mật khẩu của họ.

1

Không, bạn không thể giải mã được. đó là toàn bộ ý tưởng.

Bạn sẽ cần phải gửi cho họ mật khẩu tạm thời và để họ đặt lại mật khẩu.

1

Bạn cần phải thực hiện trang đặt lại mật khẩu. Không có cách nào trong PHP để giải mã MD5.

7

Không, MD5 không thể đảo ngược. Điểm của mật khẩu băm là để làm cho nó như vậy một kẻ tấn công những người được quyền truy cập vào cơ sở dữ liệu của bạn không thể truy cập mật khẩu của mọi người.

Điều đó nói rằng, MD5 (đặc biệt là MD5 chưa được giải quyết) thường có thể bị tấn công bằng cách sử dụng rainbow table. Để bảo mật, bạn nên sử dụng bcrypt.

3

Bạn không thể giải mã mật khẩu và thậm chí bạn không nên xem xét việc gửi mật khẩu cho người dùng thông qua văn bản thuần túy. (Đó là cách # 1 để khiến tôi không bao giờ sử dụng lại trang web; đó là lỗ hổng bảo mật GIGANTIC.) Cung cấp trang đặt lại mật khẩu được kích hoạt từ liên kết chứa khóa thời gian được liên kết được gửi tới email khôi phục mật khẩu của người dùng ; đó là trạng thái hiện tại của việc khôi phục mật khẩu.

1

MD5 là chức năng một chiều. Bạn không thể giải mã nó. SO bạn cần phải có một trang đặt lại mật khẩu.

2

Viết trang chấp nhận md5 và địa chỉ email làm người lấy mẫu và tìm trong db cho email và mật khẩu md5'd. Theo ghi chú của Jared Cobb, điều đó sẽ giúp bạn đi đúng hướng. tôi chỉ cần thêm một số ví dụ cũng

ví dụ url để gửi http://yourdomain.com/resetpassword.php?code=md5codesentviaemail

$code = isset($_GET['code']) ? $_GET['code'] : ''; 
    $email = isset($_GET['email']) ? $_GET['email'] : ''; 
$checkPw = ''; 

    if(empty($code) || empty($email)) 
    { 
    die(); 
    } 
    $sqlQuery = 'SELECT * FROM users WHERE email = "'.$email.'"; 
//remember to check for sql injections 
    //then get the results as an array, i use a database class eg $user 

    if(!empty($user['password'])) 
    { 
    $checkPw = md5($user['password']); 
    }else 
    { 
    die(); 
    } 

    if($checkPw !== $code) 
    { 
    die(); 
    }else 
    { 
    //display form for user to change password 
    } 

này nên là đủ đủ để bạn có thể biết rằng người dùng là một người dùng hợp lệ và thay đổi mật khẩu của mình

3

Điều tốt nhất để bạn làm là yêu cầu mọi người gửi địa chỉ email của họ khi đăng ký. Sau đó, nếu họ quên, có một liên kết quên mật khẩu mà đặt lại mật khẩu của họ với một giá trị ngẫu nhiên được gửi qua email cho họ để họ có thể truy cập và sau đó thay đổi mật khẩu của họ trở lại một cái gì đó đáng nhớ hơn. Bằng cách này bạn không cần phải thỏa hiệp về an ninh. Bạn có thể có một liên kết mà họ chỉ cần gửi tên người dùng của họ vào, nhưng để bảo mật tốt hơn, bạn nên có một câu hỏi và câu trả lời hoặc từ đáng nhớ.

8

Theo bài đăng này The definitive guide to forms based website authentication, cho bước 3. và 4., tôi không chắc bạn nên gửi cùng một mã thông báo bạn đang lưu trữ.

Tôi đoán bạn phải gửi mã thông báo, sau đó băm nó và lưu trữ mã thông báo băm trong DB. Nếu không, nếu cơ sở dữ liệu của bạn bị xâm nhập, người dùng có thể có quyền truy cập vào trang đặt lại mật khẩu.

Để tóm tắt:

$token = md5(microtime (TRUE)*100000); 
$tokenToSendInMail = $token; 
$tokenToStoreInDB = hash($token); 

nơi băm là một thuật toán băm.

+1

Đó là một điểm thực sự tốt, lưu trữ mã băm trong DB. +1 – Francodi

+1

Sử dụng mã thông báo có thể đoán trước không phải là một ý tưởng hay ... Mặc dù không nên dựa trên bất kỳ điều gì có thể dự đoán được, như thời gian. (Nó sẽ cho phép kẻ tấn công lặp lại thông qua các giá trị trong khoảng thời gian mã thông báo được tạo) Trong PHP7, 'random_bytes' nên được sử dụng. Trên PHP5, việc triển khai tính tương thích hoặc 'openssl_random_pseudo_byte' nên được sử dụng. –

+1

(Tùy chọn khác là sử dụng hàm băm của chuỗi ký tự ngẫu nhiên và chi tiết của người dùng và hy vọng một số dữ liệu ngẫu nhiên hợp lý. Vì nó được lưu trữ trong DB, không có lý do gì để mã thông báo có thể dự đoán được) (sử dụng phương pháp này, Tôi sẽ tạo ra các mã thông báo bằng cách sử dụng 'password_hash' trên chuỗi dài và gửi một phiên bản mã hóa base64 của băm trong liên kết). (băm nó một lần nữa trước khi lưu trữ trong DB có thể là một tùy chọn là tốt, nhưng hết hạn liên kết đặt lại sau 4-24 giờ có khả năng phòng thủ tốt hơn) (với dữ liệu ngẫu nhiên thích hợp, chỉ cần gửi dữ liệu base64 được mã hóa là tốt) –

2

Sử dụng password_verify và password_hash được tích hợp sẵn của php.

3

Như Marcus Reed đã nêu, trong 2015/2016 nếu bạn có phiên bản PHP> = 5.5 không sử dụng MD5, password_hash() và password_verify() cung cấp băm dễ dàng và an toàn cho mật khẩu của bạn với khả năng cung cấp chi phí và tự động muối băm.

Tôi không có khả năng bỏ phiếu hoặc nhận xét hiện tại, đó là lý do tôi cung cấp tuyên bố cuối cùng để tránh nhầm lẫn.

Các vấn đề liên quan