Phân biệt Authentication và Authorization. Các giao thức xác thực Web.

Authentication và Authorization

Có lẽ trong quá trình lập trình bạn đã được nghe rất nhiều về 2 khái niệm authentication và authorization nhưng liệu bạn đã phân biệt được sự khác nhau giữa 2 khái niệm này? hay đôi khi bạn vẫn mập mờ không hiểu được đâu là authorization và đâu là authentication?

Cả 2 thuật ngữ thường được sử dụng kết hợp với nhau để nói về bảo mật, đặc biệt là khi nói đến quyền truy cập vào hệ thống. Cả hai đều là những chủ đề rất quan trọng thường đi kèm với các trang web như phần quan trọng trong cơ sở hạ tầng dịch vụ của mình. Tuy nhiên, cả hai thuật ngữ rất khác nhau với các khái niệm hoàn toàn khác nhau. Trong khi đó chúng thường được sử dụng trong bối cảnh tương tự với công cụ tương tự, chúng là hoàn toàn khác biệt với nhau

Authentication

Authentication: được định nghĩa là khi thực thể chứng minh danh tính là gì hay nói một cách đơn giản là trả lời cho câu hỏi “who you are”

Dựa trên cấp độ bảo mật, authentication factor có thể thay đổi theo một trong các cách sau:

  • Single-Factor Authentication 
  • Two-Factor Authentication
  • Multi-Factor Authentication

Authorization

Authorization : được định nghĩa là khi thực thể chứng minh có quyền truy cập, đơn giản như kiểu có một cái chìa khóa nhưng chỉ được phép mở một vài cửa trong nhà chứ không được phép mở tất cả các cửa. Hay nói cách khác nó trả lời cho câu hỏi “what you can do”

Phân biệt Authentication vs Authorization

Các dạng xác thực Web

HTTP Basic authentication

HTTP Basic authentication yêu cầu client cung cấp username và password mỗi lần gọi request.

Đây là cách xác thực đơn giản nhất, không yêu cầu cookies, sessions… Client cần thêm header Authorization vào tất cả các request. Username và password không được encrypt mà được cấu trúc như sau:

  • nối username và password theo dạng username:password
  • encode chuỗi trên với Base64
  • thêm từ khoá Basic

Ví dụ với username john với password secret :

1curl –header “Authorization: Basic am9objpzZWNyZXQ=” my-website.com

Chúng ta có thể dùng Chrome để quan sát:

Cài đặt HTTP Basic Authentication trên Node.js cũng khá dễ dàng như ví dụ sau đây, sử dụng Express middleware:

Khá là đơn giản phải không? Vậy nhược điểm của HTTP Basic Authentication là gì?

  • username và password được gửi trong mọi request, nên có nguy cơ bị lộ tài khoản, kể cả khi sử dụng kết nối bảo mật.
  • Liên kết với SSL/TLS, nếu mà website sử dụng mã hoá yếu thì sẽ bị lộ tài khoản ngay lập tức.
  • Không có cách nào để đăng xuất tài khoản cả.
  • Phiên đăng nhập sẽ không bao giờ bị hết hạn, trừ khi người dùng đổi password.

Cookies

Xác thực bằng Cookies sử dụng HTTP cookies để xác thực request của client và duy trì phiên đăng nhập. Luồng hoạt động:

  • Client gửi request đăng nhập lên server.
  • Khi server nhận được HTTP request, gửi thêm Set-Cookie header vào response.
  • Trình duyệt thêm cookie đó vào tất cá các request có cùng origin với origin trong Cookie HTTP header.
  • Khi đăng xuất, server sẽ gửi lại Set-Cookie để khiến cho cookie cũ hết hạn.

Nếu muốn sử dụng Cookies để xác thực thì phải tuân thủ một số nguyên tắc sau:

Luôn luôn sử dụng HttpOnly cookies

Để giảm thiểu khả năng bị tấn công XSS thì luôn sử dụng HttpOnly flack khi thiết lập cookie. Bằng cách đó cookie sẽ không hiện lên ở document.cookies.

Luôn luôn sử dụng signed cookies

Với signed cookies, server có thể biết được là cookie có bị client sửa đổi hay không.

Ta cũng có thể quan sát được việc sử dụng Cookies để xác thực trên Chrome. Đầu tiên server sẽ thiết lập cookie:

Sau đó các request sẽ sử dụng cookie trên với domain www.linkedin.com:

Nhược điểm của xác thực sử dụng Cookies:

  • Dễ bị tấn công CSRF, cần phải làm thêm một số việc để giảm thiểu rủi ro.
  • Không tương thích với REST (vì REST là stateless)
  • Có thể bị XSS attack.

Signatures

Dù sử dụng cookies hay là tokens, nếu mà transport layer vì 1 lý do nào đó mà để lộ thông tin, thì attacker hoàn toàn có thể dùng token và cookie để truy cập như người dùng thật.

