+15

Chức năng quên mật khẩu

Hôm nay mình định viết về autoload trong PHP, nhưng ngẫm nghĩ thế nào lại muốn viết tiếp cái seri "Lập trình giúp chúng ta thoải mái hơn". Nhưng, lại nhưng, thế nào lại quên mất mật khẩu vào Viblo, ngồi gõ 1 lúc xong vẫn không được, đành dùng chức năng "Quên mật khẩu". Yeah, mọi chuyện lại suôn sẻ nếu như mình không đăng ký Viblo bằng mail công ty, mà máy cá nhân của mình lại không set up mail này, mà mail này lại có password cực kỳ khó nhớ từ hồi mình mới vào =))) đấy, chuyện đời mình nó cứ như trò đùa. thôi đành mò tiếp, và cuối cùng tất nhiên là mình đã đăng nhập được thành công rồi. Rất may là password của mình chưa bị reset và mình vẫn đăng nhập được vào bằng pwd cũ. Đến đây thì mình phải cảm ơn 1 người mà mình không thích cho lắm, hồi còn làm ở Viblo, người này yêu cầu mình làm chức năng "Reset password nhưng vẫn đăng nhập được bằng pwd cũ nếu chưa confirm". Rồi, câu chuyện về quên mật khẩu được bắt đầu.

Việc quên mật khẩu và cho người dùng đặt lại mật khẩu

Giống như ta đang tạo ra 1 cửa sau để cho người dùng đó (và có thể là cả người khác) vào tài khoản đó. Ngày xưa, hồi lâu lắm rồi, cái thời mà mình chỉ biết chat Yahoo chứ chưa biết code ấy, ngày ấy ngta code buồn cười lắm. Kể tiếp, không rõ là thời đấy trang nào cũng thế, hay là chỉ những trang mình có đăng ký thành viên thì họ xử lý như vầy:

  • Hoặc là gửi 1 cái email nêu rõ mật khẩu đang dùng là gì, to, rõ ràng, bôi đen luôn.
  • Hoặc là khá hơn, reset mật khẩu của mình thành 1 chuỗi ngẫu nhiên, và cũng gửi 1 cái email cho mình cái chuỗi ngẫu nhiên đó, vẫn to, rõ ràng và bôi đen, rồi mình mà không check được mail thì khỏi đăng nhập vào tài khoản đó luôn.
  • Cuối cùng là khá nhất, gửi cho mình 1 đường link confirm và 1 chuỗi ngẫu nhiên. Ấn vào link thì mật khẩu của mình là cái chuỗi đó, còn nếu không thì vẫn là cái cũ.

Không được gửi lại cho người dùng mật khẩu cũ của họ vào email

với trường hợp này, nếu bạn có dùng dịch vụ của họ thì nên reset mật khẩu, đổi thành mật khẩu mới mà chính bạn cũng không biết bạn viết gì rồi bye bye họ luôn đi thôi. Việc để mật khẩu 1 cách lộ thiên (plain text) trong database thế tiềm ẩn, à mà không, hiện hữu sờ sờ một tá các nguy cơ mất luôn tài khoản. Hoặc có thể họ mã hóa mật khẩu rồi, nhưng mà họ gửi cho bạn được mật khẩu chưa mã hóa thì rõ ràng là nếu vào đươc database, kiểu gì cũng lôi được mật khẩu ra. Mình dám chắc là chả ai còn làm như thế này nữa.

Không được gửi lại cho người dùng mật khẩu mới của họ vào email

