Nếu bạn có thể giải mã JWT, làm thế nào để họ an toàn?


302

Nếu tôi nhận được JWT và tôi có thể giải mã được trọng tải, làm thế nào an toàn? Tôi không thể lấy mã thông báo ra khỏi tiêu đề, giải mã và thay đổi thông tin người dùng trong tải trọng và gửi lại với cùng một bí mật được mã hóa chính xác?

Tôi biết họ phải an toàn, nhưng tôi thực sự muốn hiểu về công nghệ. Tôi đang thiếu gì?


2
md5('original messaged' + secret) != md5('changed message' + secret)do đó, nếu ai đó thay đổi tin nhắn, bạn có thể phát hiện ra nó
Pithikos

đúng cho một trường hợp lý tưởng, tuy nhiên, md5 có va chạm. @Pithikos
Yash Kumar Verma

@YashKumarVerma vâng, đó chỉ là để chứng minh ý chính của nó vì mọi người đều biết md5.
Pithikos

1
@ user1955934 nó được mã hóa base64, KHÔNG được mã hóa. Bạn chỉ có thể giải mã nó với bất kỳ bộ giải mã base64 nào.
Pithikos

1
Vì vậy, khách hàng sẽ cần gửi cả mã băm và mã thông báo jwt? và sau này ở phía máy chủ, họ sẽ cố gắng băm mã thông báo jwt bằng cách sử dụng bí mật và so sánh với hàm băm?
dùng1955934

Câu trả lời:


387

JWT có thể được ký, mã hóa hoặc cả hai. Nếu mã thông báo được ký, nhưng không được mã hóa, mọi người đều có thể đọc nội dung của nó, nhưng khi bạn không biết khóa riêng, bạn không thể thay đổi. Nếu không, người nhận sẽ nhận thấy rằng chữ ký sẽ không khớp nữa.

Trả lời nhận xét của bạn: Tôi không chắc liệu tôi có hiểu bình luận của bạn đúng cách hay không. Chỉ cần chắc chắn: bạn có biết và hiểu chữ ký số không? Tôi sẽ chỉ giải thích ngắn gọn một biến thể (HMAC, đối xứng, nhưng có nhiều biến thể khác).

Giả sử Alice muốn gửi JWT cho Bob. Cả hai đều biết một số bí mật được chia sẻ. Mallory không biết bí mật đó, nhưng muốn can thiệp và thay đổi JWT. Để ngăn chặn điều đó, Alice tính toánHash(payload + secret) và nối thêm đây là chữ ký.

Khi nhận được tin nhắn, Bob cũng có thể tính toán Hash(payload + secret)để kiểm tra xem chữ ký có khớp hay không. Tuy nhiên, nếu Mallory thay đổi nội dung nào đó trong nội dung, cô ấy không thể tính được chữ ký phù hợp (sẽ làHash(newContent + secret) ). Cô không biết bí mật và không có cách nào tìm ra nó. Điều này có nghĩa là nếu cô ấy thay đổi điều gì đó, chữ ký sẽ không khớp nữa và Bob sẽ không chấp nhận JWT nữa.

Giả sử, tôi gửi tin nhắn cho người khác {"id":1}và ký tên Hash(content + secret). (+ chỉ là ghép ở đây). Tôi sử dụng hàm Hash SHA256 và chữ ký tôi nhận được là : 330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c. Giờ đến lượt bạn: đóng vai trò Mallory và cố gắng ký tin nhắn {"id":2}. Bạn không thể bởi vì bạn không biết tôi đã sử dụng bí mật nào. Nếu tôi cho rằng người nhận biết bí mật, anh ta CÓ THỂ tính toán chữ ký của bất kỳ tin nhắn nào và kiểm tra xem nó có đúng không.


8
Vậy chữ ký có bị thay đổi khi tải trọng thay đổi? Tôi đã có ấn tượng rằng mã thông báo có định dạng [tiêu đề]. [Tải trọng]. [Chữ ký] là chữ ký được tính theo sự kết hợp giữa tải trọng và bí mật? Nếu đó là trường hợp, một tải trọng với một id khác sẽ giống nhau cho bí mật đó? Giống như nếu dữ liệu là {id: 1} và được sử dụng để tính phần chữ ký của mã thông báo, điều đó có nghĩa là {id: 2} sẽ hợp lệ cho người dùng 2 và vì vậy người dùng 1 có thể thay đổi id thành 2 và mã thông báo sẽ giống nhau?
PixMach

7
Tôi đã cho bạn một ví dụ để làm cho mọi thứ vẫn rõ ràng hơn, nhưng tôi sẽ không giải thích cho bạn toàn bộ khái niệm về chữ ký số và HMAC cho bạn. Xin vui lòng đọc lên về những điều đó, có rất nhiều tài liệu giải thích nó.
Misch

11
Ồ tôi đã hiểu rồi. Tôi không biết tại sao tôi lại thiếu ý tưởng rằng hàm băm bí mật sẽ không chính xác khi bạn thay đổi tải trọng vì hàm băm bí mật sẽ phải được tính toán lại. Vì một số lý do tôi vẫn nghĩ rằng nó độc lập. Đó là chút cuối cùng thực sự khoan nó về nhà cho tôi. Cảm ơn đã dẫn tôi đi qua nó.
PixMach

30
Tôi có một câu hỏi liên quan. Điều gì ngăn cản ai đó mạo danh Alice với JWT được sao chép?
Không có

25
Nếu ai đó có JWT, họ có thể mạo danh Alice. Vì vậy, bạn cần phải cẩn thận cách bạn lưu trữ và gửi nó. Bạn cũng nên đặt thời hạn sử dụng cho nó trong tải trọng. Theo cách đó, nếu ai đó đánh cắp JWT, họ có khung thời gian giới hạn để sử dụng nó. Hãy xem Stormpath.com/blog/ Kẻ
Geraint Anderson

134

Bạn có thể đi đến jwt.io , dán mã thông báo của bạn và đọc nội dung. Đây là chói tai cho rất nhiều người ban đầu.

Câu trả lời ngắn gọn là JWT không quan tâm đến việc mã hóa. Nó quan tâm đến việc xác nhận. Điều đó có nghĩa là, nó luôn có thể nhận được câu trả lời cho "Có nội dung của mã thông báo này bị thao túng" không? Điều này có nghĩa là việc người dùng thao tác mã thông báo JWT là vô ích vì máy chủ sẽ biết và bỏ qua mã thông báo. Máy chủ thêm chữ ký dựa trên tải trọng khi phát hành mã thông báo cho khách hàng. Sau đó, nó xác minh tải trọng và chữ ký phù hợp.

Câu hỏi logic là động lực cho việc không liên quan đến chính nó với nội dung được mã hóa là gì?

  1. Lý do đơn giản nhất là vì nó cho rằng đây là một vấn đề được giải quyết cho hầu hết các phần. Ví dụ: nếu giao dịch với một khách hàng như trình duyệt web, bạn có thể lưu trữ mã thông báo JWT trong một cookie secure(không được truyền qua HTTP, chỉ qua HTTPS) và httpOnly(không thể đọc bằng Javascript) và nói chuyện với máy chủ qua một kênh được mã hóa (HTTPS). Khi bạn biết bạn có một kênh an toàn giữa máy chủ và máy khách, bạn có thể trao đổi JWT một cách an toàn hoặc bất cứ điều gì khác mà bạn muốn.

  2. Điều này giữ cho mọi thứ đơn giản. Việc triển khai đơn giản giúp việc áp dụng dễ dàng hơn nhưng nó cũng cho phép mỗi lớp thực hiện những gì nó làm tốt nhất (để HTTPS xử lý mã hóa).

  3. JWT không có nghĩa là lưu trữ dữ liệu nhạy cảm. Khi máy chủ nhận được mã thông báo JWT và xác thực nó, bạn có thể tự do tra cứu ID người dùng trong cơ sở dữ liệu của mình để biết thêm thông tin cho người dùng đó (như quyền, địa chỉ bưu chính, v.v.). Điều này giữ cho JWT có kích thước nhỏ và tránh rò rỉ thông tin do vô ý vì mọi người đều biết không giữ dữ liệu nhạy cảm trong JWT.

Nó không quá khác biệt so với cách thức hoạt động của cookie. Cookies thường chứa tải trọng không được mã hóa. Nếu bạn đang sử dụng HTTPS thì mọi thứ đều tốt. Nếu bạn không nên tự mã hóa cookie nhạy cảm. Không làm như vậy sẽ có nghĩa là một cuộc tấn công trung gian là có thể - một máy chủ proxy hoặc ISP đọc cookie và sau đó phát lại chúng sau khi giả vờ là bạn. Vì những lý do tương tự, JWT phải luôn được trao đổi qua một lớp bảo mật như HTTPS.


4
Tâm trí nó! JWT phải luôn được trao đổi qua một lớp bảo mật như HTTPS
codemirror

Nhưng nếu JWT chỉ an toàn trên HTTPS, tại sao không gửi trọng tải? POST -> tên người dùng, mật khẩu. Nó vẫn được mã hóa phải không?
GeekPeek

@GeekPeek cho rằng bạn nên đọc những điều cơ bản về JWT nhưng Phiên Auth như bạn đề cập thường là tất cả những gì bạn cần. JWT cung cấp một số lợi ích khác nhưng làm cho một số sự đánh đổi webskotte.com/webdev/2019/10/22/iêu
aleemb

17

Các nội dung trong mã thông báo web json (JWT) vốn không an toàn, nhưng có một tính năng tích hợp để xác minh tính xác thực của mã thông báo. Một JWT là ba băm cách nhau bởi dấu chấm. Thứ ba là chữ ký. Trong hệ thống khóa công khai / riêng, nhà phát hành ký chữ ký mã thông báo bằng khóa riêng chỉ có thể được xác minh bằng khóa chung tương ứng.

Điều quan trọng là phải hiểu sự khác biệt giữa nhà phát hành và người xác minh. Người nhận mã thông báo có trách nhiệm xác minh nó.

Có hai bước quan trọng trong việc sử dụng JWT một cách an toàn trong ứng dụng web: 1) gửi chúng qua kênh được mã hóa và 2) xác minh chữ ký ngay khi nhận được. Bản chất bất đối xứng của mật mã khóa công khai giúp xác minh chữ ký JWT có thể. Khóa công khai xác minh JWT đã được ký bằng khóa riêng phù hợp. Không có tổ hợp khóa nào khác có thể thực hiện xác minh này, do đó ngăn chặn các nỗ lực mạo danh. Thực hiện theo hai bước này và chúng tôi có thể đảm bảo chắc chắn về mặt toán học tính xác thực của JWT.

Đọc thêm: Làm thế nào để khóa công khai xác minh chữ ký?


2

Chúng ta hãy từ chối ngay từ đầu:

JWT là một cách tiếp cận rất hiện đại, đơn giản và an toàn mở rộng cho Json Web Tokens. Json Web Tokens là một giải pháp không trạng thái để xác thực. Vì vậy, không cần lưu trữ bất kỳ trạng thái phiên nào trên máy chủ, điều này tất nhiên là hoàn hảo cho các API nghỉ ngơi. Các API đầy đủ phải luôn luôn không trạng thái và cách thay thế được sử dụng rộng rãi nhất để xác thực với JWT là chỉ lưu trữ trạng thái đăng nhập của người dùng trên máy chủ bằng các phiên. Nhưng tất nhiên sau đó không tuân theo nguyên tắc nói rằng các API nghỉ ngơi nên không trạng thái và đó là lý do tại sao các giải pháp như JWT trở nên phổ biến và hiệu quả.

Vì vậy, bây giờ hãy biết cách xác thực thực sự hoạt động với Json Web Tokens. Giả sử chúng tôi đã có một người dùng đã đăng ký trong cơ sở dữ liệu của chúng tôi. Vì vậy, ứng dụng khách của người dùng bắt đầu bằng cách tạo một yêu cầu bài đăng với tên người dùng và mật khẩu, sau đó ứng dụng sẽ kiểm tra xem người dùng có tồn tại không và nếu mật khẩu là chính xác, thì ứng dụng sẽ tạo Mã thông báo web Json duy nhất cho người dùng đó.

Mã thông báo được tạo bằng chuỗi bí mật được lưu trữ trên máy chủ . Tiếp theo, máy chủ sau đó gửi JWT đó trở lại máy khách sẽ lưu nó trong cookie hoặc trong bộ nhớ cục bộ. nhập mô tả hình ảnh ở đây

Giống như thế này, người dùng được xác thực và về cơ bản đăng nhập vào ứng dụng của chúng tôi mà không để lại bất kỳ trạng thái nào trên máy chủ.

Vì vậy, máy chủ thực tế không biết người dùng nào thực sự đăng nhập, nhưng tất nhiên, người dùng biết rằng anh ta đã đăng nhập vì anh ta có Mã thông báo Json Web hợp lệ, giống như hộ chiếu để truy cập các phần được bảo vệ của ứng dụng.

Vì vậy, một lần nữa, chỉ để đảm bảo bạn có ý tưởng. Một người dùng đã đăng nhập ngay khi nhận lại Mã thông báo Json Web hợp lệ duy nhất của mình mà không được lưu ở bất kỳ đâu trên máy chủ. Và do đó, quá trình này là hoàn toàn không quốc tịch.

Sau đó, mỗi lần người dùng muốn truy cập một tuyến được bảo vệ như dữ liệu hồ sơ người dùng của mình. Anh ta gửi Mã thông báo Json Web của mình cùng với một yêu cầu, vì vậy nó giống như hiển thị hộ chiếu của anh ta để có quyền truy cập vào tuyến đường đó.

Khi yêu cầu đến máy chủ, ứng dụng của chúng tôi sẽ xác minh xem Json Web Token có thực sự hợp lệ hay không và nếu người dùng thực sự là người mà anh ta nói, thì dữ liệu được yêu cầu sẽ được gửi đến máy khách và nếu không, thì sẽ là một lỗi cho người dùng biết rằng anh ta không được phép truy cập tài nguyên đó. nhập mô tả hình ảnh ở đây

Tất cả các giao tiếp này phải diễn ra qua https, Vì vậy, mã hóa http được bảo mật an toàn để ngăn chặn mọi người có thể truy cập vào mật khẩu hoặc Mã thông báo web Json. Chỉ sau đó chúng tôi có một hệ thống thực sự an toàn.

nhập mô tả hình ảnh ở đây

Vì vậy, Mã thông báo web Json trông giống như một phần bên trái của ảnh chụp màn hình này được lấy từ trình gỡ lỗi JWT tại jwt.ioSo, về cơ bản, đó là một chuỗi mã hóa gồm ba phần. Tiêu đề, tải trọng và chữ ký Bây giờ tiêu đề chỉ là một số siêu dữ liệu về chính mã thông báo và tải trọng là dữ liệu mà chúng ta có thể mã hóa vào mã thông báo, bất kỳ dữ liệu nào chúng ta thực sự muốn. Vì vậy, càng nhiều dữ liệu chúng tôi muốn mã hóa ở đây thì JWT càng lớn. Dù sao, hai phần này chỉ là văn bản đơn giản sẽ được mã hóa, nhưng không được mã hóa.

Vì vậy, bất cứ ai cũng sẽ có thể giải mã chúng và đọc chúng , chúng tôi không thể lưu trữ bất kỳ dữ liệu nhạy cảm nào ở đây. Nhưng đó không phải là một vấn đề gì cả vì trong phần thứ ba, vì vậy trong chữ ký, là nơi mọi thứ thực sự trở nên thú vị. Chữ ký được tạo bằng tiêu đề, tải trọng và bí mật được lưu trên máy chủ.

Và toàn bộ quá trình này sau đó được gọi là ký mã thông báo web Json . Thuật toán ký có tiêu đề, tải trọng và bí mật để tạo chữ ký duy nhất. Vì vậy, chỉ có dữ liệu này cộng với bí mật có thể tạo chữ ký này, được chứ? Sau đó, cùng với tiêu đề và tải trọng, các chữ ký này tạo thành JWT, sau đó được gửi đến máy khách. nhập mô tả hình ảnh ở đây

