Mã thông báo Web JSON không hợp lệ


421

Đối với dự án node.js mới mà tôi đang làm việc, tôi đang suy nghĩ về việc chuyển đổi từ cách tiếp cận phiên dựa trên cookie (ý tôi là, lưu trữ id vào kho lưu trữ khóa giá trị có chứa phiên người dùng trong trình duyệt của người dùng) đến cách tiếp cận phiên dựa trên mã thông báo (không lưu trữ khóa-giá trị) bằng cách sử dụng Mã thông báo Web JSON (jwt).

Dự án là một trò chơi sử dụng socket.io - có phiên dựa trên mã thông báo sẽ hữu ích trong trường hợp như vậy trong đó sẽ có nhiều kênh liên lạc trong một phiên duy nhất (web và socket.io)

Làm thế nào một người cung cấp mã thông báo / hiệu lực phiên từ máy chủ bằng cách sử dụng Phương pháp tiếp cận jwt?

Tôi cũng muốn hiểu những cạm bẫy / tấn công phổ biến (hoặc không phổ biến) mà tôi nên tìm ra với mô hình này. Ví dụ: nếu mô hình này dễ bị tấn công giống / khác nhau như cách tiếp cận dựa trên lưu trữ phiên / cookie.

Vì vậy, giả sử tôi có những điều sau đây (được điều chỉnh từ cái nàycái này ):

Đăng nhập cửa hàng phiên:

app.get('/login', function(request, response) {
    var user = {username: request.body.username, password: request.body.password };
    // Validate somehow
    validate(user, function(isValid, profile) {
        // Create session token
        var token= createSessionToken();

        // Add to a key-value database
        KeyValueStore.add({token: {userid: profile.id, expiresInMinutes: 60}});

        // The client should save this session token in a cookie
        response.json({sessionToken: token});
    });
}

Đăng nhập dựa trên mã thông báo:

var jwt = require('jsonwebtoken');
app.get('/login', function(request, response) {
    var user = {username: request.body.username, password: request.body.password };
    // Validate somehow
    validate(user, function(isValid, profile) {
        var token = jwt.sign(profile, 'My Super Secret', {expiresInMinutes: 60});
        response.json({token: token});
    });
}

-

Đăng xuất (hoặc không hợp lệ) cho phương pháp Lưu trữ phiên sẽ yêu cầu cập nhật cơ sở dữ liệu KeyValueStore với mã thông báo được chỉ định.

Có vẻ như một cơ chế như vậy sẽ không tồn tại trong cách tiếp cận dựa trên mã thông báo vì chính mã thông báo sẽ chứa thông tin thường tồn tại trong kho lưu trữ khóa-giá trị.


1
Nếu bạn đang sử dụng gói 'express-jwt', bạn có thể xem isRevokedtùy chọn hoặc cố gắng sao chép cùng chức năng. github.com/auth0/express-jwt#revoking-tokens
Signus

1
Cân nhắc sử dụng thời gian hết hạn ngắn trên mã thông báo truy cập và sử dụng mã thông báo làm mới, với thời gian hết hạn dài, để cho phép kiểm tra trạng thái truy cập của người dùng trong cơ sở dữ liệu (danh sách đen). auth0.com/blog/ Kẻ
Rohmer

một tùy chọn khác sẽ gắn địa chỉ IP trong tải trọng trong khi tạo mã thông báo jwt và kiểm tra IP được lưu trữ so với yêu cầu đến cho cùng một địa chỉ IP. ví dụ: req.connection.remoteAddress trong nodeJs. Có những nhà cung cấp ISP không phát hành IP tĩnh cho mỗi khách hàng, tôi nghĩ đây sẽ không phải là vấn đề trừ khi khách hàng kết nối lại với internet.
Gihan Sandaru

Câu trả lời:


392

Tôi cũng đã nghiên cứu câu hỏi này và trong khi không có ý tưởng nào dưới đây là giải pháp hoàn chỉnh, chúng có thể giúp người khác loại bỏ ý tưởng hoặc cung cấp thêm ý tưởng.

1) Chỉ cần xóa mã thông báo khỏi máy khách

Rõ ràng điều này không làm gì cho bảo mật phía máy chủ, nhưng nó ngăn chặn kẻ tấn công bằng cách loại bỏ mã thông báo khỏi sự tồn tại (nghĩa là họ sẽ phải đánh cắp mã thông báo trước khi đăng xuất).

2) Tạo danh sách đen mã thông báo

Bạn có thể lưu trữ mã thông báo không hợp lệ cho đến ngày hết hạn ban đầu của chúng và so sánh chúng với các yêu cầu đến. Điều này dường như phủ nhận lý do để đi mã thông báo đầy đủ dựa trên vị trí đầu tiên, vì bạn sẽ cần phải chạm vào cơ sở dữ liệu cho mọi yêu cầu. Tuy nhiên, kích thước lưu trữ có thể sẽ thấp hơn, vì bạn chỉ cần lưu trữ các mã thông báo giữa thời gian đăng xuất và thời gian hết hạn (đây là một cảm giác tốt và chắc chắn phụ thuộc vào ngữ cảnh).

3) Chỉ cần giữ thời gian hết hạn của mã thông báo và xoay chúng thường xuyên

Nếu bạn giữ thời gian hết hạn của mã thông báo trong khoảng thời gian đủ ngắn và để khách hàng đang chạy theo dõi và yêu cầu cập nhật khi cần thiết, số 1 sẽ hoạt động hiệu quả như một hệ thống đăng xuất hoàn chỉnh. Vấn đề với phương pháp này là nó khiến cho người dùng không thể đăng nhập giữa các lần đóng mã máy khách (tùy thuộc vào khoảng thời gian bạn thực hiện khoảng thời gian hết hạn).

Kế hoạch dự phòng

Nếu có trường hợp khẩn cấp hoặc mã thông báo người dùng bị xâm phạm, một điều bạn có thể làm là cho phép người dùng thay đổi ID tra cứu người dùng cơ bản bằng thông tin đăng nhập của họ. Điều này sẽ khiến tất cả các mã thông báo được liên kết không hợp lệ, vì người dùng được liên kết sẽ không thể tìm thấy nữa.

Tôi cũng muốn lưu ý rằng nên bao gồm ngày đăng nhập cuối cùng với mã thông báo, để bạn có thể thực thi một relogin sau một khoảng thời gian xa.

Về mặt tương đồng / khác biệt liên quan đến các cuộc tấn công sử dụng mã thông báo, bài đăng này giải quyết câu hỏi: https://github.com/dentarg/blog/blob/master/_posts/2014-01-07-angularjs-authentication-with-cookies -vs-token.markdown


3
Cách tiếp cận tuyệt vời. Ruột của tôi sẽ là thực hiện kết hợp cả 3 và / hoặc, yêu cầu mã thông báo mới sau mỗi yêu cầu "n" (trái ngược với bộ đếm thời gian). Chúng tôi đang sử dụng redis để lưu trữ đối tượng trong bộ nhớ và chúng tôi có thể dễ dàng sử dụng điều này cho trường hợp # 2, và sau đó độ trễ sẽ giảm CÁCH.
Aaron Wagner

2
Bài đăng kinh dị mã hóa này cung cấp một số lời khuyên: Giữ các cookie mang phiên (hoặc mã thông báo) ngắn nhưng làm cho nó vô hình với người dùng - dường như phù hợp với # 3. Ruột của riêng tôi (có lẽ vì nó truyền thống hơn) chỉ là để mã thông báo (hoặc băm của nó) hoạt động như một khóa vào cơ sở dữ liệu phiên được liệt kê trắng (tương tự # 2)
funseiki

8
Bài viết được viết tốt, và là một phiên bản công phu 2)ở trên. Mặc dù nó hoạt động tốt, nhưng cá nhân tôi không thấy nhiều sự khác biệt so với các cửa hàng phiên truyền thống. Tôi đoán yêu cầu lưu trữ sẽ thấp hơn, nhưng bạn vẫn yêu cầu cơ sở dữ liệu. Sức hấp dẫn lớn nhất của JWT đối với tôi là không sử dụng cơ sở dữ liệu nào cho các phiên.
Matt Way

211
Một cách tiếp cận phổ biến để vô hiệu hóa mã thông báo khi người dùng thay đổi mật khẩu của họ là ký mã thông báo bằng hàm băm mật khẩu của họ. Do đó, nếu mật khẩu thay đổi, mọi mã thông báo trước đó sẽ tự động không thể xác minh. Bạn có thể mở rộng điều này để đăng xuất bằng cách đưa thời gian đăng xuất cuối cùng vào bản ghi của người dùng và sử dụng kết hợp băm mật khẩu lần cuối và mật khẩu để đăng nhập mã thông báo. Điều này yêu cầu tra cứu DB mỗi lần bạn cần xác minh chữ ký mã thông báo, nhưng có lẽ bạn vẫn đang tìm kiếm người dùng.
Travis Terry

4
Một danh sách đen có thể được thực hiện hiệu quả bằng cách giữ nó trong bộ nhớ, do đó DB chỉ cần được nhấn để ghi lại các thông tin không hợp lệ và loại bỏ các vô hiệu đã hết hạn và chỉ đọc khi khởi chạy máy chủ. Trong kiến ​​trúc cân bằng tải, danh sách đen trong bộ nhớ có thể thăm dò DB trong các khoảng thời gian ngắn, như 10 giây, hạn chế sự phơi bày của các mã thông báo không hợp lệ. Các cách tiếp cận này cho phép máy chủ tiếp tục xác thực các yêu cầu mà không cần truy cập DB theo yêu cầu.
Joe Lapp

86

Các ý tưởng được đăng ở trên là tốt, nhưng một cách rất đơn giản và dễ dàng để vô hiệu hóa tất cả các JWT hiện tại chỉ đơn giản là thay đổi bí mật.

Nếu máy chủ của bạn tạo JWT, hãy ký nó với một bí mật (JWS) sau đó gửi nó đến máy khách, chỉ cần thay đổi bí mật sẽ làm mất hiệu lực tất cả các mã thông báo hiện có và yêu cầu tất cả người dùng nhận mã thông báo mới để xác thực vì mã thông báo cũ của họ đột nhiên không hợp lệ theo đến máy chủ.

Nó không yêu cầu bất kỳ sửa đổi nào đối với nội dung mã thông báo thực tế (hoặc ID tra cứu).

Rõ ràng điều này chỉ hoạt động cho trường hợp khẩn cấp khi bạn muốn tất cả các mã thông báo hiện tại hết hạn, đối với mỗi mã thông báo hết hạn một trong các giải pháp ở trên là bắt buộc (chẳng hạn như thời gian hết hạn mã thông báo ngắn hoặc vô hiệu hóa khóa được lưu trữ bên trong mã thông báo).


9
Tôi nghĩ rằng phương pháp này không lý tưởng. Mặc dù nó hoạt động và chắc chắn là đơn giản, hãy tưởng tượng một trường hợp bạn đang sử dụng khóa chung - bạn sẽ không muốn đi và tạo lại khóa đó bất cứ khi nào bạn muốn làm mất hiệu lực một mã thông báo.
Signus

1
@KijanaWoodard, một cặp khóa công khai / riêng tư có thể được sử dụng để xác thực chữ ký là bí mật có hiệu quả trong thuật toán RS256. Trong ví dụ hiển thị ở đây, ông đề cập đến việc thay đổi bí mật để vô hiệu hóa JWT. Điều này có thể được thực hiện bằng cách a) giới thiệu một pubkey giả không khớp với chữ ký hoặc b) tạo ra một pubkey mới. Trong tình huống đó, nó ít hơn lý tưởng.
Signus

1
@Signus - gotcha. không sử dụng khóa chung làm bí mật, nhưng những người khác có thể dựa vào khóa chung để xác minh chữ ký.
Kijana Woodard

8
Đây là giải pháp rất xấu. Lý do chính để sử dụng JWT là nó không trạng thái và tỷ lệ. Sử dụng một bí mật năng động giới thiệu một trạng thái. Nếu dịch vụ được nhóm trên nhiều nút, bạn sẽ phải đồng bộ hóa bí mật mỗi khi mã thông báo mới được phát hành. Bạn sẽ phải lưu trữ bí mật trong cơ sở dữ liệu hoặc dịch vụ bên ngoài khác, đó sẽ chỉ là phát minh lại xác thực dựa trên cookie
Tuomas Toivonen

5
@TuomasToivonen, nhưng bạn phải ký JWT với một bí mật và có thể xác minh JWT bằng chính bí mật đó. Vì vậy, bạn phải lưu trữ bí mật trên các tài nguyên được bảo vệ. Nếu bí mật bị xâm phạm, bạn phải thay đổi nó và phân phối thay đổi đó cho từng nút của bạn. Các nhà cung cấp dịch vụ lưu trữ với phân cụm / chia tỷ lệ thường cho phép bạn lưu trữ các bí mật trong dịch vụ của họ để giúp phân phối các bí mật này dễ dàng và đáng tin cậy.
Rohmer

67

Đây chủ yếu là một bình luận dài hỗ trợ và xây dựng dựa trên câu trả lời của @mattway

Được:

Một số giải pháp được đề xuất khác trên trang này ủng hộ việc truy cập kho dữ liệu theo mọi yêu cầu. Nếu bạn nhấn kho dữ liệu chính để xác thực mọi yêu cầu xác thực, thì tôi thấy ít lý do hơn để sử dụng JWT thay vì các cơ chế xác thực mã thông báo được thiết lập khác. Về cơ bản, bạn đã khiến JWT trở nên trạng thái, thay vì không trạng thái nếu bạn truy cập kho dữ liệu mỗi lần.

(Nếu trang web của bạn nhận được một khối lượng lớn yêu cầu trái phép, thì JWT sẽ từ chối chúng mà không cần nhấn kho dữ liệu, điều này rất hữu ích. Có thể có các trường hợp sử dụng khác như vậy.)

Được:

Xác thực JWT không trạng thái thực sự không thể đạt được đối với một ứng dụng web thế giới thực điển hình vì JWT không trạng thái không có cách cung cấp hỗ trợ ngay lập tứcan toàn cho các trường hợp sử dụng quan trọng sau:

Tài khoản của người dùng bị xóa / chặn / treo.

Mật khẩu của người dùng được thay đổi.

Vai trò hoặc quyền của người dùng được thay đổi.

Người dùng được đăng xuất bởi quản trị viên.

Bất kỳ dữ liệu quan trọng ứng dụng nào khác trong mã thông báo JWT đều được quản trị viên trang web thay đổi.

Bạn không thể chờ hết hạn mã thông báo trong những trường hợp này. Việc vô hiệu hóa mã thông báo phải xảy ra ngay lập tức. Ngoài ra, bạn không thể tin tưởng khách hàng không giữ và sử dụng bản sao của mã thông báo cũ, cho dù có mục đích xấu hay không.

Do đó: Tôi nghĩ rằng câu trả lời từ @ matt-way, # 2 TokenBlackList, sẽ là cách hiệu quả nhất để thêm trạng thái cần thiết vào xác thực dựa trên JWT.

Bạn có một danh sách đen chứa các mã thông báo này cho đến khi hết hạn sử dụng. Danh sách mã thông báo sẽ khá nhỏ so với tổng số người dùng, vì nó chỉ phải giữ các mã thông báo trong danh sách đen cho đến khi hết hạn. Tôi sẽ triển khai bằng cách đặt mã thông báo không hợp lệ vào redis, memcached hoặc một kho dữ liệu trong bộ nhớ khác hỗ trợ đặt thời gian hết hạn trên khóa.

Bạn vẫn phải thực hiện cuộc gọi tới db trong bộ nhớ cho mọi yêu cầu xác thực vượt qua xác thực JWT ban đầu, nhưng bạn không phải lưu trữ khóa cho toàn bộ nhóm người dùng của mình ở đó. (Điều này có thể hoặc không thể là một vấn đề lớn đối với một trang web nhất định.)


15
Tôi không đồng ý với câu trả lời của bạn. Đánh một cơ sở dữ liệu không làm cho bất cứ điều gì nhà nước; trạng thái lưu trữ trên phụ trợ của bạn nào. JWT không được tạo để bạn không phải truy cập cơ sở dữ liệu theo từng yêu cầu. Mọi ứng dụng chính sử dụng JWT đều được hỗ trợ bởi cơ sở dữ liệu. JWT giải quyết một vấn đề hoàn toàn khác. vi.wikipedia.org/wiki/Statless_protatio
Julian

6
@Julian bạn có thể giải thích một chút về điều này? Vấn đề nào JWT thực sự giải quyết sau đó?
zero01alpha

8
@ zero01alpha Xác thực: Đây là trường hợp phổ biến nhất để sử dụng JWT. Khi người dùng đã đăng nhập, mỗi yêu cầu tiếp theo sẽ bao gồm JWT, cho phép người dùng truy cập các tuyến đường, dịch vụ và tài nguyên được phép với mã thông báo đó. Trao đổi thông tin: Mã thông báo Web JSON là một cách tốt để truyền thông tin an toàn giữa các bên. Bởi vì JWT có thể được ký, bạn có thể chắc chắn rằng người gửi là người họ nói. Xem jwt.io/int sinhtion
Julian

7
@Julian Tôi không đồng ý với sự bất đồng của bạn :) JWT giải quyết vấn đề (đối với dịch vụ) để có nhu cầu truy cập một thực thể tập trung cung cấp thông tin ủy quyền cho bất kỳ khách hàng cụ thể nào. Vì vậy, thay vì dịch vụ A và dịch vụ B phải truy cập một số tài nguyên để tìm hiểu xem máy khách X có hoặc không có quyền để làm gì đó, dịch vụ A và B nhận được mã thông báo từ X chứng minh quyền của mình (thường được cấp bởi người thứ 3 buổi tiệc). Dù sao, JWT là một công cụ giúp tránh trạng thái chia sẻ giữa các dịch vụ trong một hệ thống, đặc biệt là khi chúng được kiểm soát bởi nhiều hơn một nhà cung cấp dịch vụ.
LIvanov

1
Cũng từ jwt.io/int sinhtion If the JWT contains the necessary data, the need to query the database for certain operations may be reduced, though this may not always be the case.
giantas

43

Tôi sẽ giữ một bản ghi số phiên bản jwt trên mô hình người dùng. Mã thông báo jwt mới sẽ đặt phiên bản của họ thành này.

Khi bạn xác thực jwt, chỉ cần kiểm tra xem nó có số phiên bản bằng với phiên bản jwt hiện tại của người dùng không.

Bất cứ khi nào bạn muốn vô hiệu hóa jwts cũ, chỉ cần tăng số phiên bản jwt của người dùng.


15
Đây là một ý tưởng thú vị, điều duy nhất là nơi lưu trữ phiên bản, vì một phần mục đích của mã thông báo là nó không trạng thái và không cần sử dụng cơ sở dữ liệu. Một phiên bản được mã hóa cứng sẽ khiến nó khó bị lỗi và số phiên bản trong cơ sở dữ liệu sẽ phủ nhận một số lợi ích của việc sử dụng mã thông báo.
Stephen Smith

13
Có lẽ bạn đã lưu trữ id người dùng trong mã thông báo của mình và sau đó truy vấn cơ sở dữ liệu để kiểm tra xem người dùng có tồn tại / được phép truy cập điểm cuối api hay không. Vì vậy, bạn không thực hiện bất kỳ truy vấn db bổ sung nào bằng cách so sánh số phiên bản mã thông báo jwt với số truy cập trên người dùng.
DaftMonk

5
Tôi không nên nói có lẽ, bởi vì có rất nhiều tình huống mà bạn có thể sử dụng mã thông báo với các xác nhận không chạm vào cơ sở dữ liệu. Nhưng tôi nghĩ trong trường hợp này thật khó để tránh.
DaftMonk

11
Nếu người dùng đăng nhập từ nhiều thiết bị thì sao? Nên sử dụng một mã thông báo trên tất cả chúng hay nên đăng nhập không hợp lệ tất cả các mã trước đó?
meeDamian

10
Tôi đồng ý với @SergioCorrea Điều này sẽ khiến JWT gần như có trạng thái như bất kỳ cơ chế xác thực mã thông báo nào khác.
Ed J

40

Chưa thử điều này và nó sử dụng rất nhiều thông tin dựa trên một số câu trả lời khác. Sự phức tạp ở đây là để tránh một cuộc gọi lưu trữ dữ liệu phía máy chủ theo yêu cầu thông tin người dùng. Hầu hết các giải pháp khác yêu cầu tra cứu db theo yêu cầu đối với cửa hàng phiên người dùng. Điều đó là tốt trong một số trường hợp nhất định nhưng điều này đã được tạo ra trong một nỗ lực để tránh các cuộc gọi như vậy và làm cho bất kỳ trạng thái phía máy chủ yêu cầu nào trở nên rất nhỏ. Cuối cùng, bạn sẽ tạo lại một phiên phía máy chủ, tuy nhiên nhỏ để cung cấp tất cả các tính năng vô hiệu hóa lực lượng. Nhưng nếu bạn muốn làm điều đó ở đây là ý chính:

Bàn thắng:

  • Giảm thiểu việc sử dụng một kho lưu trữ dữ liệu (không có nhà nước).
  • Khả năng buộc đăng xuất tất cả người dùng.
  • Có khả năng buộc đăng xuất bất kỳ cá nhân bất cứ lúc nào.
  • Khả năng yêu cầu nhập lại mật khẩu sau một khoảng thời gian nhất định.
  • Có khả năng làm việc với nhiều khách hàng.
  • Khả năng buộc đăng nhập lại khi người dùng nhấp vào đăng xuất từ ​​một khách hàng cụ thể. (Để ngăn người nào đó "xóa" mã thông báo khách hàng sau khi người dùng bỏ đi - xem bình luận để biết thêm thông tin)

Giải pháp:

  • Sử dụng mã thông báo truy cập có thời gian tồn tại ngắn (<5m) được ghép nối với mã thông báo làm mới được lưu trữ lâu hơn (vài giờ) .
  • Mỗi yêu cầu kiểm tra ngày hết hạn xác thực hoặc làm mới mã thông báo để xác thực.
  • Khi mã thông báo truy cập hết hạn, khách hàng sử dụng mã thông báo làm mới để làm mới mã thông báo truy cập.
  • Trong quá trình kiểm tra mã thông báo làm mới, máy chủ sẽ kiểm tra một danh sách đen nhỏ các id người dùng - nếu tìm thấy từ chối yêu cầu làm mới.
  • Khi khách hàng không có mã làm mới hợp lệ (chưa hết hạn) hoặc mã xác thực, người dùng phải đăng nhập lại, vì tất cả các yêu cầu khác sẽ bị từ chối.
  • Theo yêu cầu đăng nhập, kiểm tra lưu trữ dữ liệu người dùng để cấm.
  • Khi đăng xuất - thêm người dùng đó vào danh sách đen phiên để họ phải đăng nhập lại. Bạn sẽ phải lưu trữ thông tin bổ sung để không đăng xuất chúng khỏi tất cả các thiết bị trong môi trường đa thiết bị nhưng có thể được thực hiện bằng cách thêm trường thiết bị vào danh sách đen người dùng.
  • Để buộc nhập lại sau x lượng thời gian - duy trì ngày đăng nhập cuối cùng trong mã thông báo xác thực và kiểm tra nó theo yêu cầu.
  • Để buộc đăng xuất tất cả người dùng - đặt lại mã băm mã thông báo.

Điều này đòi hỏi bạn phải duy trì một danh sách đen (trạng thái) trên máy chủ, giả sử bảng người dùng chứa thông tin người dùng bị cấm. Danh sách đen phiên không hợp lệ - là danh sách id người dùng. Danh sách đen này chỉ được kiểm tra trong khi yêu cầu mã thông báo làm mới. Các mục nhập được yêu cầu để sống trên đó miễn là mã thông báo làm mới TTL. Khi mã thông báo làm mới hết hạn, người dùng sẽ được yêu cầu đăng nhập lại.

Nhược điểm:

  • Vẫn cần phải thực hiện tra cứu lưu trữ dữ liệu theo yêu cầu mã thông báo làm mới.
  • Mã thông báo không hợp lệ có thể tiếp tục hoạt động để truy cập vào mã thông báo truy cập.

Ưu điểm:

  • Cung cấp chức năng mong muốn.
  • Hành động làm mới mã thông báo được ẩn khỏi người dùng trong hoạt động bình thường.
  • Chỉ yêu cầu thực hiện tra cứu lưu trữ dữ liệu trên các yêu cầu làm mới thay vì mọi yêu cầu. tức là cứ sau 15 phút thay vì 1 giây.
  • Giảm thiểu trạng thái phía máy chủ thành một danh sách đen rất nhỏ.

Với giải pháp này, việc lưu trữ dữ liệu trong bộ nhớ như reddis là không cần thiết, ít nhất là không dành cho thông tin người dùng như bạn vì máy chủ chỉ thực hiện cuộc gọi db cứ sau 15 phút. Nếu sử dụng reddis, lưu trữ danh sách phiên hợp lệ / không hợp lệ trong đó sẽ là một giải pháp rất nhanh và đơn giản. Không cần mã thông báo làm mới. Mỗi mã thông báo xác thực sẽ có id phiên và id thiết bị, chúng có thể được lưu trữ trong bảng reddis khi tạo và không hợp lệ khi thích hợp. Sau đó, họ sẽ được kiểm tra theo mọi yêu cầu và từ chối khi không hợp lệ.


Thế còn kịch bản một người đứng dậy từ máy tính để cho người khác sử dụng cùng một máy tính thì sao? Người thứ nhất sẽ đăng xuất và hy vọng đăng xuất sẽ chặn ngay người thứ 2. Nếu người thứ 2 là người dùng trung bình, khách hàng có thể dễ dàng chặn người dùng bằng cách xóa mã thông báo. Nhưng nếu người dùng thứ 2 có kỹ năng hack, người dùng có thời gian để khôi phục mã thông báo vẫn còn hiệu lực để xác thực là người dùng thứ 1. Dường như không có cách nào để tránh sự cần thiết phải vô hiệu hóa ngay lập tức các mã thông báo, không chậm trễ.
Joe Lapp

5
Hoặc bạn có thể xóa JWT của mình khỏi Sesion / lưu trữ cục bộ hoặc cookie.
Kamil Kiełczewski

1
Cảm ơn @Ashtonian. Sau khi thực hiện nghiên cứu sâu rộng, tôi đã từ bỏ JWTs. Trừ khi bạn đi đến độ dài bất thường để bảo mật khóa bí mật hoặc trừ khi bạn ủy quyền cho việc triển khai OAuth an toàn, JWT dễ bị tổn thương hơn nhiều so với các phiên thông thường. Xem báo cáo đầy đủ của tôi: by.jtl.xyz/2016/06/the-unspoken-vulnerability-of-jwts.html
Joe Lapp

2
Sử dụng mã thông báo làm mới là chìa khóa để cho phép danh sách đen. Giải thích tuyệt vời: auth0.com/blog/ Kẻ
Rohmer

1
Đây dường như là câu trả lời tốt nhất cho tôi vì nó kết hợp mã thông báo truy cập ngắn hạn với mã thông báo làm mới tồn tại lâu có thể được đưa vào danh sách đen. Khi đăng xuất, khách hàng nên xóa mã thông báo truy cập để người dùng thứ 2 không thể truy cập (mặc dù mã thông báo truy cập sẽ vẫn còn hiệu lực trong vài phút nữa sau khi đăng xuất). @Joe Lapp cho biết một hacker (người dùng thứ 2) nhận được mã thông báo truy cập ngay cả sau khi nó bị xóa. Làm sao?
M3RS

14

Một cách tiếp cận tôi đã xem xét là luôn có iatgiá trị (được ban hành) trong JWT. Sau đó, khi người dùng đăng xuất, lưu trữ dấu thời gian đó trên hồ sơ người dùng. Khi xác thực JWT, chỉ cần so sánh iatdấu thời gian đã đăng xuất cuối cùng. Nếu iatcũ hơn, thì nó không hợp lệ. Có, bạn phải truy cập DB, nhưng dù sao tôi cũng sẽ luôn kéo hồ sơ người dùng nếu JWT không hợp lệ.

Nhược điểm lớn mà tôi thấy ở đây là nó sẽ đăng xuất chúng khỏi tất cả các phiên của chúng nếu chúng ở nhiều trình duyệt hoặc có cả máy khách di động.

Đây cũng có thể là một cơ chế tốt để vô hiệu hóa tất cả JWT trong một hệ thống. Một phần của kiểm tra có thể chống lại dấu thời gian toàn cầu của iatthời gian hợp lệ cuối cùng .


1
Tư tưởng tốt! Để giải quyết vấn đề "một thiết bị" là biến điều này thành một tính năng dự phòng chứ không phải là đăng xuất. Lưu trữ một ngày trên hồ sơ người dùng làm mất hiệu lực tất cả các mã thông báo được phát hành trước đó. Một cái gì đó như token_valid_after, hoặc một cái gì đó. Tuyệt vời!
OneHoopyFrood

1
Xin chào @OneHoopyFrood bạn có một mã ví dụ để giúp tôi hiểu ý tưởng theo cách tốt hơn không? Tôi thực sự đánh giá cao sự giúp đỡ của bạn!
alexventuraio

2
Giống như tất cả các giải pháp được đề xuất khác, giải pháp này yêu cầu tra cứu cơ sở dữ liệu, đó là lý do câu hỏi này tồn tại bởi vì tránh việc tra cứu đó là điều quan trọng nhất ở đây! (Hiệu suất, khả năng mở rộng). Trong các trường hợp thông thường, bạn không cần tra cứu DB để có dữ liệu người dùng, bạn đã nhận được nó từ máy khách.
Rob Evans

9

Tôi đến hơi muộn ở đây, nhưng tôi nghĩ rằng tôi có một giải pháp tốt.

Tôi có một cột "last_password_change" trong cơ sở dữ liệu của mình lưu trữ ngày và giờ khi mật khẩu được thay đổi lần cuối. Tôi cũng lưu trữ ngày / thời gian phát hành trong JWT. Khi xác thực mã thông báo, tôi kiểm tra xem mật khẩu đã được thay đổi sau khi mã thông báo được phát hành chưa và liệu đó có phải là mã thông báo bị từ chối ngay cả khi nó chưa hết hạn.


1
Làm thế nào để bạn từ chối mã thông báo? Bạn có thể hiển thị một mã ví dụ ngắn gọn?
alexventuraio

1
if (jwt.issue_date < user.last_pw_change) { /* not valid, redirect to login */}
Vanuan

15
Yêu cầu tra cứu db!
Rob Evans

5

Bạn có thể có trường "last_key_use" trên DB trên tài liệu / bản ghi của người dùng.

Khi người dùng đăng nhập với người dùng và vượt qua, tạo một chuỗi ngẫu nhiên mới, lưu trữ nó trong trường last_key_use và thêm nó vào tải trọng khi ký mã thông báo.

Khi người dùng đăng nhập bằng cách sử dụng mã thông báo, hãy kiểm tra last_key_use trong DB để khớp với mã trong mã thông báo.

Sau đó, khi người dùng thực hiện đăng xuất chẳng hạn hoặc nếu bạn muốn làm mất hiệu lực mã thông báo, chỉ cần thay đổi trường "last_key_use" thành một giá trị ngẫu nhiên khác và mọi kiểm tra tiếp theo sẽ thất bại, do đó buộc người dùng phải đăng nhập với người dùng và chuyển lại.


Đây là giải pháp tôi đã xem xét, nhưng nó có những nhược điểm sau: (1) bạn đang thực hiện tra cứu DB trên mỗi yêu cầu để kiểm tra ngẫu nhiên (vô hiệu hóa lý do sử dụng mã thông báo thay vì phiên) chỉ kiểm tra không liên tục sau khi mã thông báo làm mới đã hết hạn (ngăn người dùng đăng xuất ngay lập tức hoặc phiên bị chấm dứt ngay lập tức); và (2) đăng xuất đăng xuất người dùng từ tất cả các trình duyệt và tất cả các thiết bị (không phải là hành vi dự kiến ​​theo quy ước).
Joe Lapp

Bạn không cần thay đổi khóa khi người dùng đăng xuất, chỉ khi họ thay đổi mật khẩu hoặc - nếu bạn cung cấp - khi họ chọn đăng xuất khỏi tất cả các thiết bị
NickVarcha

3

Giữ một danh sách trong bộ nhớ như thế này

user_id   revoke_tokens_issued_before
-------------------------------------
123       2018-07-02T15:55:33
567       2018-07-01T12:34:21

Nếu mã thông báo của bạn hết hạn sau một tuần thì hãy xóa hoặc bỏ qua các hồ sơ cũ hơn thế. Cũng chỉ giữ bản ghi gần đây nhất của mỗi người dùng. Kích thước của danh sách sẽ phụ thuộc vào thời gian bạn giữ mã thông báo của mình và tần suất người dùng thu hồi mã thông báo của họ. Chỉ sử dụng db khi bảng thay đổi. Tải bảng trong bộ nhớ khi ứng dụng của bạn bắt đầu.