Giống như 2 trường hợp sau mình vừa kể, việc gửi lại mật khẩu mới như vậy cũng không tốt. Tình huống đơn giản nhất có thể nghĩ đến là email thay đổi mật khẩu này không đến được hòm thư của người dùng, vì nó đã bị chặn giữa đường bởi 1 hacker nào đó, bằng 1 đống tool hỗ trợ (nào đó). Hay thuyết âm mưu hơn, đó là hacker biết được email của người dùng (hack vào database nhưng mà ko biết được mật khẩu, hash rồi còn đâu), hắn đoán được là chuỗi ngẫu nhiên khi reset pwd chỉ có A-Za-z0-9 với 5 6 7 ký tự thôi chẳng hạn. Thế là hắn ngồi tính nhẩm, vét cạn, bla bla ra đống ký tự này sau khi nhập email của người dùng vào chỗ "quên mật khẩu". Đừng cười mình, vì chuyện này hoàn toàn có thể xảy ra. Hoặc không, mọi chuyện diễn ra êm xuôi, mail vẫn tới và người dùng có mật khẩu mới, nhưng họ lại không thay đổi pwd, và cái chuỗi ngẫu nhiên kia vẫn chình ình trong mail của họ, ví dụ như trong mail Yahoo ấy, cái dịch vụ mà có toàn bộ 3 tỷ tài khoản bị lộ ấy, thằng cha nào đó đọc được cái mail đó và đăng nhập vào thôi. Đến đây, bạn nghĩ đơn giản là, mất thì thôi, 1 cái tài khoản vớ vẩn ấy mà, sao mà âm mưu nhiều đau đầu. Đúng là thế, ví dụ tài khoản Viblo này, không vào được thì tạo cái mới, có cái gì đâu. Nhưng đó là tài khoản ngân hàng thì sao, trong tài khoản đó có đủ thứ thì sao, vì thế hacker mới mệt não nghĩ ra đủ trò như trên chứ cái account Viblo này của mình thì thằng nào nhòm ngó???

Làm như thế nào thì ổn?

Quay lại cái task mà mình được giao ở đoạn đầu, "Reset password nhưng vẫn đăng nhập được bằng pwd cũ nếu chưa confirm". Hồi đó, mình cũng không gà lắm, đó là mình tạo thêm 1 cột chứa 1 chuỗi ngẫu nhiên, ví dụ ABCDEF chẳng hạn. Sau khi người dùng chọn quên cmn mật khẩu thì mình sẽ gửi 1 cái link vào email, đại loại là thế này viblo.asia/reset-pwd/{userId}/ABCDEF ấy. Rồi check xem có đúng userId không, có trùng token này không, đúng thì hiện ra form nhập mật khẩu mới, không đúng thì thôi cho next. Nghe có vẻ ổn nhưng mà không ổn lắm. Này nhé, nói gở có thằng nào vào được database rồi, nó thấy email này, nó chọn reset pwd, rồi nó thấy cái chuỗi kia, nó tự làm thành 1 đường link mới, thế là nó có quyền tạo mật khẩu mới cho người dùng thật sự. Thế là hết. Cả câu chuyện mình luôn nói đến chuyện "thằng nào đó vào được database", bởi vì nếu ứng dụng của bạn không đủ bảo mật, thì gánh nặng bảo mật dồn hết về phía DB, thế có phải khổ không chứ.

Tiếp cái kia, nếu là mình bây giờ, thì mình sẽ làm gì với task này nào?

  • đầu tiên, vẫn là sinh ra chuỗi ngẫu nhiên ABCDEF, rồi gửi link viblo.asia/reset-pwd/{userId}/ABCDEF đó cho người dùng, sau đó hash chuỗi này bằng brcytp, hay md5, sha1. Để tăng độ khó cho game thì thêm 1 chuỗi $salt nào đó giống như hash mật khẩu vầy, rồi tiếp theo mới lưu chuỗi đã băm vào DB. Lúc này thì chả thằng hacker nào biết được đườg link thật sự là gì, vì nó đã được băm, và chuỗi ban đầu giờ chỉ còn nằm trong email của người dùng mà thôi.
  • sau đó là tạo ra thời gian hết hạn cho cái đường link kia. Hết hạn sau 2h hoặc 24h hoặc ngay sau khi người dùng kích hoạt cái link đó.
  • sau nữa, lắm chuyện hơn là chúng ta có thêm câu hỏi bảo mật, giống như các dịch vụ lớn vẫn hay có ấy, ví dụ như điền vào chỗ trống 4 số cuối số điện thoại đã đăng ký, điền chính xác email khôi phục, tên con vật bạn yêu quý, bla bla... mà những câu hỏi này không dễ dàng đoán ra được từ những thông tin cá nhân được public trên mạng của người dùng.

Kết luận

  • Thế thôi nhỉ, lảm nhảm nhiều rồi.
  • Ý tưởng viết bài: không vào được Viblo
  • Nói có sách, mách có chứng
  • ...

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí