Alasan kami peduli: kami adalah Geonode dan kami menjual layanan proxy, sehingga kami sering menjumpai banyak perintah yang berisi kredensial — seringkali kata sandi proxy dan kata sandi target tercantum dalam satu baris yang sama. Peringatan praktis yang perlu disampaikan di awal adalah bahwa kredensial dalam perintah curl akan tersimpan dalam riwayat shell, daftar proses, dan apa pun yang Anda tempelkan ke dalam tiket dukungan. Kami telah menerima tangkapan layar yang berisi kata sandi aktif lebih dari sekali. Pendekatan “.netrc” di bawah ini dapat mengatasi masalah ini dalam waktu sekitar satu menit dan tidak memerlukan biaya apa pun, serta berlaku sama untuk kredensial proxy, yang dibahas di bagian akhir.
Sintaks Dasar
curl -u username:password https://api.example.com/private
Panduan curl menjelaskan -u, --user <user:password>
: "Tentukan nama pengguna dan kata sandi yang akan digunakan untuk otentikasi server."
Basic adalah skema default, sehingga --basic
biasanya berlebihan. Manual tersebut menjelaskan hal ini: "Gunakan otentikasi HTTP Basic dengan host jarak jauh. Metode ini adalah default dan opsi ini biasanya tidak berguna, kecuali jika Anda menggunakannya untuk mengganti opsi yang telah ditetapkan sebelumnya yang menetapkan metode otentikasi yang berbeda."
Yang sebenarnya dikirim melalui jaringan adalah sebuah header:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Itu adalah username:password
yang dikodekan dengan base64 — dikodekan, bukan dienkripsi. Siapa pun yang dapat melihat permintaan tersebut dapat mendekodekannya dalam satu langkah. Inilah mengapa otentikasi Basic melalui HTTP biasa setara dengan mengirimkan kata sandi Anda dalam teks biasa, dan mengapa metode ini seharusnya hanya digunakan melalui HTTPS.
Satu batasan sintaksis dari manual: "Nama pengguna dan kata sandi dipisahkan oleh tanda titik dua pertama, yang membuatnya tidak mungkin menggunakan tanda titik dua dalam nama pengguna dengan opsi ini. Kata sandi masih boleh." Jadi, tanda titik dua dalam kata sandi diperbolehkan; tanda titik dua dalam nama pengguna tidak diperbolehkan.
Mengapa Baris Perintah Bukan Tempat yang Tepat
Buku panduan tidak berbelit-belit mengenai hal ini:
Pada sistem di mana fitur ini berfungsi, curl menyembunyikan argumen opsi yang diberikan dari daftar proses. Hal ini tidak cukup untuk melindungi kredensial agar tidak terlihat oleh pengguna lain di sistem yang sama, karena kredensial tersebut masih terlihat sejenak sebelum dihapus. Data sensitif semacam itu sebaiknya diambil dari berkas atau sumber serupa, dan tidak boleh digunakan dalam bentuk teks biasa di baris perintah.
Empat jenis paparan data yang berbeda, semuanya nyata:
Riwayat shell. ~/.bash_history atau setara zsh, dalam teks biasa, tanpa batas waktu.
Daftar proses. Terlihat oleh pengguna lain di mesin tersebut selama jendela waktu singkat sebelum curl menghapusnya.
Log. Apa pun yang mencatat perintah yang dijalankan oleh skrip.
Output yang disalin. Laporan bug, pelacak masalah, pesan obrolan, tangkapan layar.
Yang terakhir adalah yang paling umum terjadi dalam praktiknya dan paling jarang dipertimbangkan.
Tiga Cara yang Lebih Aman
1. Biarkan curl meminta masukan. Cukup berikan nama pengguna, dan curl akan meminta kata sandi secara interaktif, membacanya tanpa menampilkan karakter yang diketik:
curl -u username https://api.example.com/private
Tidak ada yang disimpan, tidak ada yang dicatat. Ini adalah pendekatan yang tepat untuk apa pun yang Anda ketik secara manual.
**2. Gunakan berkas .netrc
.** Manual menjelaskan perintah ``-n, --netrc`
`: "Membuat curl memindai berkas .netrc di direktori home pengguna untuk mencari nama login dan kata sandi... Jika digunakan dengan HTTP, curl mengaktifkan otentikasi pengguna."
Buat berkas ~/.netrc
:
machine api.example.com
login myusername
password mypassword
Kemudian batasi aksesnya, karena curl tidak akan melakukannya untuk Anda — manual mencatat bahwa "curl tidak akan memberikan peringatan jika berkas tersebut tidak memiliki izin yang benar (berkas tersebut tidak boleh dapat dibaca oleh semua orang maupun oleh grup)":
chmod 600 ~/.netrc
curl -n https://api.example.com/private
Tiga detail berguna dari manual. “Berkas netrc menyediakan kredensial untuk nama host terlepas dari protokol dan nomor port yang digunakan”, sehingga satu entri mencakup satu host. --netrc-file
“menggantikan semua cara lain untuk menentukan berkas tersebut”, yang berguna untuk berkas kredensial per-proyek. Dan sejak curl 8.16.0, variabel lingkungan ``NETRC`
dapat menentukan nama berkas tersebut. Di Windows, baik ``.netrc
maupun ``_netrc
` diperiksa di direktori home, dengan yang pertama lebih diutamakan.
``--netrc-optional`
` adalah varian yang menggunakan berkas tersebut jika ada dan tidak gagal jika tidak ada — lebih baik untuk skrip yang mungkin berjalan dalam kedua kondisi tersebut.
3. Membaca dari variabel lingkungan. Jika menggunakan berkas tidak praktis, setidaknya hindari pencatatan dalam riwayat:
read -rs API_PASS
curl -u "myuser:${API_PASS}" https://api.example.com/private
Perhatikan penggunaan ``-s`
pada ``read
` agar kata sandi tidak ditampilkan. Hal ini tetap terlihat dalam lingkungan proses, sehingga ini merupakan opsi tengah daripada opsi yang baik.
Untuk skrip, gunakan ``.netrc`
dengan ``chmod 600
`. Ini adalah opsi yang direkomendasikan dalam manual dan yang menghilangkan semua risiko paparan yang disebutkan di atas.
Skema Basic versus Skema Lainnya
curl mendukung beberapa skema, dan mengetahui perbedaan masing-masing skema dapat mencegah terjadinya kebingungan.
| Opsi | Skema | Kata sandi saat dikirim |
|---|---|---|
--basic | HTTP Basic (default) | Dienskripsi dengan Base64, secara efektif tidak terenkripsi |
--digest | HTTP Digest | Tantangan-respons yang di-hash |
--ntlm | NTLM | Lingkungan Windows |
--negotiate | SPNEGO / Kerberos | Berbasis tiket |
--anyauth | Otomatis | Tergantung pada pilihan |
--oauth2-bearer | Token Bearer | Token itu sendiri |
Digest didokumentasikan sebagai: "Aktifkan otentikasi HTTP Digest. Skema otentikasi ini menghindari pengiriman kata sandi melalui jaringan dalam bentuk teks biasa. Gunakan ini bersama dengan opsi --user biasa untuk mengatur nama pengguna dan kata sandi."
--anyauth adalah opsi praktis dengan konsekuensi yang dijelaskan secara jelas dalam manual: "Tentukan metode otentikasi secara otomatis, dan gunakan yang paling aman yang diklaim didukung oleh situs jarak jauh. Hal ini dilakukan dengan terlebih dahulu mengirimkan permintaan dan memeriksa header respons, sehingga berpotensi menimbulkan satu kali perjalanan jaringan tambahan."
Satu kali perjalanan jaringan tambahan per permintaan tidak gratis jika dilakukan dalam volume besar. Dan ada kegagalan spesifik yang diperingatkan dalam manual: "Penggunaan --anyauth tidak disarankan jika Anda melakukan unggahan dari stdin, karena hal ini mungkin mengharuskan data dikirim dua kali dan klien harus mampu memutar balik data. Jika hal ini diperlukan saat mengunggah dari stdin, operasi unggahan akan gagal."
Jadi: gunakan --anyauth ketika Anda benar-benar tidak tahu apa yang diinginkan server, dan tentukan skemanya begitu Anda mengetahuinya.
Token Bearer adalah yang sebenarnya digunakan oleh sebagian besar API modern, dan token ini sama sekali bukan otentikasi dasar:
curl --oauth2-bearer "mF_9.B5f-4.1JqM" https://api.example.com/me
Setara dengan mengatur Authorization: Bearer ... secara manual. Perhatikan bahwa token Bearer adalah kredensial itu sendiri — siapa pun yang memilikinya dapat menggunakannya — sehingga perlu ditangani dengan cara yang sama seperti kata sandi.
Membaca Respons
Langkah diagnostik singkat saat otentikasi tidak berhasil.
**401 Unauthorized
** berarti server meminta kredensial, atau menolak kredensial yang Anda kirimkan. Respons tersebut memuat header WWW-Authenticate
yang menyebutkan skema yang diharapkan, dan dengan membacanya, Anda tidak perlu menebak-nebak:
curl -sS -o /dev/null -D - https://api.example.com/private | grep -i www-authenticate
Jika tertulis Digest
dan Anda mengirimkan Basic, itulah jawabannya.
**403 Forbidden
** berbeda dan sering disalahartikan. Anda telah berhasil melakukan otentikasi, tetapi tidak diizinkan untuk melakukan ini. Mengubah kata sandi tidak akan membantu; mengubah izin Anda mungkin bisa membantu.
**407 Proxy Authentication Required
** berarti proxy meminta kredensial, bukan server tujuan. Header yang berbeda, opsi yang berbeda, akan dibahas selanjutnya.
**A 200
dengan halaman login** berarti endpoint tersebut sama sekali tidak menggunakan otentikasi HTTP — ia menggunakan formulir dan cookie sesi, dan -u
tidak berpengaruh apa-apa di sini. Periksa Content-Type
: jika Anda mengharapkan JSON dan mendapatkan text/html
, kemungkinan besar inilah yang terjadi.
Untuk memastikan apa yang sebenarnya Anda kirimkan:
curl -v -u user:pass https://api.example.com/private 2>&1 | grep -i '^> authorization'
Ingat peringatan dalam panduan bahwa output terperinci "mungkin berisi data sensitif, termasuk nama pengguna, kredensial, atau konten data rahasia" — sensor sebelum membagikannya.
Membuat Header Sendiri
Terkadang -u
tidak sesuai dengan yang Anda inginkan, dan dengan mengetahui hasil yang sebenarnya dihasilkan, Anda dapat mengatasi keterbatasannya.
Ketika nama pengguna mengandung tanda titik dua. -u
memisahkan berdasarkan tanda titik dua pertama, sehingga nama pengguna seperti service:reader
tidak dapat diekspresikan. Buat header secara langsung:
CRED=$(printf '%s' 'service:reader:mypassword' | base64 -w0)
curl -H "Authorization: Basic ${CRED}" https://api.example.com/private
Perhatikan printf
daripada echo
, yang menambahkan baris baru yang akhirnya masuk ke dalam kredensial yang dikodekan dan menghasilkan kesalahan 401 yang membingungkan. Dan gunakan base64 -w0
untuk mencegah pemotongan baris — GNU base64
secara default memotong baris pada 76 karakter, dan header dengan baris baru yang tertanam dianggap sebagai permintaan yang tidak valid. Di macOS, base64
tanpa tambahan apa pun tidak akan memotong baris, sehingga bendera tersebut tidak diperlukan.
Saat Anda memerlukan kredensial dari pengelola rahasia. Sebagian besar alat pengelola rahasia menampilkan hasilnya ke stdout, dan menyimpan nilainya dalam variabel alih-alih berkas membatasi masa pakainya:
TOKEN=$(vault kv get -field=token secret/api)
curl -H "Authorization: Bearer ${TOKEN}" https://api.example.com/me
Saat Anda ingin header tersebut berada di berkas konfigurasi daripada di perintah. curl membaca opsi dari ~/.curlrc` `, atau dari berkas yang dinamai dengan -K : `
# api-auth.conf
--user "myuser:mypassword"
--header "Accept: application/json"
curl -K api-auth.conf https://api.example.com/private
`
Batasi berkas tersebut dengan chmod 600` `. Ini merupakan solusi tengah yang wajar saat .netrc tidak sesuai — misalnya saat Anda memerlukan token daripada nama pengguna dan kata sandi.
Peringatan khusus mengenai ~/.curlrc
. Pengaturan ini berlaku untuk setiap panggilan curl yang dilakukan oleh pengguna tersebut, termasuk yang tidak Anda tulis. Menyimpan kredensial di sana berarti mengirimkannya ke host mana pun yang diminta oleh skrip apa pun. Gunakan berkas bernama dengan -K
untuk informasi sensitif, dan gunakan ~/.curlrc
untuk pengaturan default yang tidak berbahaya seperti --show-error
dan --location
.
Otentikasi Proksi Dilakukan Secara Terpisah
Perbedaan inilah yang paling sering menimbulkan kebingungan di antrean dukungan kami.
Dua set kredensial yang independen mungkin terlibat: satu untuk proxy, satu untuk target. Keduanya menggunakan header yang berbeda, kode status yang berbeda, dan opsi curl yang berbeda.
curl -x http://proxy.example.com:9000 \
--proxy-user proxyuser:proxypass \
-u apiuser:apipass \
https://api.example.com/private
--proxy-user
melakukan otentikasi ke proxy; -u
melakukan otentikasi ke target. Jika keduanya tertukar, akan muncul kode status 407 padahal Anda mengharapkan 401, atau sebaliknya.
Skema proxy memiliki opsi yang sejajar — --proxy-basic
, --proxy-digest
, --proxy-anyauth
, --proxy-negotiate
— yang mencerminkan opsi di sisi target.
Dua catatan praktis.
Kredensial dalam URL proxy memiliki masalah paparan yang sama, ditambah satu lagi. -x http://user:pass@proxy:9000
menempatkan kata sandi di baris perintah dan di variabel lingkungan mana pun yang menyimpan URL proxy, yang biasanya merupakan tempat http_proxy
berada. Lakukan pengkodean persentase (percent-encode) pada setiap @
, :
, atau /
dalam kata sandi, atau parser URL akan memisahkannya di tempat yang salah.
Bedakan hop mana yang menolak Anda daripada menebak-nebak:
curl -sS -o /dev/null -x "$PROXY" \
-w 'connect=%{http_connect} status=%{response_code}\n' \
https://api.example.com/private
connect=407
berarti proxy menolak Anda dan tidak pernah mencapai target. connect=200 status=401
berarti proxy berfungsi dan target meminta kredensial. Dua solusi yang berbeda.
Dan catatan khusus mengenai otentikasi proxy: banyak penyedia menawarkan daftar putih IP sebagai alternatif dari nama pengguna dan kata sandi. Jika alamat sumber Anda stabil, hal ini akan menghilangkan kredensial dari perintah Anda sepenuhnya, yang merupakan solusi paling bersih yang tersedia — tanpa berkas, tanpa variabel lingkungan, dan tidak ada yang bisa bocor.
Ketika Situs Sama Sekali Tidak Menggunakan Otentikasi HTTP
Sebagian besar laporan "curl basic auth tidak berfungsi" merupakan kasus di mana situs tersebut memang tidak pernah menggunakan otentikasi HTTP sejak awal.
Cara mengetahuinya. Kirim permintaan ke URL yang dilindungi tanpa kredensial dan perhatikan responsnya:
curl -sS -o /dev/null -D - https://example.com/dashboard
401
dengan header WWW-Authenticate
menandakan adanya otentikasi HTTP, dan -u
adalah alat yang tepat. Jika 200
menampilkan halaman login, atau 302
mengalihkan ke /login
, berarti situs tersebut menggunakan formulir dan cookie sesi — dan seberapa sering pun Anda menggunakan -u
tidak akan membantu, karena tidak ada yang membaca header tersebut.
Pola login berbasis formulir sebagai gantinya. Kirimkan kredensial ke titik akhir login, simpan cookie-nya, dan gunakan kembali:
curl -c jar.txt -d "username=ada&password=secret" \
https://example.com/login
curl -b jar.txt https://example.com/dashboard
-c
menulis cookie ke "cookie jar" dan -b
membacanya. Gunakan keduanya pada permintaan berikutnya (-b jar.txt -c jar.txt
) jika server mengganti cookie sesi, yang sering dilakukan oleh banyak server.
Masalah yang akan Anda hadapi: token CSRF. Sebagian besar formulir login menyertakan token tersembunyi yang harus dikirimkan bersama kredensial, dan token ini dihasilkan per sesi. Artinya, diperlukan urutan dua langkah — ambil formulir, ekstrak token, lalu kirimkan bersama cookie dari langkah pertama:
TOKEN=$(curl -sS -c jar.txt https://example.com/login \
| grep -o 'name="csrf_token" value="[^"]*"' \
| cut -d'"' -f4)
curl -b jar.txt -c jar.txt \
-d "csrf_token=${TOKEN}" -d "username=ada" -d "password=secret" \
https://example.com/login
Penggunaan grep dan pemotongan pada HTML rentan, dan hal ini hanya cocok untuk diagnosis satu kali. Untuk hal yang berkelanjutan, periksa terlebih dahulu apakah layanan tersebut menawarkan API dengan otentikasi token — hampir selalu demikian, dan ini akan jauh lebih mudah daripada memelihara scraper untuk formulir login Anda sendiri.
Dan jika proses login memerlukan JavaScript, curl sama sekali tidak dapat melakukannya. Ini bukanlah batasan curl yang perlu diatasi; ini adalah sinyal untuk mencari titik akhir API yang dipanggil oleh halaman itu sendiri, yang dapat Anda temukan di tab jaringan browser Anda dan direproduksi secara langsung.
Pertanyaan Lainnya
Bagaimana cara menggunakan otentikasi dasar (basic authentication) dengan curl?
curl -u username:password URL. Basic adalah skema default curl, jadi --basic bersifat berlebihan kecuali jika Anda mengganti metode yang telah ditetapkan sebelumnya. Selalu gunakan HTTPS, karena otentikasi dasar mengenkode kredensial menggunakan base64, bukan mengenkripsinya.
Bagaimana cara membuat curl meminta kata sandi?
Cukup berikan nama pengguna saja: curl -u username URL. curl akan meminta kata sandi secara interaktif dan tidak menampilkannya, sehingga tidak ada yang terekam dalam riwayat shell atau daftar proses Anda. Ini adalah pendekatan yang tepat untuk segala sesuatu yang diketik secara manual.
Apakah otentikasi dasar curl aman?
Hanya melalui HTTPS. Kredensial dienkode dengan base64, yang dapat dibalik dengan mudah, sehingga melalui HTTP biasa, kredensial tersebut secara efektif berada dalam teks biasa. Melalui TLS, transportasi melindungi kredensial tersebut, dan risiko yang tersisa terletak pada tempat Anda menyimpannya di mesin Anda sendiri.
Bagaimana cara menyimpan kredensial curl dalam berkas?
Gunakan perintah ~/.netrc dengan baris machine, login, dan password, lalu jalankan chmod 600 dan panggil curl dengan -n. curl tidak memberikan peringatan tentang izin yang salah, jadi Anda harus mengaturnya sendiri. --netrc-file mengarah ke lokasi alternatif, dan --netrc-optional mencegah kegagalan saat berkas tidak ada.
Mengapa curl mengembalikan kode 401 padahal kata sandi saya benar?
Ada beberapa kemungkinan: server mengharapkan skema yang berbeda — periksa header WWW-Authenticate — atau titik akhir (endpoint) menggunakan login formulir dengan cookie alih-alih otentikasi HTTP, atau nama pengguna Anda mengandung tanda titik dua, yang tidak dapat diekspresikan oleh -u karena memisahkan pada tanda titik dua pertama.
Apa perbedaan antara 401 dan 403?
Kode 401 berarti Anda belum terotentikasi: tidak ada kredensial, atau kredensial yang salah. Kode 403 berarti Anda telah berhasil terotentikasi tetapi tidak diizinkan melakukan hal ini. Mencoba lagi dengan kredensial yang berbeda akan membantu pada kasus pertama, tetapi tidak pada kasus kedua.
Bagaimana cara melakukan otentikasi ke proxy menggunakan curl?
Gunakan --proxy-user user:password, yang terpisah dari -u untuk target. Status 407 berarti proxy meminta kredensial; 401 berarti targetnya yang meminta. Jika alamat sumber Anda stabil, tanyakan kepada penyedia layanan Anda tentang daftar putih IP — ini akan menghilangkan kebutuhan kredensial dari perintah Anda sepenuhnya.
Apa fungsi opsi --anyauth?
Opsi ini membuat curl mendeteksi skema yang disukai server dengan mengirimkan permintaan dan membaca header respons, lalu melakukan otentikasi menggunakan metode paling aman yang ditawarkan. Biayanya adalah satu kali perjalanan bolak-balik tambahan per permintaan, dan panduan pengguna memperingatkan bahwa hal ini dapat gagal saat mengunggah dari stdin karena data mungkin perlu dikirim dua kali.
Kesimpulan
Sintaksnya cukup sederhana: -u username:password dan Anda sudah terotentikasi, dengan skema basic sebagai pengaturan default curl. Bagian yang perlu diperhatikan dengan benar adalah di mana kata sandi disimpan.
Manual curl sendiri sangat jelas mengenai hal ini — kredensial "sebaiknya diambil dari file atau yang serupa dan jangan pernah digunakan dalam teks biasa di baris perintah" — dan risiko kebocoran yang diperingatkannya semuanya nyata. Riwayat shell menyimpannya tanpa batas waktu, daftar proses memaparkannya sebentar kepada siapa pun di mesin tersebut, dan hasil terminal yang disalin memiliki kemampuan aneh untuk sampai ke tempat-tempat yang tidak Anda maksudkan.
Dua kebiasaan dapat mengatasi hal ini. Untuk penggunaan interaktif, berikan hanya nama pengguna dan biarkan curl meminta kata sandi. Untuk skrip, simpan kredensial di ~/.netrc dengan chmod 600 dan gunakan -n. Keduanya tidak memakan waktu lebih lama daripada mengetik kata sandi itu sendiri.
Dan pastikan Anda memahami perbedaan antara kedua lapisan otentikasi ini. Kode status 401 berasal dari server tujuan dan memerlukan -u; sedangkan kode status 407 berasal dari proxy dan memerlukan --proxy-user. Jika alamat Anda stabil, daftar putih (allowlist) akan menghilangkan kredensial kedua dari perintah Anda sepenuhnya — yang merupakan satu-satunya tempat yang benar-benar aman untuk menyimpan rahasia.
