Bài viết Đặc tả OpenID Connect Core 1.0 xác định chức năng lõi OpenID Connect: xác thực ủy quyền cho người sử dụng ứng dụng được xây dựng trên OAuth 2.0 và sử dụng “phản hồi” (khái niệm này sẽ được nói rõ ở phần sau) để truyền đạt thông tin về người dùng cuối. Để có một nội dung khái quát nhưng đầy đủ, bài viết sẽ được chia làm 2 phần xuyên suốt theo tiến trình của giao thức OpenID (dựa theo tài liệu về tiêu chuẩn Open ID Connect Core 1.0 thuộc quỹ OpenID (OIDF)).
Tiêu chuẩn được viết bởi tổ chức phi lợi nhuận OpenID Foundation do các tác giả thuộc Google, Microsoft và một số công ty công nghệ cùng xây dựng. Tiêu chuẩn này dựa trên khung ủy quyền OAuth 2.0 và sau khi chỉnh sửa nâng cấp hơn 15 lần đã hoàn thành lần cuối vào ngày 04 tháng 12 năm 2014. Từ thời điểm hoàn thiện đến nay được 6 năm nhưng tài liệu này vẫn là tiêu chuẩn đặc tả hoàn chỉnh và cơ sở xây dựng nhiều khung và cái tiêu chuẩn mới.
OpenID Connect Core 1.0 sớm nhận được công nhận và sử dụng của công đồng mạng với hơn 1 tỷ tài khoản OpenID được thiết lập song song với 50,000 webiste sử dụng phương thức này để đăng nhập. Một vài tổ chức lớn cho phép hoặc phát hành các tài khoản thuộc OpenID hoặc tái sử dụng ví dụ như Google, Facebook, Yahoo! Microsoft, AOL, MySpace, ….. Điều này khẳng định tính hữu hiệu và cần thiết của tiêu chuẩn với các nền tảng trên môi trường mạng.
Trong bài viết, tiêu chuẩn Open Connect Core 1.0 sẽ được viết tắt là Open CC 1.0.
Cấu trúc tiêu chuẩn
Tiêu chuẩn sẽ được viết thành 2 phần như được giới thiệu trước.
Phần một chia sẻ từ tổng quan của tiêu chuẩn đến các khái niệm cơ bản cấu thành chính trong tiêu chuẩn.
Phần hai sẽ hoàn thiện các khái niệm còn lại hỗ trợ cho tiêu chuẩn. Nhưng những khái niệm này cũng hoàn toàn cần thiết để thiết lập yếu tố bảo mật và kết nối của tiêu chuẩn.
Nội dung chi tiết
1. Khái niệm cơ bản
OpenID Connect 1.0 là lớp nhận dạng đơn giản trên giao thức OAuth 2.0 [RFC6749]. Trong đó, OAuth 2.0 là giao thức được viết tắt của “Open” với “Authentication” là xác thực người dùng thực hoặc “Authorization” là người dùng ủy quyền cho ứng dụng truy cập vào dữ liệu người dùng hay tài nguyên trên máy chủ thuộc sở hữu người dùng. Nó cho phép máy chủ xác minh danh tính của Người dùng cuối dựa trên xác thực được thực hiện bởi một máy chủ ủy quyền, cũng như để có được thông tin hồ sơ cơ bản về người dùng cuối theo cách tương thích và giống như REST (Phương thức tạo API với nguyên lý tổ chức nhất định).
Như nền tảng, các thông số kỹ thuật của OAuth 2.0 Authorization Framework [RFC6749] và OAuth 2.0 Bearer Token Usage [RFC6750] cung cấp một khung chung cho các ứng dụng của bên thứ ba để có được và sử dụng quyền truy cập hạn chế vào tài nguyên HTTP. Họ xác định các cơ chế để có được và sử dụng Mã thông báo truy cập để truy cập tài nguyên nhưng không xác định các phương thức tiêu chuẩn để cung cấp thông tin nhận dạng. Đáng chú ý, không có hồ sơ OAuth 2.0, không thể cung cấp thông tin về xác thực của người dùng cuối. OpenID Connect thực hiện xác thực như một phần mở rộng cho quy trình ủy quyền OAuth 2.0. Thông tin về xác thực được thực hiện được trả về trong JSON Web Token (JWT) [JWT] được gọi là Mã thông báo ID.
OpenID provider (OP) là những hệ thống sử dụng OAuth protocol có chức năng xác định danh tính của một người dùng.
Relying Party (RP) hay Client được biết là ứng dụng sử dụng danh tính được cung cấp bởi OpenID provider.
End-User hay người dùng cuối là người tham gia vào quá trình xác thực, người này cấp quyền cho RP được làm một số vai trò của mình (ví dụ: khai báo thông tin danh tính, tự động đăng nhập, v.v.)
Claim là khối thông tin về một thực thể nào đó. Khái niệm này sẽ được giải thích rõ hơn trong phần sau.
Issuer là thực thể phát hành một Claim.
Subject Identifier là danh tính của người dùng được Issuer biết đến, duy nhất và không bao giờ gán lại, có thể coi là ID của user trong OP.
ID token là mã thông báo chứa giá trị Claim về một sự kiện xác thực nào đó đang diễn ra.
2. Tổng quan về tiêu chuẩn.
Hình 1 : Tổng quan giao thức OpenID Connect core 1.0
Giao thức OpenID Connect, tóm tắt, thực hiện theo các bước sau:
Bước 1: RP (Máy khách) gửi yêu cầu đến Nhà cung cấp OpenID (OP).
Bước 2: OP xác thực Người dùng cuối và được ủy quyền.
Bước 3: OP trả lời bằng Mã thông báo ID (ID Token) và thường là Mã thông báo truy cập.
Bước 4: RP có thể gửi yêu cầu với Mã thông báo truy cập đến Điểm cuối UserInfo.
Bước 5: Điểm cuối UserInfo trả về Phản hồi về Người dùng cuối.
Trong tiêu chuẩn OAuth 2.0, ứng dụng hay địa chỉ trang web phải thuê hay mua một máy chủ để xác thực thông tin người dùng. Trên nền tảng đó, tiêu chuẩn OpenID cho phép được xác thực người dùng thông qua một máy chủ đã tồn tại thông tin người dùng, đồng thời đủ uy tín để xác thực thông tin cho người dùng, điều này giảm thiểu chi phí, giảm thiểu dữ liệu trùng lặp và quan trọng tính kết nối dữ liệu.
Hình 2 : Giao thức OAuth 2.0
3. Mã thông báo ID (ID token)
Tiện ích mở rộng chính mà OpenID Connect tạo ra trên OAuth 2.0 để cho phép người dùng cuối được xác thực là cấu trúc dữ liệu ID Token. Mã thông báo ID là mã thông báo bảo mật có chứa phản hồi về xác thực người dùng cuối bởi máy chủ ủy quyền khi sử dụng máy khách và các phản hồi được yêu cầu khác. Mã thông báo ID được biểu diễn dưới dạng JSON Web Token [JWT].
Mã thông báo ID có thể chứa các yêu cầu khác. Bất kỳ yêu cầu nào khác sử dụng và không hiểu thì không chấp nhận. Mã này phải được ký bằng JWShoặc có thể tùy chọn ký và mã hóa bằng JWS và JWE nhằm đảm bảo tính xác thực, toàn vẹn, bảo mật. Mã thông báo ID không được sử dụng “none” làm giá trị “alg” trừ khi loại phản hồi được sử dụng trả về không có mã thông báo ID từ Điểm cuối ủy quyền (chẳng hạn như khi sử dụng Luồng mã ủy quyền) và khách hàng yêu cầu rõ ràng việc sử dụng “none” tại thời điểm đăng ký.
Các khối thông tin về thực thể sau được sử dụng trong Mã thông báo ID cho tất cả các luồng OAuth 2.0 được sử dụng bởi OpenID Connect:
iss
Giá trị này trong mã thông báo ID là CẦN THIẾT và định danh nhà phát hành cho phản hồi từ phía phản hồi. Các “iss” giá trị là một URL linh hoạt, trường hợp sử dụng “https” có chứa chương trình, lưu trữ, tùy chọn số cổng, các thành phần đường dẫn và không nhận thắc mắc về giá trị.
sub
Giá trị này trong mã thông báo ID là CẦN THIẾT và định danh chủ thể. Một mã định danh duy nhất tại máy chủ và không bao giờ được gán lại trong các giá trị mới được sử dụng cho ứng dụng. Ví dụ: 24400320 hoặc vutrJUqsvl6qs7A4. Nó KHÔNG ĐƯỢC vượt quá 255 ký tự ASCII. Các “sub” giá trị là một trường hợp chuỗi linh hoạt về giá trị.
aud
Giá trị này trong mã thông báo ID là CẦN THIẾT và đối tượng mà Mã thông báo ID này được dành cho PHẢI chứa OAuth 2.0 “client_id” của bên tin cấy “Relying Party” làm giá trị đối tượng. Nó cũng có thể chứa định danh cho các đối tượng khác. Trong trường hợp chung, giá trị “aud” là một chuỗi các chuỗi phân biệt chữ hoa chữ thường.
exp
Giá trị này trong mã thông báo ID là CẦN THIẾT và là thời gian hết hạn mà sau đó mã thông báo ID KHÔNG được chấp nhận để xử lý. Việc xử lý tham số này yêu cầu ngày / giờ hiện tại PHẢI trước ngày / giờ hết hạn được liệt kê trong giá trị. Những người triển khai CÓ THỂ cung cấp cho một số khoảng thời gian nhỏ, thường không quá vài phút, để tính đến độ lệch của đồng hồ. Giá trị của nó là một số JSON biểu thị số giây từ 1970-01-01T0: 0: 0Z như được đo bằng UTC cho đến ngày / giờ (văn bản RFC3339 [RFC3339] sẽ nêu chi tiết về ngày / giờ nói chung và UTC nói riêng). Giá trị này chứa OAuth 2.0 “client_id” của bên tin cậy làm giá trị đối tượng. Nó cũng có thể chứa định danh cho các đối tượng khác.
iat
Giá trị này trong mã thông báo ID là CẦN THIẾT và là thời gian mà JWT được ban hành. Giá trị của nó là một số JSON biểu thị số giây từ 1970-01-01T0: 0: 0Z như được đo bằng UTC cho đến ngày / giờ
auth_time
Giá trị này trong mã thông báo ID làthời gian khi xác thực Người dùng cuối xảy ra. Giá trị của nó là một số JSON biểu thị số giây từ 1970-01-01T0: 0: 0Z như được đo bằng UTC cho đến ngày / giờ. Khi yêu cầu “max_age” (gán thời gian tối đa trước khi tệp tin hay yêu cầu hết hạn) được thực hiện hoặc khi auth_time được yêu cầu như một yêu cầu thiết yếu, thì yêu cầu này phải là BẮT BUỘC; trong một số trường hợp khác còn lại thì nó KHÔNG BẮT BUỘC.
nonce
Giá trị này là chuỗi được sử dụng để liên kết phiên ứng dụng với mã thông báo ID và để giảm thiểu các cuộc tấn công phát lại. Giá trị này được chuyển qua không được sửa đổi từ yêu cầu xác thực đến mã thông báo ID. Nếu có mặt trong Token ID, máy chủ phải xác minh rằng các nonce yêu cầu là giá trị tương đương với giá trị của các nonce tham số được gửi trong yêu cầu xác thực (đơn giản là hai phía máy chủ đồng thời phản hồi “nonce”). Nếu có mặt trong yêu cầu xác thực hay ủy quyền người dùng từ máy chủ thì PHẢI bao gồm một giá trị nonce trong Token ID. Máy chủ ủy quyền NÊN giữ nguyên giá trị nonce được sử dụng và không nên xủ lý giá trị đó. Giá trị “nonce” là một chuỗi phân biệt viết hoa và viết thường.
acr
Giá trị này trong mã thông báo ID là KHÔNG BẮT BUỘC. Giá trị này là giá trị tham chiếu lớp bối cảnh xác thực hay hiểu rằng trong máy chủ đã có một vùng nhớ được tiếp nhận sẽ được tồn tại bao lâu. Giá trị “0” cho biết xác thực người dùng cuối không đáp ứng các yêu cầu của ISO29115 [ISO29115] cấp 1. Một URL cần thiết theo [RFC6711] để đăng ký tên NÊN được sử dụng như giá trị “acr”; tên đã đăng ký PHẢI KHÔNG được sử dụng với nghĩa khác với tên được đăng ký. Các bên sử dụng giá trị này sẽ cần phải đồng ý về ý nghĩa của các giá trị được sử dụng, có thể là cụ thể theo ngữ cảnh. Các “acr” giá trị là một chuỗi ký tự phân biệt viết hoa và viết thường.
amr
Giá trị này trong mã thông báo ID là KHÔNG BẮT BUỘC và có nhiệm vụ xác thực tài liệu tham khảo. Mảng JSON của các chuỗi giá trị này là định danh cho các phương thức xác thực được sử dụng trong xác thực. Chẳng hạn, các giá trị có thể chỉ ra rằng cả hai phương thức xác thực mật khẩu và OTP đã được sử dụng. Định nghĩa về giá trị cụ thể được sử dụng trong amr yêu cầu bồi thường là vượt quá phạm vi của đặc tả này. Các bên sử dụng khiếu nại này sẽ cần phải đồng ý về ý nghĩa của các giá trị được sử dụng, có thể là cụ thể theo ngữ cảnh. Các amr giá trị là một mảng ký tự phân biệt chữ viết hoa và chữ viết thường.
azp
Giá trị này trong mã thông báo ID là KHÔNG BẮT BUỘC. Giá trị này thuộc về bên được ủy quyền – bên mà Mã thông báo ID được phát hành. Nếu có giá trị “azp” thì nó PHẢI chứa ID ứng dụng OAuth 2.0 của bên đó. Khối thông tin này chỉ cần thiết khi Mã thông báo ID có một giá trị đối tượng duy nhất và đối tượng đó khác với bên được ủy quyền. Các “azp” giá trị là một chuỗi phân biệt từ viết hoa và viết thường có chứa một giá trị String trong URI.
Hình 3 : Tiến trình xác thực
Kết quả xác thực được trả về trong Mã thông báo ID. Nó có phản hồi thể hiện thông tin như Người phát hành, Mã định danh chủ đề, khi hết hạn xác thực, v.v.
Xác thực có thể đi theo một trong ba đường dẫn: Luồng mã ủy quyền ( response_type = code ), Luồng ẩn ( answer_type = “id_token token” hoặc response_type = “id_token” ) hoặc Luồng kết hợp (sử dụng các giá trị Loại phản hồi khác được xác định trong Mã hóa loại phản hồi khác nhau được xác định trong OAuth 2.0 Multiple Response Type Encoding Practices [OAuth.Responses]). Các luồng xác định cách Mã thông báo ID và Mã thông báo truy cập được trả về máy chủ RP.
Các đặc điểm của ba luồng được tóm tắt trong bảng không quy tắc sau đây. Bảng này nhằm cung cấp một số hướng dẫn về việc chọn luồng nào trong bối cảnh cụ thể.
Thuộc tính
Luồng mã ủy quyền
Luồng ẩn
Luồng kết hợp
Tất cả mã thông báo được trả thẳng từ endpoint.
Không
Có
Không
Tất cả các mã thông báo được trả về từ mã thông báo của endpoint.
Có
Không
Không
Mã thông báo không được tiết lộ cho người dùng ẩn danh
Có
Không
Không
Máy chủ có thể được xác thực
Có
Không
Có
Có khả thi trong việc tạo mới mã thông báo
Có
Không
Có
Chỉ cần một lần xác thực có thể hoàn thành
Không
Có
Không
Hầu như có sự liên lạc giữa các máy chủ.
Có
Không
Không chắc chắn
Dòng sử dụng được xác định bởi “response_type” giá trị chứa trong các yêu cầu ủy quyền. Những giá trị“response_type” lựa chọn theo luồng sau:
Giá trị “response_type”
Luồng
code
Luồng mã ủy quyền
id_token
Luồng ẩn
id_token_token
Luồng ẩn
Code_id_token
Luồng kết hợp
Code_token
Luồng kết hợp
code id_token token
Luồng kết hợp
Tất cả trừ giá trị mã luồng phản hồi, được xác định bởi OAuth 2.0 [RFC6749], được xác định trong đặc tả OAuth 2.0 Multiple Response Type Encoding Practies [OAuth.Responses].
Lưu ý: Mặc dù OAuth 2.0 cũng xác định giá trị loại mã phản hồi thông báo cho Luồng ẩn, OpenID Connect không sử dụng Loại phản hồi này, vì sẽ không có mã thông báo ID nào được trả về.
5. Quá trình xác thực đối với từng luồng mã:
Các bước của quá trình xác thực luôn có 6 bước cơ bản:
Bước 1: Máy chủ RP chuẩn bị một yêu cầu xác thực chứa các tham số yêu cầu.
Bước 2: Máy chủ RP gửi yêu cầu đến Máy chủ ủy quyền.
Bước 3: Máy chủ ủy quyền OP xác thực người dùng cuối.
Bước 4: Máy chủ ủy quyền có được sự đồng ý/ ủy quyền của người dùng cuối.
Bước 5: Quá trình xử lý dựa theo 3 luồng mã.
Bước 6: Máy chủ RP xác thực mã thông báo ID và truy xuất mã định danh của người dùng.
Sau 6 bước này, phản hồi xác thực là thông báo phản hồi ủy quyền OAuth 2.0 được trả về từ đích truyền tin của máy chủ ủy quyền để trả lời tin nhắn yêu cầu từ phía máy chủ RP. Nếu có lỗi hoặc nếu người dùng từ chối yêu cầu xác thực hoặc xác thực không thành công, máy chủ ủy quyền thông báo máy chủ RP bằng cách sử dụng các tham số phản hồi lỗi của OAuth 2.0 [RFC6749].
Tại bước 5, đối với mỗi luồng mã quá trình xác thực có các cách xác thực khác nhau.
a. Xác thực thông qua “Luồng mã ủy quyền”
Khi sử dụng “Luồng mã ủy quyền” tất cả các mã thông báo được trả về từ mã thông báo của đích trong một kênh truyền tin (token endpoint). Luồng mã này trả một mã ủy quyền cho máy chủ RP, sau đó mã ủy quyền có thể chuyển đổi thành một mã thông báo ID và một mã thông báo truy cập trực tiếp. Điều này có tác dụng không tiết lộ bất kỳ mã thông báo cho người dùng ẩn và có thể các ứng dụng mã độc khác có quyền truy cập vào dưới danh nghĩa người dùng ẩn. Máy chủ ủy quyền cũng có thể kiểm tra máy chủ RP có bị giả mạo không trước khi trao đổi mã ủy quyền lấy mã thông báo truy cập. Luồng mã ủy quyền phù hợp với các máy chủ RP có thể duy trì an toàn bảo mật khách hàng giữa họ và máy chủ ủy quyền. Hiểu đơn giản hơn là giữa 2 máy chủ có độ tin cậy cao hoặc các nhà cung cấp lớn (google, facebook…)
Tại bước 5, luồng mã ủy quyền sẽ:
– Máy chủ ủy quyền chuyển người dùng cuối trở lại với điểm truy cập của máy chủ RP với mã ủy quyền.
– Máy chủ RP yêu cầu phản hồi bằng mã ủy quyền tại điểm truy cập cuối cùng.
– Máy chủ RP nhận được phản hồi có chứa đồng thời cả mã thông báo ID và mã thông báo truy cập trong nội dung phản hồi.
b. Xác thực thông qua “Luồng mã ẩn”
Khi sử dụng luồng mã ẩn, tất cả các mã thông báo được trả về từ từ điểm ủy quyền cuối (Authorization Endpoint), mã thông báo từ điểm cuối của kênh thông tin (token endpoint) không được sử dụng.
Luồng mã ẩn chủ yếu sử dụng bởi máy chủ RP được triển khai trong trình duyệt sử dụng ngôn ngữ script. Mã thông báo truy cập và mã thông ID được trả lại trực tiếp cho máy chủ RP, có thể hiện thì chúng cho người dùng cuối và các ứng dụng có quyền truy cập với tác nhân là người dùng ẩn danh. Máy chủ ủy quyền không thực hiện xác thực ứng dụng máy chủ RP.
Tại bước 5, luồng mã ẩn sẽ:
– Máy chủ ủy quyền sẽ gửi người dùng cuối trở lại với máy chủ RP bằng mã thông báo ID và, nếu được yêu cầu có kèm cả mã thông báo truy cập.
c. Xác thực thông qua “Luồng mã kết hợp”
Khi sử dụng luồng mã kết hợp, một số thông báo được trả về từ điểm ủy quyền cuối và một số mã thông báo được trả về từ mã thông báo ở điểm cuối. Các cơ chế trả lại mã thông báo trong luồng kết hợp được chỉ định trong OAuth 2.0 Multiple Response Type Encoding Practices [OAuth.Responses].
Tại bước 5, luồng mã kết hợp sẽ:
– Máy chủ ủy quyền gửi người dùng cuối trở lại máy chủ RP với mã ủy quyền và tùy thuộc vào loại phản hồi, một hoặc nhiều tham số bổ sung.
– Máy chủ RP yêu cầu phản hồi bằng mã ủy quyền bằng mã thông báo ở điểm cuối.
– Máy chủ RP nhận được phản hồi có chứa mã thông báo ID và mã thông báo truy cập trong nội dung phản hồi.
Sau khi hoàn thành quá trình xác thực ta có hình ảnh như sơ đồ này, tuy nhiên đối với một số trường hợp, luồng đăng nhập được bắt đầu bởi nhà cung cấp OpenID hoặc một bên khác, thay vì là một bên đáng tin cây.
Trong quá trình tuần tự chạy mã ủy quyền, luồng mã bắt buộc phải chạy theo tuần tự được nêu ở trên. Đầu tiên mã sẽ được yêu cầu xác thực và xác minh rằng mã có chứa giá trị phạm vi “openid” (Không có nào trùng giá trị với vi phạm openid, yêu cầu có thể là giống OAuth 2.0 tổng hợp), sau đó là xác thực người dùng cuối với máy chủ ủy quyền. Tiếp đó là phản hồi xác thực thành công hoặc lỗi, nếu lỗi sẽ cần xác thực phản hồi lỗi này có đúng không. Và tuần tự như vậy với mã thông báo ở điểm cuối, mã thông báo ID và mã thông báo truy cập đều tuân theo quá trình tuần tự này.
Tạm kết
Sau các mục đầu tiên, bài viết đã chia sẻ những cái nhìn đầu tiên về tiêu chuẩn OpenID Connect 1.0. Từ tổng quan vận hành và việc xây dựng riêng mã thông báo ID, tiêu chuẩn đã khẳng định yếu tố bảo mật trong uy quyền người dùng từ nhiều bên. Việc này có hiệu quả lớn trong xây dựng và phát triền các nền tảng hiện hành cho đến các nền tảng, ứng dụng mới trong tương lại. Hi vọng bài viết sẽ giúp bạn đọc có cái nhìn rõ ràng hơn với tiêu chuẩn này.
Vũ Cao Minh Đức
- Hardt, D., “The OAuth 2.0 Authorization Framework,” RFC 6749, October 2012 (TXT).
- Jones, M., “JSON Web Algorithms (JWA),” draft-ietf-jose-json-web-algorithms (work in progress), July 2014 (HTML).
- Jones, M., Rescorla, E., and J. Hildebrand, “JSON Web Encryption (JWE),” draft-ietf-jose-json-web-encryption (work in progress), July 2014 (HTML).
- Jones, M., Bradley, J., and N. Sakimura, “JSON Web Token (JWT),” draft-ietf-oauth-json-web-token (work in progress), July 2014 (HTML).
- Sakimura, N., Bradley, J., Jones, M., and E. Jay, “OpenID Connect Discovery 1.0,” November 2014.