2
Hầu hết các trang web sản xuất chạy trên nhiều máy chủ nên giải pháp này sẽ không hoạt động. Việc thêm Redis hoặc bộ đệm ẩn tương tự tương tự làm phức tạp đáng kể hệ thống và thường mang lại nhiều vấn đề hơn các giải pháp.
dùng2555515

@ user2555515 tất cả các máy chủ có thể được đồng bộ hóa với cơ sở dữ liệu. Đó là lựa chọn của bạn nhấn cơ sở dữ liệu mọi lúc hay không. Bạn có thể nói những gì nó mang lại.
Eduardo

3

------------------------ Chậm trễ cho câu trả lời này nhưng có thể nó sẽ giúp ích cho ai đó ------------- -----------

Từ phía khách hàng , cách dễ nhất là xóa mã thông báo khỏi bộ lưu trữ của trình duyệt.

Nhưng, Điều gì sẽ xảy ra nếu bạn muốn hủy mã thông báo trên máy chủ Node -

Vấn đề với gói JWT là nó không cung cấp bất kỳ phương pháp hay cách thức nào để phá hủy mã thông báo. Bạn có thể sử dụng các phương pháp khác nhau liên quan đến JWT đã được đề cập ở trên. Nhưng ở đây tôi đi với jwt-redis.

Vì vậy, để hủy mã thông báo trên máy chủ, bạn có thể sử dụng gói jwt-redis thay vì JWT

Thư viện này (jwt-redis) lặp lại hoàn toàn toàn bộ chức năng của thư viện jsonwebtoken, với một bổ sung quan trọng. Jwt-redis cho phép bạn lưu trữ nhãn mã thông báo trong redis để xác minh tính hợp lệ. Việc không có nhãn mã thông báo trong redis làm cho mã thông báo không hợp lệ. Để phá hủy mã thông báo trong jwt-redis, có một phương thức hủy

nó hoạt động theo cách này:

1) Cài đặt jwt-redis từ npm

2) Để tạo -

var redis = require('redis');
var JWTR =  require('jwt-redis').default;
var redisClient = redis.createClient();
var jwtr = new JWTR(redisClient);

jwtr.sign(payload, secret)
    .then((token)=>{
            // your code
    })
    .catch((error)=>{
            // error handling
    });

3) Để xác minh -

jwtr.verify(token, secret);

4) Tiêu diệt -

jwtr.destroy(token)

Lưu ý : bạn có thể cung cấp hết hạn trong khi đăng nhập mã thông báo giống như được cung cấp trong JWT.

Có thể điều này sẽ giúp cho ai đó


2

Tại sao không chỉ sử dụng yêu cầu jti (nonce) và lưu trữ trong danh sách dưới dạng trường bản ghi người dùng (phụ thuộc db, nhưng ít nhất một danh sách được phân tách bằng dấu phẩy là tốt)? Không cần tra cứu riêng biệt, vì những người khác đã chỉ ra rằng có lẽ bạn muốn lấy hồ sơ người dùng và bằng cách này bạn có thể có nhiều mã thông báo hợp lệ cho các trường hợp khách khác nhau ("đăng xuất ở mọi nơi" có thể đặt lại danh sách thành trống)


Vâng cái này. Có thể tạo mối quan hệ một-nhiều giữa bảng người dùng và bảng (phiên) mới, vì vậy bạn có thể lưu trữ dữ liệu meta cùng với các khiếu nại jti.
Peter Lada

2
  1. Dành thời gian hết hạn 1 ngày cho các mã thông báo
  2. Duy trì một danh sách đen hàng ngày.
  3. Đặt mã thông báo không hợp lệ / đăng xuất vào danh sách đen

Để xác thực mã thông báo, trước tiên hãy kiểm tra thời gian hết hạn của mã thông báo và sau đó là danh sách đen nếu mã thông báo chưa hết hạn.

Đối với các nhu cầu phiên dài, cần có một cơ chế để kéo dài thời gian hết hạn mã thông báo.


4
đưa mã thông báo vào danh sách đen và tình trạng không quốc tịch của bạn
Kerem Baydoğan

2

Đến bữa tiệc muộn, hai xu của tôi được đưa ra dưới đây sau một số nghiên cứu. Trong quá trình đăng xuất, hãy đảm bảo những điều sau đây đang diễn ra ...

Xóa bộ nhớ / phiên của khách hàng

Cập nhật bảng người dùng ngày đăng nhập lần cuối và ngày đăng xuất thời gian bất cứ khi nào đăng nhập hoặc đăng xuất xảy ra tương ứng. Vì vậy, thời gian ngày đăng nhập luôn phải lớn hơn đăng xuất (Hoặc giữ ngày đăng xuất là null nếu trạng thái hiện tại là đăng nhập và chưa đăng xuất)

Đây là cách đơn giản hơn nhiều so với việc giữ bảng bổ sung của danh sách đen và thanh trừng thường xuyên. Hỗ trợ nhiều thiết bị yêu cầu bảng bổ sung để giữ thông tin đăng nhập, ngày đăng xuất với một số chi tiết bổ sung như hệ điều hành - hoặc chi tiết máy khách.


2

Chuỗi duy nhất cho mỗi người dùng và chuỗi toàn cầu được băm cùng nhau

để phục vụ như phần bí mật JWT cho phép vô hiệu hóa mã thông báo cá nhân và toàn cầu. Tính linh hoạt tối đa với chi phí tra cứu / đọc db trong quá trình xác thực yêu cầu. Cũng dễ dàng để lưu trữ bộ đệm, vì chúng hiếm khi thay đổi.

Đây là một ví dụ:

HEADER:ALGORITHM & TOKEN TYPE

{
  "alg": "HS256",
  "typ": "JWT"
}
PAYLOAD:DATA

{
  "sub": "1234567890",
  "some": "data",
  "iat": 1516239022
}
VERIFY SIGNATURE

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload), 
  HMACSHA256('perUserString'+'globalString')
)

where HMACSHA256 is your local crypto sha256
  nodejs 
    import sha256 from 'crypto-js/sha256';
    sha256(message);

ví dụ: sử dụng, hãy xem https://jwt.io (không chắc họ xử lý các bí mật 256 bit động)


1
Một số chi tiết khác sẽ đủ
giantas

2
@giantas, tôi nghĩ ý nghĩa của Mark là phần chữ ký. Vì vậy, thay vì chỉ sử dụng một phím duy nhất để ký JWT, hãy kết hợp nó với một khóa duy nhất cho mỗi khách hàng. Do đó, nếu bạn muốn vô hiệu hóa tất cả phiên của người dùng, chỉ cần thay đổi khóa cho người dùng đó và nếu bạn vô hiệu hóa tất cả phiên trong hệ thống của mình, chỉ cần thay đổi khóa đơn chung đó.
Tommy Aria Pradana