Khi máy chủ nhận được JWT để cấp quyền truy cập vào tuyến được bảo vệ, nó cần xác minh nó để xác định xem người dùng có thực sự là người mà anh ta tuyên bố là. Nói cách khác, nó sẽ xác minh nếu không ai thay đổi tiêu đề và dữ liệu tải trọng của mã thông báo. Vì vậy, một lần nữa, bước xác minh này sẽ kiểm tra xem không có bên thứ ba nào thực sự thay đổi tiêu đề hoặc tải trọng của Mã thông báo web Json.

Vì vậy, làm thế nào để xác minh này thực sự hoạt động? Vâng, nó thực sự khá đơn giản. Khi JWT được nhận, xác minh sẽ lấy tiêu đề và tải trọng của nó và cùng với bí mật vẫn được lưu trên máy chủ, về cơ bản tạo chữ ký kiểm tra.

Nhưng chữ ký ban đầu được tạo khi JWT lần đầu tiên được tạo vẫn nằm trong mã thông báo, phải không? Và đó là chìa khóa để xác minh này. Bởi vì bây giờ tất cả những gì chúng ta phải làm là so sánh chữ ký kiểm tra với chữ ký gốc. Và nếu chữ ký kiểm tra giống với chữ ký gốc, thì điều đó có nghĩa là tải trọng và tiêu đề chưa được sửa đổi. nhập mô tả hình ảnh ở đây

Bởi vì nếu chúng đã được sửa đổi, thì chữ ký kiểm tra sẽ phải khác. Do đó, trong trường hợp không có sự thay đổi dữ liệu, chúng tôi có thể xác thực người dùng. Và tất nhiên, nếu hai chữ ký thực sự khác nhau, thì điều đó có nghĩa là ai đó đã can thiệp vào dữ liệu. Thông thường bằng cách cố gắng thay đổi tải trọng. Nhưng bên thứ ba đó thao túng tải trọng tất nhiên không có quyền truy cập vào bí mật, vì vậy họ không thể ký JWT. Vì vậy, chữ ký gốc sẽ không bao giờ tương ứng với dữ liệu bị thao túng. Và do đó, việc xác minh sẽ luôn thất bại trong trường hợp này. Và đó là chìa khóa để làm cho toàn bộ hệ thống này hoạt động. Đó là phép thuật làm cho JWT trở nên đơn giản, nhưng cũng vô cùng mạnh mẽ.


1

Chỉ privateKey của JWT, trên máy chủ của bạn sẽ giải mã JWT được mã hóa. Những người biết privateKey sẽ có thể giải mã JWT được mã hóa.

Ẩn privateKey ở một vị trí an toàn trong máy chủ của bạn và không bao giờ nói cho ai biết privateKey.


1
JWT không phải lúc nào cũng được mã hóa. Chúng có thể được ký, mã hóa, ký sau đó được mã hóa hoặc mã hóa sau đó được ký.
csauve

0

Đối với những người không đủ khả năng truy vấn cơ sở dữ liệu đắt tiền như tôi, một tùy chọn để giữ dữ liệu nhạy cảm (Quyền riêng tư của người dùng, v.v.) là, khi tạo JWT, bạn có thể mã hóa dữ liệu này và đính kèm mã thông báo JWT. (Giữ khóa mã hóa trong phần phụ trợ)

Khi bạn muốn đọc thông tin nhạy cảm, bạn có thể gửi mã thông báo JWT đến phần phụ trợ và giải mã nó và lấy lại thông tin. Theo cách này, bạn không phải thực hiện tra cứu DB hoặc để thông tin nhạy cảm ở phía trước thông qua mã thông báo JWT


-1

Tôi sẽ đề nghị xem xét JWE bằng các thuật toán đặc biệt không có trong jwt.io để giải mã

Liên kết tham khảo: https://www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

Câu trả lời này có thể quá muộn hoặc bạn có thể đã tìm ra cách, nhưng vẫn vậy, tôi cảm thấy nó cũng hữu ích cho bạn và những người khác.

Một ví dụ đơn giản mà tôi đã tạo: https://github.com/hansiemithun/jwe-example

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.