Tìm hiểu về OAuth 2.0 (part I)

Các khái niệm cơ bản

Các thuật ngữ này sẽ được sử dụng một cách thường xuyên trong bài viết, nên trước tiên, chúng ta cần nói rõ với nhau xem, chúng có nghĩa là gì :

  • Resource Owner: là chủ sở hữu của dữ liệu ta muốn chia sẻ. Chẳng hạn, bạn muốn chia sẻ thông tin email + username facebook của bạn cho Viblo để có thể đăng nhập Viblo qua facebook, thì ở đây, thông tin email + username này là tài nguyên cần chia sẻ (resource), còn bạn chính là resource owner.

  • Resource Server: là server nơi chứa thông tin dữ liệu cần chia sẻ. Server này phải có khả năng nhận và trả lời các yêu cầu (request) truy xuất dữ liệu. Như ở ví dụ trên của chúng ta thì resource server chính là facebook.

  • Client: Là những chương trình, ứng dụng có như cầu muốn sử dụng tài nguyên được chia sẻ. Như trong ví dụ trên thì client chính là ứng dụng Viblo.

  • Authorization Server: Là đối tượng quyết định việc cấp quyền truy cập vào dữ liệu cho client. Như trong ví dụ trên, đây chính là authorization server của facebook. Đôi khi resource server và authorization server có thể là một , nhưng về mặt chức năng mà nói, đây là 2 chức năng hoàn toàn riêng biệt.

Basic authentication

Thời kì đầu, việc chia sẻ tài nguyên với ứng dụng bên thứ 3 là chưa nhiều, nên khi cần phải thực hiện chuyện đó, ta chỉ dùng phương thức xác thực đơn giản nhất là Basic authentication, implement của nó cũng diễn ra theo chiều hướng trực giác, tự nhiên nhất. Flow cơ bản của nó là : khi client cần truy xuất dữ liệu (resource) trên server, server sẽ yêu cầu phía client nhập thông tin xác thực ( thường là username, password) của resource owner . Nếu như bạn là resource owner, và bạn muốn chia sẻ dữ liệu của mình với bên thứ 3 nũa, bạn sẽ phải chia sẻ cho họ thông tin xác thực . Việc làm này, có thể dễ dàng thấy, tuy đơn giản, dễ áp dụng, nhưng tiềm tàng nhiều nguy cơ về mặt bảo mật :

  • Thứ nhất là để làm việc này yêu cầu bên thứ 3 phải có khả năng lưu trữ thông tin xác thực của bạn để có thể sử dụng bất kì khi nào.

  • Thứ hai , khi bạn chia sẽ tài nguyên theo cách này, bạn không thể nào giới hạn mức độ chia sẻ tới đâu. Server ko thể phân biệt được đối tượng đang trả lời yêu cầu xác thực là resource owner, hay là bên thứ 3, và như vậy, bên thứ 3 sẽ có toàn quyền với dữ liệu của bạn.

  • Tiếp đến, giả sử bạn chia sẻ thông tin xác thực của mình với nhiều bên thứ 3 khác nhau, khi muốn thu hồi lại quyền truy cập dữ liệu đã chia sẻ, bạn sẽ phải thu hồi lại với tất cả.

Rõ ràng, nếu cứ làm thế này thì không ổn chút nào. Cùng với sự phổ biến của việc chia sẻ tài nguyên giữa các ứng dụng, nhu cầu đặt ra lúc này là phải có một cách thức nào đó để chia sẻ tài nguyên cho bên thứ 3, mà không cần phải chia sẻ password của người dùng. Đó cũng chính là tư tưởng cốt lõi của chuẩn OAuth. Phiên bản đầu tiên của OAuth là OAuth 1.0 , và OAuth 1.0 chỉ là một giao thức (protocol). Do trọng tâm của bài viết ko phải là OAuth 1.0, nên xin được không đi vào chi tiết, ta có thể hiểu một cách tóm tắt như thế này : để thực hiện xác thực theo giao thức OAuth 1.0, ta cần phải qua 3 bước :

  • Client sẽ gọi lên Authorization Server để xin xác nhân tạm thời (temporary credentials)

  • Mở một webpage với thông tin xác nhân tạm thời đó, để user ( resource owner ) đăng nhập vào server và trao quyền truy cập cho phía client. Sau đó redirect về client, dựa theo thông tin callback gắn kèm trong request đầu tiên, gửi theo thông tin token tạm thời.

  • Gọi lên Authorization Server một lần nữa, sử dụng cả xác nhân tạm thời và token tạm thời. Server lúc này sẽ trả về cho client access token. Sử dụng token này, client từ đó về sau có thể truy cập thông tin dữ liệu của user (resource owner), cho tới khi nào resource owner rút lại quyền truy cập ( revoke ) của access token đó thì thôi.