Một cách để giải quyết vấn đề trên là chúng ta sẽ ký (sign) vào tất cả các request (ở đây chỉ đề cập đến các request qua APIs, không bao gồm các request từ browser).

Sign vào request có nghĩa là phải hash toàn bộ request sử dụng private key. Việc hashing cần sử dụng:

  • HTTP method
  • Đường dẫn của request
  • HTTP headers
  • Checksum của HTTP payload
  • private key để tạo hash

Người gọi và người cung cấp API phải có chung 1 private key. Một khi mà đã có signature, người dùng cần thêm signature vào query string hoặc HTTP header của request. Người dùng cũng nên thêm date vào để có thể chỉ rõ được thời gian hết hạn của signature.

AWS Request Signing Flow – source

Bằng cách trên, nếu mà transport layer có bị hack thì attacker cũng chỉ có thể đọc được nội dung của request, chứ không thể nào mà giả vờ là user để gửi request được vì không có private key. Hầu hết các dịch vụ của AWS đều sử dụng loại xác thực này.

Nhược điểm:

  • Không thể sử dụng với browser/client, chỉ sử dụng với APIs.

One-Time passwords

Thuật toán One-Time passwords tạo ra 1 password dùng 1 lần (one-time password) dựa vào khoá bí mật được dùng chung và thời gian hiện tại hoặc 1 bộ đếm:

  • Time-based One-time Password Algorithm, dựa vào thời gian hiện tại
  • HMAC-based One-time Password Algorithm, dựa vào bộ đếm

One-Time passwords thường được áp dụng trong các ứng dụng cần bảo mật hai lớp: người dùng nhập username, password sau đó cả server và client sẽ cùng tạo ra một one-time password.

Nhược điểm:

  • Nếu khoá bí mật bị lộ thì attacker sẽ nắm được one-time password.
  • Client (thường là điện thoại) có thể bị trộm nên hệ thống cần có cách để skip one-time password, ví dụ như là rest qua email.

Token-based authentication

Token-based authentication là phương thức xác thực bằng chuỗi má hóa. Một hệ thống sử dụng Token-based authentication cho phép người dùng nhập user/password để nhận về 1 chuỗi token. Chuỗi Token này được sử dụng để “xác minh” quyền truy cập vào tài nguyên mà không cần phải cung cấp lại username/password nữa.

Tiếp theo, chúng ta sẽ tìm hiểu về phương pháp sử dụng Token-based authentication bằng JWT (Json Web Token).

JWT Authentication

JSON Web Token là một chuỗi mã hóa mà nguồn gốc ban đầu là một chuỗi JSON. Chuỗi thông tin dạng JSON bằng phương pháp mã hóa nào đó, nó trở thành 1 chuỗi ký tự lộn xộn nhìn vào sẽ rất khó hiểu.

Như vậy, Bảo mật JWT là phuơng pháp xác thực quyền truy cập (Authentication) bằng JSON Web Token.

JWT trên bao gồm 3 phần:

  • Header
  • Payload
  • Signature
Flow sử dụng JWT

Nhìn vào hình ta có thể thấy flow đi như sau:

  1. User thực hiện login bằng cách gửi id/password hay sử dụng các tài khoản mạng xã hội lên phía Authentication Server (Server xác thực)
  2. Authentication Server tiếp nhận các dữ liệu mà User gửi lên để phục vụ cho việc xác thực người dùng. Trong trường hợp thành công, Authentication Server sẽ tạo một JWT và trả về cho người dùng thông qua response.
  3. Người dùng nhận được JWT do Authentication Server vừa mới trả về làm “chìa khóa” để thực hiện các “lệnh” tiếp theo đối với Application Server.
  4. Application Server trước khi thực hiện yêu cầu được gọi từ phía User, sẽ verify JWT gửi lên. Nếu OK, tiếp tục thực hiện yêu cầu được gọi.
Khi nào nên sử dụng JWT

Với JWT, bạn không cần phải giữ session data trên server để xác thực user.

Nếu không sử dụng session thì bạn mới có thể ứng dụng tạo một service thuần RESTful, bởi vì một service thuần RESTful được định nghĩa là phải stateless. Với dung lượng nhỏ, JWT có thể được gửi lên với mọi request cũng giống như session cookie. Nhưng ko giống với session cookie, nó ko cần phải trỏ đến bất kì dữ liệu nào được lưu trữ trên server, bản thân JWT đã có dữ liệu.

JWT  phù hợp với API cho native mobile app hoặc single page application. Có một điều cần lưu ý khi sử dụng JWT là browser sẽ lưu JWT trong LocalStorage hoặc SessionStorage, do đó có nguy cơ bị XSS attack.

Nhược điểm:

  • Có thể bị XSS attack.

Api Keys