1

Tôi đã làm theo cách sau:

  1. Tạo một unique hash, và sau đó lưu trữ nó trong redisJWT của bạn . Điều này có thể được gọi là một phiên
    • Chúng tôi cũng sẽ lưu trữ số lượng yêu cầuJWT cụ thể đã thực hiện - Mỗi lần jwt được gửi đến máy chủ, chúng tôi sẽ tăng số nguyên yêu cầu . (đây là tùy chọn)

Vì vậy, khi người dùng đăng nhập, một hàm băm duy nhất được tạo, được lưu trữ trong redis và được đưa vào JWT của bạn .

Khi người dùng cố gắng truy cập điểm cuối được bảo vệ, bạn sẽ lấy hàm băm phiên duy nhất từ JWT của mình , truy vấn lại và xem liệu đó có phải là một kết quả khớp không!

Chúng tôi có thể mở rộng từ điều này và làm cho JWT của chúng tôi an toàn hơn nữa, dưới đây là:

Mỗi X yêu cầu một JWT cụ thể đã thực hiện, chúng tôi tạo một phiên duy nhất mới, lưu trữ nó trong JWT của chúng tôi và sau đó đưa vào danh sách đen phiên trước đó.

Điều này có nghĩa là JWT liên tục thay đổi và ngăn chặn việc JWT bị hack, đánh cắp hoặc một cái gì đó khác.


1
Bạn có thể băm chính mã thông báo và lưu trữ giá trị đó trong redis, thay vì tiêm một hàm băm mới vào mã thông báo.
Frug

Ngoài ra hãy kiểm tra audjtiyêu cầu trong JWT, bạn đang đi đúng hướng.
Peter Lada

1

Nếu bạn muốn có thể thu hồi mã thông báo người dùng, bạn có thể theo dõi tất cả các mã thông báo đã phát hành trên DB của mình và kiểm tra xem chúng có hợp lệ (tồn tại) trên bảng giống như phiên không. Nhược điểm là bạn sẽ đạt DB theo mọi yêu cầu.

Tôi đã không thử nó, nhưng tôi đề xuất phương pháp sau đây để cho phép thu hồi mã thông báo trong khi giữ các lần truy cập DB ở mức tối thiểu -

Để hạ thấp tỷ lệ kiểm tra cơ sở dữ liệu, hãy chia tất cả các mã thông báo JWT đã phát hành thành các nhóm X theo một số liên kết xác định (ví dụ: 10 nhóm cho chữ số đầu tiên của id người dùng).

Mỗi mã thông báo JWT sẽ giữ id nhóm và dấu thời gian được tạo khi tạo mã thông báo. ví dụ,{ "group_id": 1, "timestamp": 1551861473716 }

Máy chủ sẽ giữ tất cả các id nhóm trong bộ nhớ và mỗi nhóm sẽ có dấu thời gian cho biết khi nào là sự kiện đăng xuất cuối cùng của người dùng thuộc nhóm đó. ví dụ,{ "group1": 1551861473714, "group2": 1551861487293, ... }

Các yêu cầu có mã thông báo JWT có dấu thời gian nhóm cũ hơn, sẽ được kiểm tra tính hợp lệ (lần truy cập DB) và nếu hợp lệ, mã thông báo JWT mới có dấu thời gian mới sẽ được phát hành để sử dụng trong tương lai của khách hàng. Nếu dấu thời gian nhóm của mã thông báo mới hơn, chúng tôi tin tưởng JWT (Không có DB nhấn).

Vì thế -

  1. Chúng tôi chỉ xác thực mã thông báo JWT bằng DB nếu mã thông báo có dấu thời gian của nhóm cũ, trong khi các yêu cầu trong tương lai sẽ không được xác thực cho đến khi ai đó trong nhóm người dùng sẽ đăng xuất.
  2. Chúng tôi sử dụng các nhóm để giới hạn số lượng thay đổi dấu thời gian (giả sử có người dùng đăng nhập và đăng xuất như không có ngày mai - sẽ chỉ ảnh hưởng đến số lượng người dùng hạn chế thay vì tất cả mọi người)
  3. Chúng tôi giới hạn số lượng nhóm để giới hạn số lượng dấu thời gian được giữ trong bộ nhớ
  4. Vô hiệu hóa mã thông báo là một cách dễ dàng - chỉ cần xóa nó khỏi bảng phiên và tạo dấu thời gian mới cho nhóm người dùng.

