I. Giới thiệu
Nếu bạn từng làm việc với dịch vụ lưu trữ đám mây (ví dụ: AWS S3 hoặc GCP Cloud Storage), bạn có thể biết rằng việc tạo Signed URL là một cách để cung cấp quyền truy cập an toàn và tạm thời đối với các đối tượng lưu trữ trên các bucket trên cloud đúng không?
Một Signed URL được ký chứa thông tin xác thực, có thời gian hết hạn và cho phép người dùng không có thông tin đăng nhập tải lên và download các file trên bucket. Do đó, bất kỳ ai biết URL này đều có thể truy cập tài nguyên cho đến khi thời gian hết hạn của URL đó.
Cách tạo chữ ký signed
Bây giờ chỉ có cách tạo một cách để tạo chữ ký V4 là ký một “blob” (byte tùy ý) bằng Service Account Key. Key này về cơ bản là một RSA Private key có thể được tạo cho Service Account của bạn. Việc ký dữ liệu bằng Private key của Service Account cho phép GCP xác thực dữ liệu và liên kết nó với Service Account tương ứng.
Service Account yêu cầu quyền storage.buckets.get để liệt kê bucket mà trong đó có một tệp tin được lưu trữ. Tùy thuộc vào mục đích của URL đã ký, cũng có thể cần quyền storage.objects.get hoặc storage.objects.insert.
Phương pháp này được triển khai bằng lệnh gsutil signurl và hoặc call trực tiếp API gửi cho Cloud Storage.
Dưới đây là một ví dụ về lệnh gsutil signurl sử dụng service account:
gsutil signurl -d 10m private-key.json gs://<bucket>/<object>
II.Sự nguy hiểm của signBlob IAM method
Sử dụng service account key và IAM signBlob đều có mục đích giống nhau (một ưu điểm rõ ràng của phương pháp signBlob trong môi trường GCP là nó cho phép các nhà phát triển URL signed mà không cần quản lý service account key). Tuy nhiên, có một khác biệt quan trọng trong phương pháp signBlob mà có lẽ không rõ ràng khi đọc tài liệu: Phương pháp này cho phép bất kỳ dữ liệu nào được ký thay mặt cho bất kỳ service account nào.
Cụ thể hơn, một service account có quyền iam.serviceAccounts.signBlob có thể ký dữ liệu bằng cách sử dụng email hoặc ID dự án duy nhất của bất kỳ tài khoản dịch vụ nào sử dụng tham số đường dẫn tên. Service account được tham chiếu phải thuộc cùng một tài khoản GCP. Kết quả là, Service Account Key có thể được sử dụng để thủ công ký một JWT ủy quyền để yêu cầu một mã thông báo truy cập tạm thời của một tài khoản dịch vụ với đặc quyền cao hơn.
Vậy thì làm sao hacker có thể tận dụng điểm yếu này? Rất dễ, chỉ cần chiếm được một Service Account (qua các lỗ hổng như SSRF, RCE hoặc LFI) với quyền iam.serviceAccounts.signBlob. Do IAM signBlob bi ràng buộc bởi các rule của IAM, do đó Service Account nào cũng có thể được sử dụng để ký dữ liệu.
Thông tin chi tiết hơn về cách lợi dụng quyền iam.serviceAccounts.signBlob và một kịch bản khai thác PoC có thể được tìm thấy trong bài viết này về các kỹ thuật leo thang đặc quyền GCP của RhinoSecurity.
Do cách Google Cloud hoạt động, khả năng tìm thấy một Default Service Account mặc định với đặc quyền cao là gần như 100%. Default Service Account được tạo tự động khi bạn kích hoạt hoặc sử dụng dịch vụ Google Cloud và cho phép dịch vụ truy cập các nguồn tài nguyên khác của Google Cloud.
Khi một Default Service Account được tạo, nó sẽ tự động được cấp quyền vai trò Editor cơ bản trên project. Vai trò này bao gồm gần như tất cả các quyền liên quan đến project => tạo ra rủi ro leo thang đặc quyền.
III. Kết luận
Cả việc ký thông qua Service Account Key và ký thông qua phương pháp IAM signBlob đều mang theo những rủi ro bảo mật trong môi trường GCP của bạn. Việc sử dụng Service Account Key buộc các nhà phát triển phải quản lý key, bao gồm việc lưu trữ an toàn và rotate key. Điều này khiến phương pháp ký bằng key không tiện lợi cho họ, đặc biệt là trong môi trường không có máy chủ như Cloud Functions, Cloud Run và App Engine. Để tránh sự không thuận tiện này, nhiều nhà phát triển sử dụng phương pháp IAM signBlob, cho phép URL được ký bằng cách sử dụng Service Account Key đính kèm trong một computing instance. Phương pháp này sử dụng một token tạm thời làm thông tin xác thực có thể được lấy từ siêu dữ liệu môi trường.
Tuy nhiên, nếu bạn sử dụng phương pháp IAM signBlob để tạo các signed URL, một Service Account sẽ yêu cầu quyền iam.serviceAccounts.signBlob. Một ứng dụng web có lỗ hổng SSRF, RCE hoặc LFI có thể cho phép xâm phạm tài khoản dịch vụ cộng với có quyền signBlob, => đặt cả project Google Cloud vào tình trạng nguy hiểm.
Do đó, phương pháp IAM signBlob mang lại nhiều rủi ro hơn cho môi trường GCP từ góc độ bảo mật. Như một lựa chọn khác, ta có thể ký các URL bằng cách sử dụng HMAC credential. Phương pháp này được tạo ra để tương thích với các cơ chế ký khác nhau của các nhà cung cấp cloud khác nhau. Hiện tại, credential chỉ có thể được sử dụng với Cloud Storage. Tuy nhiên, nhà phát triển cũng phải quản lý key một cách an toàn.
Nếu bạn vẫn thấy phương pháp IAM signBlob thuận tiện hơn cho ứng dụng của mình, các bước tiếp theo này có thể giúp bạn giảm thiểu ảnh hưởng từ việc service account bị thịt:
- Không ràng buộc các vai trò cơ bản (Viewer, Editor và Owner) với các Service Account trong môi trường Product.
- Tắt việc cấp quyền tự động cho các Default Service Account.
- Hạn chế quyền của Service Account bằng cách thêm các custom role hoặc sử dụng các role cũ có sẵn nhưng được siết chặt hơn.
Update: role này đã bị deprecated ^_^
Ref: https://lsgeurope.com/post/signing-urls-in-gcp-convenience-vs-security