7 điểm bởi GN⁺ 2024-10-11 | 1 bình luận | Chia sẻ qua WhatsApp
  • Đây là bộ hướng dẫn cơ bản có thể tham khảo khi thiết kế triển khai xác thực trong ứng dụng web, nhằm lấp đầy những khoảng trống của các tài liệu xác thực trực tuyến
  • Là tài liệu miễn phí, mã nguồn mở và được cung cấp theo cách cộng đồng cùng duy trì
  • Một số nội dung có thể mang tính quan điểm hoặc chưa hoàn chỉnh, vì vậy phù hợp hơn khi dùng làm tài liệu bổ trợ thay vì tiêu chuẩn duy nhất
  • Khuyến nghị sử dụng cùng với OWASP Cheat Sheet Series, một tài liệu tham khảo về bảo mật xác thực
  • Nếu có đề xuất hoặc lo ngại, bạn có thể mở issue mới để gửi phản hồi và tham gia cải thiện tài liệu

Mục đích và tính chất của tài liệu

  • The Copenhagen Book cung cấp các hướng dẫn chung có thể tham khảo khi triển khai xác thực (auth) trong ứng dụng web
  • Cách vận hành như sau
    • Được cung cấp miễn phí
    • Là mã nguồn mở
    • Được cộng đồng duy trì
  • Nội dung đôi khi có thể mang tính quan điểm hoặc chưa hoàn thiện

Tài liệu nên tham khảo cùng và cách tham gia

  • Khi triển khai xác thực, nên tham khảo cùng OWASP Cheat Sheet Series
  • Nếu có đề xuất hoặc lo ngại, bạn có thể mở issue mới