Danh sách tương tự có thể được giữ trong bộ nhớ (ứng dụng cho c #) và nó sẽ loại bỏ nhu cầu nhấn db cho mỗi yêu cầu. Danh sách có thể được tải từ db khi bắt đầu ứng dụng
dvdmn

1

Nếu tùy chọn "đăng xuất từ ​​tất cả các thiết bị" được chấp nhận (trong hầu hết các trường hợp là):

  • Thêm trường phiên bản mã thông báo vào hồ sơ người dùng.
  • Thêm giá trị trong trường này vào các khiếu nại được lưu trữ trong JWT.
  • Tăng phiên bản mỗi khi người dùng đăng xuất.
  • Khi xác thực mã thông báo, hãy so sánh yêu cầu phiên bản của nó với phiên bản được lưu trong hồ sơ người dùng và từ chối nếu nó không giống nhau.

Một chuyến đi db để có được hồ sơ người dùng trong hầu hết các trường hợp là bắt buộc vì vậy điều này không thêm nhiều chi phí cho quá trình xác nhận. Không giống như duy trì một danh sách đen, trong đó tải DB là đáng kể do sự cần thiết phải sử dụng một tham gia hoặc một cuộc gọi riêng biệt, làm sạch các bản ghi cũ và như vậy.


0

Tôi sẽ trả lời Nếu chúng tôi cần cung cấp đăng xuất từ ​​tất cả các tính năng của thiết bị khi chúng tôi đang sử dụng JWT. Cách tiếp cận này sẽ sử dụng tra cứu cơ sở dữ liệu cho từng yêu cầu. Bởi vì chúng ta cần một trạng thái bảo mật bền bỉ ngay cả khi có sự cố máy chủ. Trong bảng người dùng, chúng tôi sẽ có hai cột

  1. LastValidTime (mặc định: thời gian tạo)
  2. Đã đăng nhập (mặc định: đúng)

Bất cứ khi nào có yêu cầu đăng xuất từ ​​người dùng, chúng tôi sẽ cập nhật LastValidTime thành thời gian hiện tại và Đăng nhập thành sai. Nếu có yêu cầu đăng nhập, chúng tôi sẽ không thay đổi LastValidTime nhưng Đăng nhập sẽ được đặt thành đúng.

Khi chúng ta tạo JWT, chúng ta sẽ có thời gian tạo JWT trong tải trọng. Khi chúng tôi ủy quyền cho một dịch vụ, chúng tôi sẽ kiểm tra 3 điều kiện

  1. JWT có hợp lệ không
  2. Thời gian tạo tải trọng JWT có lớn hơn Người dùng LastValidTime không
  3. Là người dùng đã đăng nhập

Hãy xem một kịch bản thực tế.

Người dùng X có hai thiết bị A, B. Anh ấy đăng nhập vào máy chủ của chúng tôi lúc 7 giờ tối bằng thiết bị A và thiết bị B. (giả sử thời gian hết hạn của JWT là 12 giờ). Cả A và B đều có JWT với createdTime: 7pm

Lúc 9 giờ tối, anh ta bị mất thiết bị B. Anh ta ngay lập tức đăng xuất khỏi thiết bị A. Điều đó có nghĩa là Bây giờ cơ sở dữ liệu người dùng X của chúng tôi có LastValidTime là "ThatDate: 9: 00: xx: xxx" và Đăng nhập là "sai".

Vào lúc 9:30, Mr.Thief cố gắng đăng nhập bằng thiết bị B. Chúng tôi sẽ kiểm tra cơ sở dữ liệu ngay cả Đăng nhập là sai vì vậy chúng tôi sẽ không cho phép.

Lúc 10 giờ tối, Mr.X đăng nhập từ thiết bị của mình A. Bây giờ thiết bị A có JWT với thời gian được tạo: 10 giờ tối. Bây giờ cơ sở dữ liệu Logged-In được đặt thành "true"

Lúc 10:30 tối, Mr.Thief cố gắng đăng nhập. Mặc dù Đăng nhập là đúng. LastValidTime là 9 giờ tối trong cơ sở dữ liệu nhưng JWT của B đã tạo thời gian là 7 giờ tối. Vì vậy, anh ta sẽ không được phép truy cập dịch vụ. Vì vậy, sử dụng thiết bị B mà không có mật khẩu, anh ta không thể sử dụng JWT đã được tạo sau khi đăng xuất một thiết bị.


0

Giải pháp IAM như Keycloak (mà tôi đã làm việc trên) cung cấp điểm cuối Thu hồi mã thông báo như

Điểm cuối thu hồi mã thông báo /realms/{realm-name}/protocol/openid-connect/revoke

Nếu bạn chỉ muốn đăng xuất một người dùng (hoặc người dùng), bạn cũng có thể gọi một điểm cuối (điều này chỉ đơn giản là làm mất hiệu lực các Mã thông báo). Một lần nữa, trong trường hợp của Keycloak, Relying Party chỉ cần gọi điểm cuối

/realms/{realm-name}/protocol/openid-connect/logout

Liên kết trong trường hợp nếu bạn muốn tìm hiểu thêm


-1

Điều này có vẻ thực sự khó giải quyết nếu không có tra cứu DB khi xác minh mã thông báo. Cách thay thế tôi có thể nghĩ đến là giữ một danh sách đen các phía máy chủ mã thông báo không hợp lệ; cần được cập nhật trên cơ sở dữ liệu bất cứ khi nào có thay đổi để duy trì các thay đổi trong quá trình khởi động lại, bằng cách làm cho máy chủ kiểm tra cơ sở dữ liệu khi khởi động lại để tải danh sách đen hiện tại.

Nhưng nếu bạn giữ nó trong bộ nhớ máy chủ (một biến toàn cục) thì sẽ không thể mở rộng được trên nhiều máy chủ nếu bạn đang sử dụng nhiều máy chủ, vì vậy trong trường hợp đó bạn có thể giữ nó trên bộ đệm Redis được chia sẻ, nên thiết lập để duy trì dữ liệu ở đâu đó (cơ sở dữ liệu? hệ thống tập tin?) trong trường hợp phải khởi động lại và mỗi khi máy chủ mới xuất hiện, nó phải đăng ký vào bộ đệm Redis.

Thay thế cho một danh sách đen, sử dụng cùng một giải pháp, bạn có thể thực hiện với một hàm băm được lưu trong redis mỗi phiên như câu trả lời khác này chỉ ra (không chắc rằng sẽ hiệu quả hơn với nhiều người dùng đăng nhập).

Nghe có vẻ phức tạp khủng khiếp? nó làm với tôi

Tuyên bố miễn trừ trách nhiệm: Tôi chưa sử dụng Redis.


-1

Nếu bạn đang sử dụng axios hoặc lib yêu cầu http dựa trên lời hứa tương tự, bạn có thể chỉ cần hủy mã thông báo ở mặt trước bên trong .then()phần. Nó sẽ được khởi chạy trong phần phản hồi .then () sau khi người dùng thực thi chức năng này (mã kết quả từ điểm cuối của máy chủ phải ổn, 200). Sau khi người dùng nhấp vào tuyến đường này trong khi tìm kiếm dữ liệu, nếu trường cơ sở dữ liệu user_enabledsai, nó sẽ kích hoạt hủy mã thông báo và người dùng sẽ ngay lập tức bị đăng xuất và dừng truy cập các tuyến / trang được bảo vệ. Chúng tôi không phải chờ mã thông báo hết hạn trong khi người dùng đăng nhập vĩnh viễn.

function searchForData() {   // front-end js function, user searches for the data
    // protected route, token that is sent along http request for verification
    var validToken = 'Bearer ' + whereYouStoredToken; // token stored in the browser 

    // route will trigger destroying token when user clicks and executes this func
    axios.post('/my-data', {headers: {'Authorization': validToken}})
     .then((response) => {
   // If Admin set user_enabled in the db as false, we destroy token in the browser localStorage
       if (response.data.user_enabled === false) {  // user_enabled is field in the db
           window.localStorage.clear();  // we destroy token and other credentials
       }  
    });
     .catch((e) => {
       console.log(e);
    });
}

-3

Tôi chỉ lưu mã thông báo vào bảng người dùng, khi người dùng đăng nhập tôi sẽ cập nhật mã thông báo mới và khi auth bằng với jwt hiện tại của người dùng.

Tôi nghĩ rằng đây không phải là giải pháp tốt nhất nhưng nó hiệu quả với tôi.


2
Tất nhiên nó không phải là tốt nhất! Bất cứ ai có quyền truy cập vào db đều có thể dễ dàng mạo danh bất kỳ người dùng nào.
user2555515

1
@ user2555515 Giải pháp này hoạt động tốt nếu mã thông báo được lưu trữ trên cơ sở dữ liệu được mã hóa, giống như bất kỳ mật khẩu nào được lưu trữ trên cơ sở dữ liệu. Có một sự khác biệt giữa Stateless JWTStateful JWT(rất giống với phiên). Stateful JWTcó thể hưởng lợi từ việc duy trì danh sách trắng mã thông báo.
TheDarkIn1978
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.