Giao thức OAuth 1.0 ( và bản nâng cấp OAuth 1.0a ) đã giải quyết được bài toán ban đầu đặt ra, là chia sẻ quyền truy cập dữ liệu của resource owner với bên thứ 3, mà không cần phải chia sẻ thông tin xác thực (credentials). Resource owner có thể chia sẻ với nhiều bên thứ 3 khác nhau, và khi cần, có thể rút lại quyền này của một hay nhiều client tùy chọn. Tuy nhiên, khi sử dụng giao thức này, người ta sớm nhận thấy một vài điểm yếu mới phát sinh của nó :

  • Cách thức implements khá phức tạp, khiến cho việc thực thi đôi khi không thuận lợi.

  • Khi cấp access token, ta không thể quy định xem đến khi nào thì token này hết hạn, không còn giá trị sử dụng.

  • Không có phân quyền chi tiết cho mỗi token, ví dụ như token1 chỉ được thực hiện những hành động abc trên loại tài nguyên xyz, còn token2 thì lại có quyền def trên tài nguyên ftg ....

Và đề giải quyết bài toán đó, thì các nhà hoạch định internet đã xây dựng chuẩn OAuth 2.0, và cũng là trọng tâm của bài viết này. Bản draft đầu tiên của OAuth 2.0 ra đời vào năm 2010, và đã có nhiều dịch vụ áp dụng phiên bản này từ ngày đó, nhưng phải đến năm 2012, chuẩn OAuth 2.0 hoàn chỉnh mới chính thức được ra mắt. Khác với OAuth 1.0 là một giao thức (protocol), OAuth 2.0 được định nghĩa là một framework. Trong chuẩn 2.0, client không chỉ được quyền truy xuất dữ liệu nhân danh resource owner, mà clients có thể nhân danh chính mình. Qua đó, việc phân quyền cụ thể cho từng clients cũng có thể thực hiện được. Nhưng cũng chính vì những khác biệt đó, mà chuẩn OAuth2.0 ko tương thích với OAuth 1.0.

Workflow của OAuth 2.0

 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

Về cơ bản, work flow của OAuth2.0 bao gồm 3 bước chính :

  • Client request quyền truy cập và resource owner chấp thuận cấp quyền.

  • Client gửi authorization grant do resource owner cung cấp lên cho authorization server, sau khi xác nhận, server sẽ gửi về access token cho client.

  • Client sử dụng access token này trong quá trình liên lạc với resource server. Resource server sẽ kiểm tra tính hợp lệ của token, nếu đúng trả protected resource về cho client.

Chúng ta sẽ cùng tìm hiểu sâu hơn về từng bước trong workflow này.

Authorization Request & Grant

Authorization grant thể hiện sự chấp thuận của resource owner cho phép client truy cập vào protected resource. Tùy vào mối quan hệ giữa client với resource owner, cũng như tính chất của client , OAuth 2.0 có định nghĩa các loại grant type phù hợp cho đa số các tình huống, cũng như hỗ trợ định nghĩa thêm custom grant type. Về cơ bản, ta có 4 loại grant sau, tìm hiểu sâu về mỗi loại này sẽ là nội dung của bài viết phần tới.

Authorization Code
Implicit Grant
Resource Owner Password Credentials
Client Credentials