Phương thức này được tạo ra với mục đích khắc phục những vấn đề của basic authentication. Trong phương thức này, một giá trị key duy nhất sinh (unique key) ra và gán cho user trong lần đầu tiên, biểu thị rằng user đó được xác định. Khi user quay trở lại hệ thống, unique key (có thể được sinh ra từ việc kết hợp giữa thông tin phần cứng, địa chỉ IP và thời gian của server) được sử dụng để chứng minh rằng user là giống với lần đầu tiên.
 Rất nhiều api key được gửi dưới dạng là một phần của URL (query string) để giúp nhận biết rằng ai không nên có quyền truy cập. Một lựa chọn tốt hơn là gửi api key trong authorization header, như kiểu Authorization: Apikey 1234567890abcdef.

Trong thực tế thì api key xuất hiện dưới dạng như:
. Authorization Header
. Basic Authen
. Body Data
. Query String
Một số trường hợp có thể sử dụng api keys, ví dụ trường hợp có một api được giới hạn với quyền chỉ được đọc. Trong trường hợp dùng với authentication rest api, thì cần phải quan tâm đến vấn đề bảo mật hơn.

OAuth (2.0)

OAuth là viết tắt của Open với Authentication hoặc Authorization. OAuth ra đời nhằm giải quyết các vấn đề trên và xa hơn nữa, đây là một phương thức chứng thực giúp các ứng dụng có thể chia sẻ tài nguyên với nhau mà không cần chia sẻ thông tin username và password. OAuth bao gồm bốn vai trò khác nhau:
Resource Server: REST API là một ví dụ, một máy chủ HTTP nơi người dùng có thể tạo, sửa đổi hoặc xóa các bản ghi, tài liệu hoặc tệp.

Resource Owner: Duy trì quyền sở hữu tài nguyên mà người dùng đã tạo hoặc sửa đổi trên máy chủ và người ủy quyền cho ứng dụng bên thứ 3 truy cập vào tài khoản của họ. Ứng dụng của bên thứ 3 có quyền truy cập hạn chế vào tài khoản của người dùng, dựa trên phạm vi của phạm vi của ủy quyền được cấp.

Client: Ứng dụng bên thứ 3 muốn truy cập vào tài khoản người dùng. Trước khi nó có thể làm như vậy, máy chủ resource/authorization và chủ sở hữu tài nguyên phải ủy quyền cho yêu cầu đó. Mọi khách hàng phải được đăng ký với máy chủ authorization và sẽ được cung cấp cho nó thông tin xác thực duy nhất của riêng mình (client_id và client_secret) để xác thực riêng.

Authorization Server (thường là giống Resource Server): Đôi khi, ta có thể muốn rút ra khỏi máy chủ authorization từ máy chủ resource và triển khai nó như một phiên bản chuyên dụng, đặc biệt là trong các môi trường phân tán.

Lấy một ví dụ như sau:
Khi ta đăng nhập bằng Facebook hay Gmail, website sẽ dẫn ta đến trang (hoặc phần mềm) Facebook và liệt kê những quyền mà nó cần phải có để cho phép bạn đăng nhập và sử dụng dịch vụ. Nếu ta đồng ý thì lúc này Facebook sẽ phát cho website một cái token Token này chứa một số quyền hạn nhất định giúp cho website có thể xác minh chúng ta là ai cũng như giúp cho website có thể hoạt động được. Nếu website này bị hacker tấn công thì nó chỉ lấy được thông tin hay hoạt động của ta trên website đó mà không ảnh hưởng đến những website khác đang sử dụng. Do đó cách đăng nhập bằng phương thức OAuth này rất an toàn cho người dùng cuối như chúng ta.

Sơ đồ luồng hoạt động của OAuth2

  1. Ứng dụng (website hoặc mobile app) yêu cầu ủy quyền để truy cập vào Resource Server (Gmail,Facebook, Twitter hay Github…) thông qua User
  2. Nếu User ủy quyền cho yêu cầu trên, Ứng dụng sẽ nhận được ủy quyền từ phía User (dưới dạng một token string)
  3. Ứng dụng gửi thông tin định danh (ID) của mình kèm theo ủy quyền của User tới Authorization Server
  4. Nếu thông tin định danh được xác thực và ủy quyền hợp lệ, Authorization Server sẽ trả về cho Ứng dụng access_token. Đến đây quá trình ủy quyền hoàn tất.
  5. Để truy cập vào tài nguyên (resource) từ Resource Server và lấy thông tin, Ứng dụng sẽ phải đưa ra access_token để xác thực.
  6. Nếu access_token hợp lệ, Resource Server sẽ trả về dữ liệu của tài nguyên đã được yêu cầu cho Ứng dụng

Cách lựa chọn phương thức xác thực

Nếu mà bạn chỉ xây dựng web thì cookies và tokens là lựa chọn phù hợp. Với Cookies bạn cần chú ý về tấn công XSRF, còn với JWT thì cần chú ý đến tấn công XSS.

Nếu mà bạn cần xây dựng cả web và app thì nên dựng API xác thực qua token.

Nếu bạn đang xây dựng APIs để người dùng gọi đến API của bạn thì nên dùng signatures.

Tham khảo

Leave a Reply

Your email address will not be published. Required fields are marked *