View a markdown version of this page

Paket gating pada usia versi - CodeArtifact

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Paket gating pada usia versi

penting

Version age gating tidak melindungi terhadap kerentanan yang ditemukan di versi yang ada yang telah melewati jendela karantina. Gunakan CodeArtifact dengan Amazon Inspector untuk pemindaian kerentanan paket yang sudah ada.

Ketika versi paket dipublikasikan ke registri publik, registri mencatat stempel waktu publikasi. CodeArtifact mempertahankan stempel waktu hulu asli ini saat menyimpan paket dari koneksi eksternal. Anda dapat membaca stempel waktu ini di CI/CD pipeline Anda dan menolak versi yang diterbitkan terlalu baru.

Sebagian besar paket berbahaya terdeteksi dan dihapus dalam beberapa jam setelah publikasi. Jendela karantina 3 hingga 7 hari memblokir sebagian besar serangan rantai pasokan, termasuk kebingungan ketergantungan, pengambilalihan akun pengelola, dan kesalahan ketik.

catatan

Contoh dalam topik ini menanyakan URL CodeArtifact repositori, yang merupakan titik akhir yang sama yang digunakan manajer paket Anda untuk mengunduh paket. Semua permintaan memerlukan otentikasi. Lulus token CodeArtifact otorisasi yang valid di Authorization: Bearer header. Untuk mendapatkan token, jalankan aws codeartifact get-authorization-token (lihat CI/CD contoh nanti dalam topik ini untuk pemanggilan lengkap dengan --domain dan--domain-owner).

Jangan gunakan publishedTime bidang yang dikembalikan aws codeartifact describe-package-version untuk gerbang usia. Bidang ini dihuni pada waktu konsumsi. Untuk catatan di mana waktu publikasi hulu asli tidak ditangkap (termasuk paket yang dicerna sebelum pengambilan stempel waktu per artefak diperkenalkan, dan jalur konsumsi tertentu), itu diam-diam jatuh kembali ke waktu terakhir rekaman yang diperbarui. Respons API tidak menunjukkan nilai mana dari dua nilai yang Anda baca, jadi Anda tidak dapat mengandalkannya sebagai tanggal publikasi hulu. Gunakan bidang per format yang dijelaskan dalam topik ini sebagai gantinya.

Detail per format berbeda, tetapi pola gating sama untuk setiap format: baca stempel waktu publikasi hulu untuk setiap versi yang diselesaikan, bandingkan dengan batas waktu karantina Anda (waktu saat ini dikurangi jendela yang Anda pilih), dan gagal membangun jika ada versi yang lebih baru dari cutoff. Jika Anda menggunakan lebih dari satu format paket, Anda menerapkan pola yang sama dengan bidang khusus format yang ditunjukkan di bawah ini.

npm

CodeArtifact mengembalikan stempel waktu publikasi npmjs.org asli untuk setiap versi di bidang paket npm. time Banyak manajer paket dan alat keamanan membaca bidang ini secara asli. Ini termasuk npmMinimalAgeGate opsi Yarn 4, minimumReleaseAge pengaturan Renovate, dan minimumReleaseAge pengaturan pnpm, yang semuanya berfungsi tanpa CodeArtifact modifikasi.

Permintaan:

curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \ https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/npm/my-repo/axios

Tanggapan (disingkat):

{ "name": "axios", "time": { "1.6.0": "2023-10-26T21:15:55.685Z", "1.6.5": "2024-01-05T19:52:15.051Z", "1.7.0": "2024-05-19T20:25:03.615Z", "1.7.1": "2024-05-20T13:32:52.757Z", "1.7.2": "2024-05-21T16:58:04.163Z" } }

Bidang kunci: time["<version>"] — nilainya adalah tanggal publikasi asli dari npmjs.org. Misalnya, time["1.7.2"] return2024-05-21T16:58:04.163Z, yang merupakan stempel waktu yang tepat yang direkam oleh npmjs.org saat versi tersebut diterbitkan. Untuk menentukan usia, bandingkan nilai ini dengan waktu saat ini dikurangi jendela karantina Anda.

Maven

Untuk artefak Maven, CodeArtifact mengembalikan stempel waktu publikasi Maven Central asli di header respons Last-Modified HTTP saat Anda mengunduh file (JAR, POM, atau artefak lainnya).

Permintaan:

curl -I -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \ https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/maven/my-repo/\ org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.pom

Header respons:

HTTP/2 200 content-type: application/xml Last-Modified: Fri, 26 Feb 2021 20:40:52 GMT content-length: 22672

Bidang kunci: Last-Modified header - ini adalah tanggal penerbitan asli dari Maven Central. Bandingkan dengan batas karantina Anda untuk menentukan apakah artefak itu terlalu baru.

catatan

<lastUpdated>Bidang di dalamnya maven-metadata.xml mencerminkan kapan CodeArtifact terakhir menyegarkan cache-nya, bukan tanggal publikasi hulu. Jangan gunakan maven-metadata.xml stempel waktu untuk gerbang usia.

NuGet

Untuk NuGet paket, CodeArtifact mengembalikan stempel waktu publikasi nuget.org asli di published bidang respons pendaftaran V3.

Permintaan:

curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \ https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/nuget/my-repo/\ v3/registration4/newtonsoft.json/index.json

Respon (disingkat, menampilkan satu versi):

{ "items": [{ "items": [{ "catalogEntry": { "id": "Newtonsoft.Json", "version": "13.0.3", "published": "2023-03-08T07:42:54.647+00:00", "listed": true } }] }] }

Bidang kunci: catalogEntry.published — ini adalah tanggal publikasi asli dari nuget.org. Misalnya, "2023-03-08T07:42:54.647+00:00" berarti Newtonsoft.Json 13.0.3 diterbitkan pada 8 Maret 2023.

Cargo (Kargo)

Untuk peti Cargo yang ditarik dari crates.io, CodeArtifact mempertahankan stempel waktu publikasi asli dalam respons crates.io V1 API. versions Kueri titik akhir API V1 agar peti dapat membaca stempel waktu per versi. created_at

Permintaan:

curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \ https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/cargo/my-repo/\ api/v1/crates/serde/versions

Bidang kunci: created_at Stempel waktu per versi dalam versions respons V1 adalah tanggal publikasi crates.io asli.

catatan

Cargo menggunakan protokol indeks jarang (<prefix>/<crate>) untuk resolusi ketergantungan normal. Indeks sparse mengembalikanvers,, cksumyanked, dan features untuk setiap versi, tetapi tidak menyertakan stempel waktu publikasi. Untuk mengatur dependensi Cargo berdasarkan usia, kueri API V1 yang ditunjukkan di atas dalam langkah terpisah dalam pipeline Anda. Standar cargo build dan cargo update perintah tidak memanggil API V1.

PyPI

Untuk paket Python, CodeArtifact mendukung PEP 691 (JSON Simple API) dan PEP 700, yang mencakup bidang untuk setiap file distribusi. upload-time

Permintaan:

curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \ -H "Accept: application/vnd.pypi.simple.v1+json" \ https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/pypi/my-repo/simple/requests/

Tanggapan (disingkat):

{ "files": [{ "filename": "requests-2.31.0-py3-none-any.whl", "upload-time": "2023-05-22T15:12:42.313790Z", "size": 62574, "url": "../../packages/requests/2.31.0/requests-2.31.0-py3-none-any.whl" }] }

Bidang kunci: upload-time — ini adalah tanggal publikasi asli dari PyPI. Alat seperti uv mendukung ini secara asli:

# Only install versions published before a specific date uv pip install --exclude-newer 2026-05-01T00:00:00Z -r requirements.txt
catatan

PEP 691 JSON API membutuhkan header. Accept: application/vnd.pypi.simple.v1+json HTML Simple API default tidak menyertakan stempel waktu.

Untuk file distribusi yang dicerna sebelum pengambilan waktu unggahan per artefak diperkenalkan (catatan lama), upload-time bidang mungkin tidak ada dalam entri di. files[] Logika gating Anda harus memperlakukan yang hilang upload-time sebagai versi yang tidak dapat diverifikasi, dan memutuskan apakah akan mengizinkan atau memblokirnya sesuai dengan kebijakan Anda.

Contoh: Gating paket npm di CI/CD

Skrip Python berikut membaca package-lock.json file, kueri CodeArtifact untuk stempel waktu publikasi dari setiap dependensi, dan keluar dengan status bukan nol jika ada versi yang diterbitkan dalam jendela karantina.

