FDE PulseViệc làm FDE đang mở 316Mới đăng 7 ngày qua 10Chủ đề nổi bật: Đào tạo kỹ năng FDE tại Đông Nam Á

Tờ báo của nghề Forward Deployed Engineer

Bách khoa

API key, Basic Auth, session, JWT hay OIDC: cách đọc đúng cơ chế xác thực ở hệ thống khách hàng

Lỗi 401 đầu tiên ở site khách chưa phải điều đáng sợ nhất. Đáng sợ hơn là integration vẫn chạy trong khi bạn hiểu sai cách hệ thống xác thực.

Ảnh kỹ sư ngồi trước laptop đang viết code hoặc kiểm tra request API, bối cảnh văn phòng công nghệ hiện đại.
Ảnh: Christina Morillo / CC0
Infographic gồm ba hàng câu hỏi. Câu 1, credential nằm ở đâu: trong header Authorization (với Basic là chuỗi base64 của user:pass, decode được ngay) hoặc trong cookie (session của trình duyệt, thường gắn với một domain); Basic và API key phải đi qua HTTPS. Câu 2, server có phải nhớ gì không: có với session (stateful, khó scale hơn), không với token (stateless); agent chạy trên domain khác khó dùng lại session cookie. Câu 3, ai bảo đảm danh tính: JWT chỉ là định dạng token, khác với OIDC, lớp danh tính chạy trên OAuth 2.0 và được tô màu nhấn; nên hỏi khách danh tính do hệ thống nào cấp.
Ba câu cần trả lời khi nhìn vào một request: credential nằm ở đâu, server có phải nhớ gì không, và ai bảo đảm danh tính. JWT chỉ là định dạng token, còn OIDC mới là lớp danh tính.

Tóm tắt nhanh

  • Base64 chỉ là encoding, không phải encryption. Basic Auth và API key đều phải đi qua HTTPS.
  • Session buộc server nhớ trạng thái và gắn với domain. JWT thì không cần lưu, nhưng phải kiểm tra chữ ký trước khi dùng.
  • Chữ ký JWT chứng minh dữ liệu không bị sửa, không giữ được bí mật. Muốn biết người dùng là ai thì cần OIDC.
Chia sẻLinkedInFacebookX

Tuần đầu ở site khách, bạn được giao nối một agent vào hệ thống nội bộ của họ. Kỹ sư phía khách nhắn: “Cứ gọi API thôi, auth có sẵn rồi.” Request đầu tiên trả về 401, và lúc đó bạn mới thấy “có sẵn rồi” có thể là năm cơ chế hoàn toàn khác nhau.

API key, Basic Auth, session cookie, JWT và OIDC trả lời những câu hỏi khác nhau, nên khi hỏng cũng hỏng theo những kiểu khác nhau. Đọc sai cơ chế, bạn dễ viết ra integration chạy tốt trên laptop nhưng gãy khi lên production. Tệ hơn, credential có thể nằm trong log mà không ai hay.

Kỹ năng này không đòi bạn thuộc lòng spec. Nó là khả năng nhìn vào một request và trả lời được ba câu: credential nằm ở đâu, server có phải nhớ gì không, và ai bảo đảm danh tính người dùng.

Basic Auth trông như mật khẩu bị giấu, thực ra không

Basic Auth là scheme có sẵn trong giao thức HTTP. Client ghép username và password thành chuỗi username:password, encode bằng base64, rồi gửi trong header theo định dạng mà tài liệu của Twilio mô tả: chữ Authorization: Basic, theo sau là chuỗi base64 đó.

Cách nhanh nhất để thấy vấn đề là tự làm thử với một tài khoản giả:

echo -n 'user:pass' | base64
# dXNlcjpwYXNz

echo 'dXNlcjpwYXNz' | base64 -d
# user:pass

Không cần key, cũng chẳng có gì để bẻ khóa, vì base64 là encoding chứ không phải encryption. Postman nói rõ credential Basic Auth không được hash và cũng không được mã hóa (encryption). Tài liệu của Swagger khuyến cáo chỉ dùng Basic Auth khi có thêm cơ chế bảo mật khác đi kèm, chẳng hạn HTTPS.

API key cùng nhóm rủi ro với Basic Auth. Postman định nghĩa API key là định danh cấp cho người dùng đã đăng ký, và nhấn mạnh rằng nó phải đi qua HTTPS mới giữ được an toàn.

Ở site khách, việc đầu tiên nên làm vì thế khá đơn giản: kiểm tra mọi endpoint nhận API key hay Basic Auth đều chạy HTTPS, kể cả các endpoint “chỉ dùng nội bộ”.

Session hay token: khác nhau ở chỗ ai phải nhớ

Hai cơ chế tiếp theo khác nhau về kiến trúc chứ không chỉ khác về định dạng. Authgear mô tả session authentication là stateful: server giữ trạng thái trong bộ nhớ, còn trình duyệt giữ cookie. JWT thì stateless, backend không phải lưu token.

Okta giải thích token-based auth theo cùng logic: xác minh danh tính một lần, cấp token, sau đó server không phải giữ bản ghi session nào. Authgear cũng lưu ý rằng session lưu trên server khó scale hơn.

Thử hình dung khách hàng có một web app nội bộ dùng session cookie, và bạn cần agent chạy trên một domain khác gọi vào backend của app đó. Cookie thường chỉ hoạt động trong một domain hoặc các subdomain của nó, nên agent của bạn khó mà “mượn” session của người dùng.

