Paparan Cloud dan Penyimpanan

Paparan cloud dan penyimpanan: bucket terbuka, endpoint metadata, dan CORS yang terlalu longgar.

Daftar isi

Paparan cloud adalah kebocoran yang bersumber dari konfigurasi layanan cloud, bukan dari baris kode aplikasi. Tiga bentuknya paling sering ditemui, yaitu bucket penyimpanan objek yang terbuka untuk publik, endpoint metadata instance yang hanya terjangkau dari dalam server, dan CORS yang diatur terlalu longgar. Topik ini membahas mekanisme ketiganya, lalu menutupnya dengan auditor sederhana yang menandai konfigurasi berisiko dari berkas kebijakan. Seluruhnya termasuk kategori A02 Security Misconfiguration pada OWASP Top 10:2025 sebab penyebabnya sama, yaitu nilai konfigurasi yang tidak pernah ditinjau.

Bucket penyimpanan objek yang terbuka#

Penyimpanan objek (object storage) menyimpan berkas sebagai objek yang diakses melalui API HTTP, dan wadahnya disebut bucket. Siapa yang boleh membaca sebuah objek ditentukan oleh kebijakan akses layanan, bukan oleh kode aplikasi. ACL public-read membuat seluruh objek dapat dibaca siapa pun yang mengetahui alamatnya, sedangkan daftar isi (listing) yang terbuka mempermudah penemuan karena nama seluruh objek dapat dihitung tanpa menebak. Arsip cadangan dan berkas unggahan pengguna adalah isi yang paling sering ditemukan pada bucket semacam ini.

Dampaknya berlapis: data yang tidak dimaksudkan untuk publik menjadi terbaca, salinan cadangan basis data sering menjadi bagian yang paling mahal harganya, dan pengunduhan berulang oleh pihak lain menaikkan biaya penyimpanan. Enkripsi at-rest yang mati menambah lapisan masalah karena objek tersimpan dalam bentuk polos pada media penyimpanan, padahal prinsip penyimpanan kriptografis menyarankan data sensitif dienkripsi saat disimpan. Kebijakan baca publik kadang memang diperlukan untuk aset statis situs, tetapi keputusannya harus diambil secara sadar dan terbatas pada objek yang memang disiapkan untuk publik.

Endpoint metadata instance#

Instance cloud dapat menanyakan informasi tentang dirinya melalui HTTP ke alamat link-local 169.254.169.254 yang disebut endpoint metadata. Jawabannya memuat nama instance, konfigurasi jaringan, dan pada banyak platform juga kredensial sementara untuk layanan cloud. Alamat ini hanya terjangkau dari dalam instance, sehingga tidak dapat diuji dari luar. Topik SSRF pada modul Kontrol Akses yang Rusak memperlihatkan cara server dijadikan proxy untuk mencapai alamat tersebut tanpa akses langsung.

Versi pertama endpoint ini menjawab permintaan GET secara langsung, sehingga satu permintaan sederhana sudah cukup membocorkan isinya. Versi kedua, yang umum dikenal sebagai IMDSv2, mengubah aturannya: token sesi harus diperoleh lebih dahulu melalui permintaan PUT, kemudian token itu dikirim pada header setiap permintaan GET berikutnya dengan masa berlaku terbatas. Payload SSRF sederhana yang hanya mengirim GET tidak lagi memperoleh kredensial karena tidak membawa token. Permintaan berikut menunjukkan bentuk versi pertama dan tetap berguna untuk memastikan versi yang aktif pada instance milik sendiri.

bash
# tidak-dijalankan
# endpoint metadata hanya terjangkau dari dalam instance yang diizinkan
curl http://169.254.169.254/latest/meta-data/

CORS yang terlalu longgar#

Browser memblokir pembacaan respons lintas origin sebagai bagian dari kebijakan same-origin, dan CORS (Cross-Origin Resource Sharing) adalah mekanisme yang digunakan server untuk menyatakan pengecualian tersebut melalui header. Nilai Access-Control-Allow-Origin: * berarti setiap situs boleh membaca responsnya. Masalah muncul bila nilai itu disandingkan dengan Access-Control-Allow-Credentials: true, karena respons yang menyertai cookie atau token menjadi layak dibaca oleh situs mana pun, termasuk milik penyerang. Refleksi header Origin permintaan tanpa daftar izin menghasilkan kebocoran yang setara.

Ketiga konfigurasi di atas dapat dinilai secara mekanis dari berkas kebijakan. Skrip berikut membaca kebijakan JSON lalu menandai tiga kondisi berisiko, yaitu ACL public-read, enkripsi at-rest yang mati, dan origin wildcard (tanda bintang yang berarti semua origin) yang disandingkan dengan kredensial. Simpan dua berkas berikut dalam satu folder, lalu jalankan dengan perintah python3 auditor-penyimpanan.py.

json kebijakan.json
{
  "bucket": "arsip-catatan",
  "acl": "public-read",
  "enkripsi_aktif": false,
  "cors": [
    {
      "origin": "*",
      "methods": ["GET", "PUT"],
      "credentials": true
    }
  ]
}
python auditor-penyimpanan.py
"""Auditor konfigurasi penyimpanan cloud dan CORS.

Membaca berkas kebijakan berformat JSON, lalu menandai tiga kondisi
berisiko: ACL bucket public-read, enkripsi at-rest yang mati, dan
aturan CORS dengan origin wildcard "*" yang disandingkan dengan kredensial.
Setiap temuan dicetak satu baris beserta alasannya.
"""