#!/usr/bin/env python3 """ gate_package_age.py - Block npm packages published too recently. Reads package-lock.json, queries CodeArtifact for each dependency's publish timestamp, and rejects versions newer than QUARANTINE_HOURS. Environment variables: CODEARTIFACT_AUTH_TOKEN - from `aws codeartifact get-authorization-token` CODEARTIFACT_NPM_ENDPOINT - from `aws codeartifact get-repository-endpoint` QUARANTINE_HOURS - minimum version age in hours (default: 72) """ import json, os, sys, urllib.request from datetime import datetime, timezone, timedelta def get_publish_time(endpoint, token, package, version): """Fetch the publish timestamp for a specific version from CodeArtifact.""" url = f"{endpoint.rstrip('/')}/{package}" req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"}) data = json.loads(urllib.request.urlopen(req, timeout=30).read()) time_str = data.get("time", {}).get(version) if not time_str: return None return datetime.fromisoformat(time_str.replace("Z", "+00:00")) token = os.environ["CODEARTIFACT_AUTH_TOKEN"] endpoint = os.environ["CODEARTIFACT_NPM_ENDPOINT"] quarantine_hours = int(os.environ.get("QUARANTINE_HOURS", "72")) cutoff = datetime.now(timezone.utc) - timedelta(hours=quarantine_hours) with open("package-lock.json") as f: lockfile = json.load(f) blocked = [] checked = 0 for path, info in lockfile.get("packages", {}).items(): if not path.startswith("node_modules/"): continue name = path.replace("node_modules/", "", 1) version = info.get("version") if not name or not version: continue checked += 1 pub_time = get_publish_time(endpoint, token, name, version) if pub_time and pub_time > cutoff: age_h = (datetime.now(timezone.utc) - pub_time).total_seconds() / 3600 blocked.append(f" {name}@{version} (age: {age_h:.0f}h, published {pub_time.isoformat()})") if blocked: print(f"BLOCKED: {len(blocked)} package(s) newer than {quarantine_hours} hours:") print("\n".join(blocked)) sys.exit(1) print(f"PASSED: all {checked} packages older than {quarantine_hours} hours.")

CI/CD integrasi:

# Step 1: Authenticate export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \ --domain my-domain --domain-owner 111122223333 \ --query authorizationToken --output text) export CODEARTIFACT_NPM_ENDPOINT=$(aws codeartifact get-repository-endpoint \ --domain my-domain --domain-owner 111122223333 \ --repository my-repo --format npm \ --query repositoryEndpoint --output text) # Step 2: Set quarantine window (72 hours = 3 days) export QUARANTINE_HOURS=72 # Step 3: Generate lockfile without installing npm install --package-lock-only # Step 4: Gate on age — fails if any dependency is too new python3 gate_package_age.py # Step 5: If gate passes, install npm ci

Contoh keluaran saat paket diblokir:

BLOCKED: 1 package(s) newer than 72 hours: evil-package@1.0.0 (age: 2h, published 2026-06-03T08:30:00+00:00)

Contoh keluaran saat semua paket lulus:

PASSED: all 847 packages older than 72 hours.

Serangan dikurangi

Jenis serangan Cara kerjanya Bagaimana gerbang usia membantu
Kebingungan ketergantungan Penyerang menerbitkan paket versi tinggi dengan nama yang sama dengan paket internal ke registri publik. Versi berbahaya adalah merek baru. Diblokir oleh jendela karantina.
Pengambilalihan akun Penyerang mengkompromikan kredensi pengelola dan menerbitkan pembaruan berbahaya (misalnya, event-stream). Versi baru diadakan. Komunitas mendeteksi dan mengembalikannya dalam periode karantina.
Typosquatting Penyerang menerbitkan paket dengan nama yang mirip dengan paket populer (misalnya, lodashs bukan). lodash Semua versi paket typosquat baru. Setiap versi diblokir.
Star-jacking Penyerang menyuntikkan malware ke dalam rilis patch dari paket sah yang mereka kendalikan. Patch berbahaya adalah versi yang baru diterbitkan. Diblokir sampai usia melewati jendela karantina.

Ringkasan format yang didukung

Format Tempat membaca mempublikasikan stempel waktu Bidang kunci Status
npm Respon paket () GET /<package> time["<version>"] Available
Maven Header respons HTTP pada unduhan artefak Last-Modified Available
NuGet Indeks pendaftaran V3 catalogEntry.published Available
kargo Respons versi API V1 created_at Available
PyPI PEP 691 JSON API Sederhana upload-time Tersedia