Hệ quả thực tế là đừng cố giả lập trình duyệt để lấy cookie. Hãy hỏi khách xem backend có hỗ trợ token cho các client không chạy trên trình duyệt hay không. Nếu chưa có, đó là một hạng mục cần đưa vào scope ngay từ đầu, đừng để thành một workaround về sau.

Mở một JWT ra để thấy nó không giữ bí mật

JWT gồm ba phần ngăn cách nhau bằng dấu chấm: header, payload và signature. Bạn có thể tách phần giữa ra và decode giống hệt cách làm với Basic Auth:

TOKEN='xxxxx.yyyyy.zzzzz'
echo "$TOKEN" | cut -d. -f2 | base64 -d
# có thể phải thêm ký tự '=' ở cuối để đủ padding

Theo jwt.io, chữ ký dùng để xác minh rằng thông điệp không bị thay đổi trên đường truyền. Nó chứng minh tính toàn vẹn của dữ liệu chứ không che giấu dữ liệu: ai cầm token cũng đọc được payload. Vì vậy, đừng đặt bí mật vào một JWT chỉ có chữ ký mà không được mã hóa (encryption).

Chiều ngược lại cũng dễ bị bỏ qua: người nhận token phải kiểm tra nó. Tài liệu của Auth0 yêu cầu JWT nhận được phải được kiểm tra chữ ký trước khi đem ra dùng. Nếu code của bạn chỉ decode payload rồi đọc user_id mà không verify, bất kỳ ai cũng có thể tự viết một token và mạo danh người khác.

JWT không cho biết người dùng là ai, OIDC thì có

Nhiều kỹ sư thấy khách dùng JWT rồi mặc định rằng danh tính đã được giải quyết. Thực ra JWT chỉ là một định dạng token. Spec OpenID Connect Core mô tả OIDC là một lớp danh tính đơn giản chạy trên OAuth 2.0, và chính lớp này mới trả lời câu “người dùng này là ai”.

Điểm phân biệt này quyết định cách bạn đặt câu hỏi trong buổi discovery. Đừng hỏi “Anh chị có dùng JWT không?”. Hãy hỏi “Danh tính người dùng do hệ thống nào cấp, và agent của chúng tôi sẽ đăng nhập thay ai?”.

Cơ chế Credential nằm ở đâu Server có lưu trạng thái? Rủi ro cần kiểm đầu tiên
Basic Auth Header Authorization: Basic Không Endpoint không chạy HTTPS
API key Do API quy định Không Key bị lộ khi không có HTTPS
Session Cookie Có Gọi chéo domain, khó scale
JWT Token do client giữ Không Không verify chữ ký, để bí mật trong payload
OIDC Lớp danh tính trên OAuth 2.0 Tùy triển khai Nhầm định dạng token với danh tính

Quy trình năm phút trước khi viết dòng code đầu tiên

Bắt đầu bằng việc bắt một request thật từ ứng dụng của khách, qua DevTools hoặc proxy, rồi xem header Authorization và cookie. Bước này cho bạn biết credential nằm ở đâu. Tiếp theo, decode thử: nếu là Basic thì bạn sẽ thấy ngay username, nếu là JWT thì bạn sẽ thấy payload.

Sau đó hỏi khách hai câu: server có giữ session không, và ai cấp lại credential khi nó hết hạn. Cuối cùng, ghi tất cả vào một “auth map” ngắn rồi đưa đội khách xác nhận. Tài liệu này sẽ là điểm tựa cho những lần xử lý sự cố về sau.

Những lỗi FDE hay mắc

Lỗi phổ biến nhất là coi base64 encoding như encryption, rồi log nguyên header Authorization ra file debug. Lỗi thứ hai là decode JWT để lấy thông tin người dùng mà bỏ qua bước verify chữ ký. Lỗi thứ ba là cố dùng lại session cookie cho một client chạy trên domain khác, trong khi cookie vốn gắn với một domain.

Lỗi khó thấy nhất nằm trong khâu giao tiếp: ghi “dùng JWT” vào tài liệu scope và nghĩ mọi chuyện đã rõ. Khi chưa ai trả lời được câu “danh tính do đâu cấp”, phần việc khó nhất của dự án vẫn còn nằm nguyên đó.

Bài tập cho tuần này: chọn một hệ thống bạn đang tích hợp, viết auth map gồm bốn cột như bảng trên, rồi tự kiểm xem team bạn đang mắc lỗi nào trong số các lỗi kể trên.

Nếu muốn dùng bài tập này khi đi xin việc FDE, đừng mang auth map thật của khách ra ngoài; hãy làm lại trên một dự án cá nhân hoặc một bản đã ẩn danh hoàn toàn.

Lần tới có ai nói “auth có sẵn rồi”, bạn sẽ biết cần hỏi tiếp câu gì.

8 nguồn
Đọc tiếp trên lộ trình · Chặng 2: Kỹ thuật rộngKéo một triệu bản ghi qua API phân trang của khách hàng mà không mất dòng nàoVòng lặp đọc dữ liệu chỉ có vài dòng code, nhưng nếu chọn sai cách phân trang, script sẽ chạy cả đêm hoặc trả về dữ liệu trùng mà bạn không hề hay biết.