import json
import sys


def audit_bucket(konfigurasi):
    temuan = []
    if konfigurasi.get("acl") == "public-read":
        temuan.append('ACL "public-read": seluruh pengguna anonim dapat membaca isi bucket')
    if not konfigurasi.get("enkripsi_aktif", False):
        temuan.append("enkripsi at-rest mati: objek tersimpan dalam bentuk tidak terenkripsi")
    return temuan


def audit_cors(aturan_list):
    temuan = []
    for aturan in aturan_list:
        origin = aturan.get("origin", "")
        credentials = aturan.get("credentials", False)
        if origin == "*" and credentials:
            temuan.append(
                'CORS origin "*" bersama credentials true: situs mana pun '
                "dapat membaca respons berkredensial atas nama pengguna"
            )
    return temuan


def utama():
    berkas = sys.argv[1] if len(sys.argv) > 1 else "kebijakan.json"
    with open(berkas, encoding="utf-8") as sumber:
        konfigurasi = json.load(sumber)
    print(f"== Auditor konfigurasi penyimpanan dan CORS: {berkas} ==")
    temuan = audit_bucket(konfigurasi) + audit_cors(konfigurasi.get("cors", []))
    if temuan:
        for item in temuan:
            print(f"TEMUAN  {item}")
    else:
        print("TEMUAN  tidak ada; seluruh pemeriksaan lolos")
    print(f"== {len(temuan)} temuan dari 3 pemeriksaan ==")


utama()
text Keluaran
== Auditor konfigurasi penyimpanan dan CORS: kebijakan.json ==
TEMUAN  ACL "public-read": seluruh pengguna anonim dapat membaca isi bucket
TEMUAN  enkripsi at-rest mati: objek tersimpan dalam bentuk tidak terenkripsi
TEMUAN  CORS origin "*" bersama credentials true: situs mana pun dapat membaca respons berkredensial atas nama pengguna
== 3 temuan dari 3 pemeriksaan ==

Keluaran mencantumkan setiap temuan beserta alasannya dalam urutan yang tetap, sehingga laporan itu dapat langsung diterjemahkan menjadi tugas perbaikan. Dua baris pertama berasal dari pengaturan bucket, sedangkan baris ketiga berasal dari aturan CORS. Auditor semacam ini bukan pengganti tinjauan manual, tetapi cukup untuk menangkap nilai bawaan yang luput dari peninjauan.

Versi perbaikan membatasi origin pada satu situs yang benar-benar memerlukan akses, mengubah ACL menjadi private, dan mengaktifkan enkripsi. Simpan berkas perbaikan berikut, lalu jalankan kembali auditor atas kebijakan barunya.

json kebijakan-perbaikan.json
{
  "bucket": "arsip-catatan",
  "acl": "private",
  "enkripsi_aktif": true,
  "cors": [
    {
      "origin": "https://dashboard.catatan.example",
      "methods": ["GET"],
      "credentials": true
    }
  ]
}
bash
# menjalankan auditor atas kebijakan hasil perbaikan
python3 auditor-penyimpanan.py kebijakan-perbaikan.json
text Keluaran
== Auditor konfigurasi penyimpanan dan CORS: kebijakan-perbaikan.json ==
TEMUAN  tidak ada; seluruh pemeriksaan lolos
== 0 temuan dari 3 pemeriksaan ==

Dengan origin yang tercantum eksplisit, kredensial tetap boleh dikirim karena hanya situs tersebut yang dapat membaca responsnya. Enkripsi yang aktif menutup risiko pada media penyimpanan, sedangkan ACL private mengembalikan keputusan akses kepada kebijakan yang ditinjau.

Kesalahan umum#

Kesalahan berikut lazim terjadi pada konfigurasi cloud dan penyimpanan.

  • Menganggap bucket tersembunyi selama alamatnya tidak dipublikasikan. Nama bucket dapat ditebak dan sering terbocor dari log, kode klien, maupun repositori, sehingga kuncinya ada pada kebijakan akses dan bukan pada kerahasiaan alamat.
  • Mengatur CORS terlalu longgar untuk menghilangkan error browser secepat mungkin. Perbaikan yang benar adalah mencantumkan origin eksplisit yang benar-benar memerlukan akses.
  • Menguji endpoint metadata dari mesin kerja. Alamat link-local hanya bermakna dari dalam instance, sehingga pengujian dilakukan pada instance milik sendiri yang diizinkan.
  • Membiarkan daftar isi terbuka pada bucket aset statis. Nama berkas internal ikut terbaca, padahal aset publik cukup dijangkau melalui alamat langsung.

Ringkasan#

  • Bucket terbuka, endpoint metadata, dan CORS longgar adalah miskonfigurasi yang bersumber dari kebijakan layanan, bukan dari kode aplikasi, dan termasuk kategori A02 pada OWASP Top 10:2025.
  • IMDSv2 menuntut token dari permintaan PUT sebelum kredensial metadata dikirim, sehingga payload GET sederhana tidak lagi cukup untuk membocorkannya.
  • Auditor kecil atas berkas kebijakan menandai ACL public-read, enkripsi yang mati, dan origin wildcard bersama kredensial secara deterministik, lengkap dengan alasannya.

Referensi#