1 bình luận

 
GN⁺ 2024-10-11
Ý kiến trên Hacker News
  • Nếu tôi không nhầm thì bài này có vẻ do tác giả của Lucia, một thư viện xác thực phổ biến cho TypeScript, viết
    Gần đây, thư viện Lucia đã công bố rằng họ cho rằng thư viện này không còn là một cách tiện dụng để triển khai xác thực nữa, nên sẽ ngừng thư viện và thay thế bằng một loạt bài hướng dẫn dạng văn bản
    Bản xem trước hướng dẫn ban đầu đọc khá tốt và cũng rất hợp với The Copenhagen Book
    https://github.com/lucia-auth/lucia
    https://github.com/lucia-auth/lucia/discussions/1707
    https://lucia-next.pages.dev/

    • Tôi đã thắc mắc liệu họ có viết ra lý do vì sao lại đánh giá như vậy không, và nó ở đây: https://github.com/lucia-auth/lucia/discussions/1707
      Thật hiếm khi thấy họ nhận ra dấu hiệu độ phức tạp sắp bùng nổ, thừa nhận rằng thư viện không còn hữu ích ngay cả với chính mình, rồi khiêm tốn rời khỏi con đường tiêu chuẩn của tình trạng phình to thư viện thường gặp
    • Dù vậy, Lucia rất có khả năng sẽ sớm được thay thế bằng một thư viện xác thực phổ biến khác
      Thực ra 99% người dùng chỉ cần đăng nhập/đăng xuất, và thứ này cực kỳ hữu ích khi được cung cấp dưới dạng thư viện
      Nếu phải cung cấp passkey Web 8.0 bằng socket đường cong elliptic WASM thì có thể tự làm hoặc dùng Auth0, nhưng ném đặc tả OAuth và danh sách cạm bẫy cho người đang làm một ứng dụng nấu ăn CRUD rồi bảo họ tự xây xác thực thì thật kỳ lạ
      Người đó nên tập trung vào ý tưởng thực sự thay vì phát minh lại hệ thống ống nước, và nhiều người cuối cùng có thể triển khai sai đến mức thực tế là không có xác thực
  • Phần này sai: “địa chỉ email không phân biệt chữ hoa chữ thường”
    https://thecopenhagenbook.com/email-verification
    Theo tiêu chuẩn email, địa chỉ email có phân biệt chữ hoa chữ thường
    Nếu chuyển email thành chữ thường trong quá trình gửi, thư có thể đến nhầm người, và điều đó nguy hiểm trong xác thực
    Nhiều nhà cung cấp email nổi tiếng chọn không phân biệt chữ hoa chữ thường, nhưng nếu là một trang xử lý xác thực nói chung thì nên khuyến nghị trường hợp tổng quát
    https://stackoverflow.com/questions/9807909/are-email-addres...
    Nói thêm, không phải lúc nào cũng rõ dạng chữ hoa/chữ thường đối ứng của một ký tự là gì, và điều đó cũng có thể thay đổi theo thời gian. Ví dụ chữ ß viết hoa trong tiếng Đức được thêm vào Unicode năm 2008, nên trong lập trình nói chung, nếu có thể thì tốt hơn nên tránh phân biệt chữ hoa chữ thường

    • Câu trả lời được bình chọn cao nhất trên Stack Overflow mà bạn liên kết lại nói ngược lại: “trên thực tế, không hệ thống mail được dùng rộng rãi nào phân biệt các địa chỉ chỉ khác nhau ở chữ hoa/chữ thường”
      Tiêu chuẩn nói một đằng nhưng triển khai lại hoạt động một nẻo, và trong trường hợp này nếu chỉ bám vào câu chữ của tiêu chuẩn thì sẽ gây vấn đề trong thế giới thực
    • Cách tôi làm là lưu chữ hoa chữ thường gốc mà người dùng nhập, nhưng tra cứu thì không phân biệt chữ hoa chữ thường
      Như vậy email sẽ được gửi đến địa chỉ với cách viết hoa thường như lần đầu nhập, còn đăng nhập thì có thể thực hiện bất kể hoa thường
      Nhược điểm là không thể có hai người dùng riêng biệt với email chỉ khác nhau về chữ hoa/chữ thường, nhưng tôi cho rằng như vậy cũng ổn
    • Đã từng có trường hợp khi đăng ký bằng email thì email đó trở thành tên người dùng để đăng nhập
      Email không phân biệt chữ hoa chữ thường, nhưng tên người dùng được tạo từ email lại phân biệt chữ hoa chữ thường, nên nếu tạo tài khoản bằng email có chữ hoa, bạn phải nhập đúng y như vậy mới đăng nhập được, còn nhập email theo kiểu không phân biệt hoa thường thì không đăng nhập được
    • Dẹp luôn chữ hoa đi. Quá lãng phí. Tiếp theo là múi giờ, UTC muôn năm
      Sau đó nếu xóa luôn khác biệt ngôn ngữ và văn hóa thì hàng chục tỷ dòng code sẽ biến mất, tôi đã nghe thấy tiếng kho lưu trữ nhỏ lại rồi
    • Về lý thuyết thì đúng, nhưng trong thực tế tôi đã nhiều lần thấy các hệ thống lưu cùng một email dưới nhiều kiểu viết hoa thường khác nhau vì lỗi triển khai ban đầu
      Ví dụ một bản ghi người dùng có JohnDoe@example.com, bản ghi khác có johndoe@example.com, trong khi rõ ràng là cùng một người
      Hơn nữa, vì các giá trị đến từ các hệ thống khác nhau nên còn rắc rối hơn
      Tôi cho rằng ma trận rủi ro của email không phân biệt chữ hoa chữ thường tốt hơn nhiều so với email có phân biệt chữ hoa chữ thường. Nói cách khác, chuyển mọi email thành chữ thường là đúng, và The Copenhagen Book cũng đúng ở điểm này
  • Rất hay. Tôi luôn không hài lòng với việc 90% tài liệu bảo mật dường như được viết theo cách mà nếu không phải chuyên gia bảo mật thì không thể hiểu nổi. Đặc biệt là tài liệu mật mã học
    Nhưng hầu như mọi trang ở đây đều rõ ràng, ngắn gọn, đi thẳng vào trọng tâm và có thể áp dụng ngay, nên tôi rất thích
    Tuy nhiên trang về đường cong elliptic vẫn khó hiểu như các tài liệu mật mã học khác

    • Nói ngắn gọn về lý do mật mã học khó hiểu: mật mã học dựa vào lý thuyết số và giả định về lý thuyết độ phức tạp rằng N!=NP, tức giả định rằng tồn tại các hàm một chiều/cửa sập
      Bản thân nguyên lý hoạt động là toán học, nên tôi nghĩ nó vốn dĩ khó nhìn thấu
      Sau khi hiểu trường hữu hạn, đường cong elliptic, và về cơ bản là các nhóm số nguyên, tôi đã có thể nắm được nhiều phần của mật mã học, và phần lớn thường là một dạng nào đó của bài toán logarit rời rạc
  • Sẽ tốt hơn nếu có thêm các tài liệu thay thế về chủ đề tương tự. Ví dụ như OWASP Cheatsheet, nhưng là tài liệu theo góc nhìn thực tiễn hơn
    Tôi tôn trọng nó, nhưng hơi hoài nghi về tài liệu này
    Cái tên khá hoành tráng. Gọi tài liệu như thể do các nhà nghiên cứu đại học ở Copenhagen viết là một chiêu marketing rất hay
    Đúng là Lucia là một thư viện tương đối phổ biến, nhưng điều đó không có nghĩa là nó quảng bá best practice, hay tác giả nên được xem là người có thẩm quyền trong lĩnh vực quan trọng này
    Tôi cũng không thích một số phần trong thiết kế của Lucia. Khi token của người dùng sắp hết hạn, nó gợi ý kéo dài thời gian sống của token hiện tại thay vì tạo token bảo mật mới
    Việc token về cơ bản sống mãi và có thể tiếp tục bị lạm dụng trông rất không an toàn, và vi phạm best practice bảo mật về vòng đời token có giới hạn
    Cả Lucia và “Copenhagen Book” đều khuyến nghị cách này: https://thecopenhagenbook.com/sessions#session-lifetime

    • Đoạn mã trong liên kết bạn đưa có vẻ không “kéo dài” vòng đời token, mà là kéo dài phiên
      Đây là cách làm phổ biến, thường được gọi là rolling session
      Bản thân token ngay từ đầu nên là bất biến, nên không thể thay đổi vòng đời của nó; vì vậy việc làm mới token vốn là cấp một token mới, chứ không phải sửa token ban đầu
    • Nếu bạn hủy token và phản hồi cho client bằng token mới, nhưng client đã gửi một yêu cầu mới bằng token cũ, thì yêu cầu đó sẽ bị từ chối
    • Trong ngữ cảnh của Lucia, tôi xem việc kéo dài phiên hiện có và tạo phiên mới là không khác nhau
      Ở trường hợp thứ nhất, kẻ tấn công đánh cắp token và dùng mãi mãi. Ở trường hợp thứ hai, nếu kẻ tấn công đánh cắp token rồi nhận token mới ngay trước khi hết hạn, họ vẫn có thể tiếp tục mạo danh người dùng
      Nếu người dùng bị đá ra ngoài thì có thể họ sẽ nhận ra điều gì đó, nhưng khả năng thấp; và để có trải nghiệm người dùng tốt thì dù sao cũng cần một khoảng gia hạn. Nếu không, người dùng hợp lệ cũng sẽ gặp vấn đề với các yêu cầu song song
      Có thể dùng token thứ hai, tức refresh token, nhưng như vậy chỉ chuyển rủi ro sang token đó. Lúc này bạn phải lo refresh token bị đánh cắp và bị lạm dụng mãi mãi
      Refresh token hữu ích ở chỗ không cần chạm cơ sở dữ liệu ở mọi yêu cầu. Thông thường, session token có vòng đời ngắn có thể được xác thực không cần cơ sở dữ liệu, chẳng hạn như JWT đã ký
      Nhưng khi bị đánh cắp thì không thể vô hiệu hóa và vẫn hợp lệ cho đến khi hết hạn, nên để giảm thiệt hại thì thời gian hết hạn phải ngắn
      Ngược lại, refresh token sẽ truy vấn cơ sở dữ liệu. Bản thân token thứ hai không tăng thêm bảo mật; chính việc truy vấn cơ sở dữ liệu mới tăng bảo mật. Vì có thể xóa nó khỏi cơ sở dữ liệu để vô hiệu hóa
      Lucia, ít nhất theo các ví dụ, luôn truy vấn cơ sở dữ liệu nên có thể vô hiệu hóa token bất cứ lúc nào
      Để giảm rủi ro, nên cho phép người dùng xem và kết thúc các phiên đang hoạt động. Nếu có thể, nên hiển thị cả thời gian, vị trí và thông tin thiết bị. Ví dụ: “Đăng nhập lúc 12 giờ sáng hôm qua từ iPhone ở Copenhagen”
      Cũng có thể thông báo cho người dùng khi có đăng nhập từ vị trí hoặc thiết bị mới
      Rốt cuộc, không có cách nào triển khai phiên tồn tại lâu dài mà hoàn toàn an toàn
    • Có vẻ bạn đang gán quá nhiều ý nghĩa cho cái tên. Dù vậy tôi cũng tò mò về phương án thay thế cho việc thay thế session token
      Tôi nghĩ đó là một nhận xét hay, nhưng không thể nói tôi là chuyên gia
  • Có hai điều trong OAuth mà mọi người đều bỏ lỡ, và chúng không dễ thấy
    Tôi rất vui vì có người đã chỉ ra một trong số đó. Khi dùng token, bắt buộc phải dùng transaction như một cơ chế khóa phân tán
    Với refresh token, tầm quan trọng này tăng gấp đôi, gấp bốn. Nếu dùng cùng một token từ hai lần trở lên, người dùng đó sẽ bị đăng xuất
    Không quan trọng hệ thống chạy trên một máy hay N máy. Nếu có từ hai yêu cầu trở lên kèm refresh token đang diễn ra đồng thời — điều này xảy ra rất thường xuyên — nó sẽ đăng xuất người dùng và thường kết thúc bằng lỗi 500
    Refresh token là dùng một lần
    Điều còn lại mà các lập trình viên và framework xác thực bỏ lỡ là tham số “state”

    • Trên mạng không có thứ gì là “một lần” cả. Việc máy chủ vô hiệu hóa refresh token ngay khi nhận được nó là tự chuốc lấy rắc rối
    • Tôi thấy nó quá phức tạp và không phù hợp cho xác thực hằng ngày
      Nhìn vào hướng phát triển chung của xác thực hiện nay, có vẻ nó đang tiến gần đến sự bất ổn do mơ hồ, chứ không phải bảo mật nhờ mơ hồ
      Khi cả trạng thái ứng dụng cũng bị cuốn vào, bạn phải điều chỉnh logic ứng dụng theo xác thực, và ứng dụng phải kiểm tra xem có ai đó đã đánh cắp refresh token hay không
    • Vì lý do tương tự, hầu hết hệ thống triển khai khoảng gia hạn tái sử dụng refresh token
      Chỉ transaction thôi không giải quyết được. Ví dụ, nếu mở nhanh hai tab, bạn sẽ đánh vào máy chủ hai lần bằng refresh token ban đầu
    • Rất có thể bạn biết tài liệu OAuth Threat Model
      Tài liệu đó ưu tiên refresh token rotation, nhưng cũng đề cập đến khó khăn hiển nhiên trong môi trường cluster: https://datatracker.ietf.org/doc/html/rfc6819#section-5.2.2....
    • Xin lỗi, nhưng trong ứng dụng thực tế nó không hoạt động như vậy
      Nhiều yêu cầu luôn xảy ra đồng thời. Ví dụ, trình duyệt khởi động với nhiều tab, hoặc ứng dụng smartphone khởi động và gửi nhiều yêu cầu cùng lúc là chuyện phổ biến
  • Mong rằng nhiều trang web hơn sẽ đưa ra lựa chọn “hãy để phiên không hết hạn cho đến khi tôi đăng xuất, tôi hiểu rủi ro”
    Dạo này nút “remember me” chẳng có tác dụng gì
    Cứ bị ngắt quãng cả ngày vì phiên hết hạn, thật là bực. Tôi đặc biệt ghét GitHub: vì chỉ dùng khoảng mỗi tuần một lần nên phiên luôn hết hạn, lại còn bắt buộc xác thực 2 bước, lần nào cũng phải lấy điện thoại ra nhập số
    Trải nghiệm người dùng đã tệ, nhưng dù không có bằng chứng, tôi nghĩ việc liên tục bắt đăng nhập như vậy khiến người dùng mệt mỏi và kém chú ý hơn
    Nếu phải đăng nhập vào một trang nhiều lần mỗi tuần, đến lần đăng nhập thứ 60 thì một trang phishing chen vào sẽ dễ hơn. Ngược lại, với một tài khoản hầu như không bao giờ phải đăng nhập, nếu đột nhiên bị yêu cầu mật khẩu thì sẽ thấy bất thường và cảnh giác hơn
    Cuối cùng, các công ty cần hiểu rằng mỗi người có mức chấp nhận rủi ro và tư thế bảo mật khác nhau, rồi cung cấp lựa chọn
    Nói thêm, việc GitHub thường xuyên hết hạn phiên và bắt xác thực 2 bước quá khó chịu nên tôi đã chuyển sang Gitea và tắt hết hạn phiên. 90% lý do chuyển là vì chuyện đó
    Vì chỉ có thể truy cập từ mạng của tôi nên tôi cảm thấy bảo mật thậm chí còn tốt hơn. Việc một công ty mất khách hàng vì mô hình bảo mật thiếu linh hoạt là hoàn toàn có thể xảy ra

    • Tài liệu này có khuyến nghị tốt về cách xử lý thời lượng phiên
      Đại khái là nếu phiên được dùng trong vòng 30 ngày thì cho phiên tiếp tục thêm 30 ngày nữa
      https://thecopenhagenbook.com/sessions#session-lifetime
    • Với tôi thì Notion là tệ nhất. Không phải vì tần suất, mà vì nó thực sự cắt phiên đang hoạt động và bắt đăng nhập lại
      Tệ hơn nữa là phiên có vẻ kéo dài hơn một tuần khoảng 1–2 phút, nên tuần này tôi bị đá ra ngay sau khi bắt đầu công việc từ tuần trước
      Vài tuần trước tôi đăng nhập để ghi chú ngay trước một cuộc họp định kỳ, và trong nhiều tuần liên tiếp tôi bị buộc đăng nhập giữa chừng cuộc họp đó
    • Cũng nên kiểm tra xem bạn có thay đổi gì trong cài đặt trình duyệt không
      Có rất nhiều cài đặt có thể vô hiệu hóa kiểu nút “remember me” đó
      Cá nhân tôi không gặp vấn đề gì với việc duy trì đăng nhập trên các trang web, bao gồm cả GitHub
    • Một số nhà cung cấp xác thực giới hạn thời lượng token tùy theo gói dịch vụ
    • Ít nhất thì còn có thể thưởng thức màn kịch bảo mật
  • Gần đây tôi mới biết đến giao thức SRP, và khá ngạc nhiên là nó không được dùng hay nhắc đến rộng rãi hơn
    Đây là một giao thức tương đối đơn giản, có thể thực hiện chứng minh không tiết lộ thông tin và đồng thời tạo token phiên giữa máy chủ và client
    https://en.wikipedia.org/wiki/Secure_Remote_Password_protoco...

    • Việc áp dụng bị cản trở vì bằng sáng chế
  • Tôi thích tài liệu này. Nhiều lời khuyên về bảo mật khó hiểu và đôi khi nghe vô lý. Giống như luật sư khuyên đừng làm gì cả
    Hướng dẫn này hay ở chỗ ngắn gọn một cách sảng khoái, dễ theo dõi, dễ hiểu và có lời khuyên thẳng thắn
    Tôi sẽ tiếp tục xem bình luận để biết có ý kiến phản biện hay điểm cần lưu ý nào không, nhưng có lẽ tôi sẽ dùng nó để đối chiếu với dự án xác thực của mình
    Có một điều tôi mong muốn là có mục JWT. Nếu ý kiến của tác giả là “đừng dùng” thì chỉ cần nói vậy cũng được

    • Cách nói “giống như luật sư khuyên đừng làm gì cả” rất đúng
      Một trong những điều tôi thường phê bình các nhóm phụ trách bảo mật là họ dành nhiều thời gian nói những gì không được làm, thay vì chủ động cung cấp công cụ hay cách thức để mọi người làm hiệu quả những việc họ muốn làm
    • Tôi cũng muốn có một mục SAML và phần tổng quan cấp cao về cách triển khai
    • Với các luồng email như xác nhận email hoặc đặt lại mật khẩu, tôi khuyến nghị để chúng có hiệu lực trong vài ngày nếu token bí mật đủ mạnh
      Email có thể được xem là hệ thống an toàn hơn, nên không nhất thiết lúc nào cũng truy cập được ngay lập tức hoặc ở mọi nơi
  • Tôi thắc mắc “auth” ở đây nghĩa là xác thực (authn) hay phân quyền (authz)
    Nhìn thì có vẻ là xác thực, nhưng sẽ tốt hơn nếu làm rõ

    • Vì nói về token phiên, mật khẩu và WebAuthn nên có vẻ bao gồm cả hai
  • Một lời phàn nàn ngắn hơi liên quan: trình duyệt nhúng đang phá hỏng web
    Trình duyệt nhúng khiến việc dùng OAuth xã hội trở nên bất khả thi. Trong một số trường hợp là bất khả thi theo đúng nghĩa đen, còn trong các trường hợp khác thì gần như bất khả thi
    Khi nhấn một liên kết trong Instagram, mặc định nó mở trong trình duyệt của Instagram; nếu liên kết đó có “Sign in with Google” thì Google sẽ chặn “trình duyệt không an toàn” như Instagram, nên nó không hoạt động
    Ngay cả “Sign in with Facebook” cũng gặp vấn đề, dù Meta sở hữu cả Instagram lẫn Facebook. Trình duyệt nhúng của Facebook cũng có vấn đề tương tự

    • Trình duyệt nhúng có nhiều công dụng tốt, nhưng điều hướng đến các liên kết tùy ý không phải là một trong số đó
      Việc nhấn liên kết ở nơi như Slack, rồi trả lời tin nhắn, sau đó quay lại trình duyệt và mong trang đó vẫn còn, nhưng Slack đã nuốt nó vào trong trình duyệt của chính mình khiến nó chẳng ở đâu cả, hầu như luôn vô dụng
      May là tôi vừa kiểm tra và thấy Slack có cách tắt trình duyệt nhúng