Bagaimana cara mengirim kata sandi dengan aman melalui HTTP?

115

Jika pada layar login pengguna mengirimkan formulir dengan nama pengguna dan kata sandi, kata sandi dikirim dalam teks biasa (bahkan dengan POST, koreksi saya jika saya salah).

Jadi pertanyaannya adalah bagaimana cara yang benar untuk melindungi pengguna dan kata sandinya dari pihak ketiga yang mungkin menguping data komunikasi?

Saya sadar bahwa HTTPS adalah solusi untuk masalah ini, tetapi adakah cara untuk memastikan setidaknya beberapa tingkat keamanan menggunakan protokol HTTP standar (permintaan POST)? (mungkin menggunakan javascript dalam beberapa cara)

EDIT Saya mungkin telah meninggalkan beberapa hal penting.

Apa yang saya tentang adalah halaman - yaitu halaman login yang dihasilkan PHP, yang tentu saja dikirim ke pengguna dalam permintaan HTTP GET sebagai file HTML. Tidak ada koneksi (@Jeremy Powel) yang dibuat antara server dan klien jadi saya tidak dapat membuat protokol handshaking seperti itu. Dan saya ingin proses lengkapnya transparan bagi pengguna - dia ingin mengirimkan kata sandi, bukan berurusan dengan kriptografi.

Terima kasih.

Kornelije Petak
sumber
1
Anda mungkin tidak akan dapat mencapai ini tanpa klien menggunakan kriptografi, tetapi pengguna tidak harus melihat proses seperti itu. Dia baru saja memasukkan kata sandinya dan kode yang dihasilkan PHP Anda (javascript misalnya) menangani semuanya untuk Anda.
Jeremy Powell
13
Masalah yang Anda jelaskan adalah alasan HTTPS ditemukan. Jika Anda mengirim rahasia ke klien untuk mengenkripsi kata sandi, penyadap akan dapat mengendusnya dan mendekripsi kata sandi pada perjalanan pulang.
jnoss
1
Jadi S dalam saran Anda hanya boleh kata sandi (atau nama pengguna + kata sandi digabungkan dengan cara apa pun), karena ini adalah satu-satunya "rahasia" yang dimiliki pengguna. Apakah saya benar? Jadi solusinya adalah sebagai berikut: - Server menyediakan halaman HTML dengan bidang formulir tersembunyi R - Pengguna memasukkan kata sandi, dan sebelum kata sandi dikirim, javascript menghitung H (R, S) dan mengirimkannya ke server, bahkan mungkin dengan menggunakan AJAX - Server menghitung H (R, S) dan membandingkannya dengan yang diterima dan mengirimkan respons ke permintaan ajax apakah otentikasi berhasil - Javascript mengalihkan browser ke halaman web yang diinginkan
Kornelije Petak
2
@jeremy powell - meskipun yang Anda jelaskan adalah praktik umum, ini juga rentan terhadap perantara yang dapat mengendus cookie dari header dan meniru pengguna dengan menggunakan kembali cookie. Serangan orang di tengah sulit untuk diamankan kecuali Anda menggunakan HTTPS
jnoss
1
Untuk siapa pun yang mendapatkan pertanyaan ini di masa mendatang: SETELAH masuk, Anda juga perlu mengamankan cookie sesi. (Jadi: menggunakan HTTPS benar-benar jauh lebih mudah.)
Arjan

Jawaban:

66

Menggunakan HTTP dengan SSL akan membuat hidup Anda lebih mudah dan Anda bisa tenang. Orang-orang yang sangat pintar (setidaknya lebih pintar dari saya!) Telah meneliti metode komunikasi rahasia ini selama bertahun-tahun.

Jeremy Powell
sumber
14
... dan "Tapi saya harus membayar untuk sertifikat SSL !!" bukan keluhan yang sah, karena Anda bisa mendapatkannya dengan $ 30 hari ini. Apakah data Anda benar-benar tidak bernilai 30 dolar untuk dilindungi?
kafe
3
Bagaimana jika host web langganan Anda tidak mendukung penambahan sertifikat SSL?
Calmarius
89
@Calmarius - kemudian Anda pindah ke webhost nyata
BornToCode
3
@BornToCode Ini secara teknis berarti Anda harus memiliki IP khusus dan Anda perlu memiliki perangkat keras server (atau setidaknya VPS) untuk menggunakan HTTPS. Host web bersama tidak dapat melakukan HTTPS, kecuali seluruh server dilindungi dengan sertifikat pemilik host.
Calmarius
6
berbagi webhost pasti dapat melakukan https, menggunakan en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton
39

Otentikasi aman adalah topik yang luas. Singkatnya, seperti yang disebutkan @ jeremy-powell, selalu lebih menyukai pengiriman kredensial melalui HTTPS daripada HTTP. Ini akan menghilangkan banyak sakit kepala terkait keamanan.

Sertifikat TSL / SSL cukup murah akhir-akhir ini. Bahkan jika Anda tidak ingin mengeluarkan uang sama sekali, ada letsencrypt.org gratis - Otoritas Sertifikat otomatis.

Anda dapat melangkah lebih jauh dan menggunakan caddyserver.com yang memanggil letsencrypt di latar belakang.

Sekarang, setelah kami mendapatkan HTTPS ...

Anda tidak boleh mengirim login dan kata sandi melalui payload POST atau parameter GET. Gunakan header Otorisasi (Skema otentikasi akses dasar) sebagai gantinya, yang dibuat sebagai berikut:

  • Nama pengguna dan kata sandi digabungkan menjadi string yang dipisahkan oleh titik dua, misalnya: nama pengguna: kata sandi
  • String yang dihasilkan dienkode menggunakan varian RFC2045-MIME dari Base64, kecuali tidak terbatas pada 76 karakter / baris.
  • Metode otorisasi dan spasi yaitu "Basic" kemudian diletakkan sebelum string yang dikodekan.

sumber: Wikipedia: Judul otorisasi

Ini mungkin tampak agak rumit, tetapi sebenarnya tidak. Ada banyak perpustakaan bagus di luar sana yang akan menyediakan fungsionalitas ini untuk Anda di luar kotak.

Ada beberapa alasan bagus Anda harus menggunakan header Otorisasi

  1. Itu adalah standar
  2. Sederhana (setelah Anda mempelajari cara menggunakannya)
  3. Ini akan memungkinkan Anda untuk masuk di tingkat URL, seperti ini: https://user:[email protected]/login(Chrome, misalnya akan secara otomatis mengubahnya menjadi Authorizationtajuk)

PENTING:
Seperti yang ditunjukkan oleh @zaph dalam komentarnya di bawah ini, mengirimkan info sensitif sebagai kueri GET bukanlah ide yang baik karena kemungkinan besar akan berakhir di log server.

masukkan deskripsi gambar di sini

FullStackForger
sumber
11
Masalah dengan mengirim kredensial (kata sandi) sebagai parameter GET adalah bahwa pasangan pengguna / kata sandi mungkin akan berakhir di log server yang bukan merupakan ide yang baik. Cara terbaik adalah mengirim kredensial dalam POST.
zaf
Ahh ... tidak sama sekali. Tangkapan layar yang Anda lihat dimodifikasi untuk mengilustrasikan apa yang terjadi di browser. Saat Anda menekan enter browser akan mengubah url Anda membuat Authorizationheader. Coba saja. Log akan mengingatkan bersih. Dan tentu saja jika Anda membuat panggilan dari server (jika itu skenario yang Anda khawatirkan), Anda harus membuat header secara terprogram tentunya.
FullStackForger
Anda tidak dapat mencatat apa yang tidak dapat Anda lihat. username:password@urldari browser diterjemahkan menjadi: url+ Authorizationheader permintaan. Adapun pertanyaan GET ... seperti yang saya katakan, gunakan header Authroziation. Ini lebih baik.
FullStackForger
2
Anda tidak menjawab inti pertanyaan: melindungi data sensitif dari penyadapan orang-di-tengah. Fokusnya bukan untuk mencari alternatif dan / atau cara yang lebih terstandardisasi untuk memberikan kredensial, tetapi melindunginya melalui saluran yang tidak aman.
Lord of the Goo
3
Perlu ditekankan bahwa solusi ini hanya berfungsi jika Anda sudah mengenkripsi koneksi dengan TLS / SSL. base64 bukanlah enkripsi.
Skotlandia
14

Anda dapat menggunakan skema respons tantangan. Katakanlah klien dan server sama-sama mengetahui rahasia S. Kemudian server dapat memastikan bahwa klien mengetahui kata sandi (tanpa memberikannya) dengan:

  1. Server mengirimkan nomor acak, R, ke klien.
  2. Klien mengirim H (R, S) kembali ke server (di mana H adalah fungsi hash kriptografi, seperti SHA-256)
  3. Server menghitung H (R, S) dan membandingkannya dengan respons klien. Jika cocok, server tahu klien mengetahui kata sandinya.

Edit:

Ada masalah di sini dengan kesegaran R dan fakta bahwa HTTP tidak memiliki kewarganegaraan. Ini dapat ditangani dengan meminta server membuat rahasia, sebut saja Q, yang hanya diketahui oleh server . Kemudian protokolnya seperti ini:

  1. Server menghasilkan nomor acak R. Kemudian mengirimkan ke klien H (R, Q) (yang tidak dapat dipalsukan oleh klien).
  2. Klien mengirim R, H (R, Q), dan menghitung H (R, S) dan mengirimkan semuanya kembali ke server (di mana H adalah fungsi hash kriptografi, seperti SHA-256)
  3. Server menghitung H (R, S) dan membandingkannya dengan respons klien. Kemudian dibutuhkan R dan menghitung (lagi) H (R, Q). Jika versi klien H (R, Q) dan H (R, S) cocok dengan penghitungan ulang server, server menganggap klien telah diautentikasi.

Sebagai catatan, karena H (R, Q) tidak dapat dipalsukan oleh klien, H (R, Q) bertindak sebagai cookie (dan oleh karena itu sebenarnya dapat diimplementasikan sebagai cookie).

Edit Lainnya:

Pengeditan protokol sebelumnya tidak benar karena siapa pun yang telah mengamati H (R, Q) tampaknya dapat memutarnya kembali dengan hash yang benar. Server harus mengingat R mana yang tidak lagi segar. Saya CW'ing jawaban ini sehingga kalian dapat mengedit ini dan mengerjakan sesuatu yang baik.

Jeremy Powell
sumber
+1 - Anda harus menghitung respons di sisi klien dengan javascript (atau Flash / Silverlight / dll.)
orip
10
Tidak menghentikan serangan manusia di tengah atau peniruan identitas. Misal melalui wifi. Sepertinya ini hanya akan memberikan rasa aman yang palsu, IMO.
Tom Hawtin - tackline
2
Itu melindungi dari serangan pasif, tapi Man in the Middle masih bisa menyerang.
Douglas Leeder
7
Juga membutuhkan server untuk mengetahui kata sandi asli.
Douglas Leeder
3
Jangan menemukan kembali crypto! (dalam produksi)
bryanph
11

Jika host web Anda mengizinkannya, atau Anda perlu menangani data sensitif, gunakan HTTPS, titik. (Ini sering diwajibkan oleh hukum afaik).

Sebaliknya jika Anda ingin melakukan sesuatu melalui HTTP. Saya akan melakukan sesuatu seperti ini.

  1. Server menyematkan kunci publiknya ke halaman login.
  2. Klien mengisi formulir login dan mengklik kirim.
  3. Permintaan AJAX mendapatkan stempel waktu saat ini dari server.
  4. Skrip sisi klien menggabungkan kredensial, stempel waktu, dan salt (di-hash dari data analog misalnya gerakan mouse, peristiwa penekanan tombol), mengenkripsinya menggunakan kunci publik.
  5. Mengirimkan hash yang dihasilkan.
  6. Server mendekripsi hash
  7. Memeriksa apakah stempel waktu cukup baru (memungkinkan jendela pendek 5-10 detik saja). Menolak login jika stempel waktunya terlalu lama.
  8. Menyimpan hash selama 20 detik. Menolak hash yang sama untuk login selama interval ini.
  9. Mengotentikasi pengguna.

Jadi dengan cara ini kata sandi dilindungi dan hash otentikasi yang sama tidak dapat diputar ulang.

Tentang keamanan token sesi. Itu sedikit lebih sulit. Tetapi mungkin untuk membuat penggunaan kembali token sesi yang dicuri sedikit lebih sulit.

  1. Server menetapkan cookie sesi tambahan yang berisi string acak.
  2. Browser mengirimkan kembali cookie ini pada permintaan berikutnya.
  3. Server memeriksa nilai dalam cookie, jika berbeda maka itu akan menghancurkan sesi, jika tidak semuanya baik-baik saja.
  4. Server menyetel cookie lagi dengan teks yang berbeda.

Jadi jika token sesi dicuri, dan permintaan dikirim oleh orang lain, maka sesi tersebut akan dimusnahkan berdasarkan permintaan pengguna asli berikutnya. Jadi jika pengguna aktif menjelajahi situs, sering mengklik tautan, maka pencuri tidak akan bertindak jauh dengan token yang dicuri. Skema ini dapat diperkuat dengan meminta otentikasi lain untuk operasi sensitif (seperti penghapusan akun).

EDIT: Harap dicatat ini tidak mencegah serangan MITM jika penyerang mengatur halaman mereka sendiri dengan kunci publik yang berbeda dan permintaan proxy ke server. Untuk melindungi dari ini, kunci publik harus disematkan di penyimpanan lokal browser atau di dalam aplikasi untuk mendeteksi jenis trik ini.

Tentang implementasinya: RSA mungkin adalah algoritme yang paling dikenal, tetapi agak lambat untuk kunci yang panjang. Saya tidak tahu seberapa cepat implementasi PHP atau Javascript nantinya. Tapi mungkin ada algoritma yang lebih cepat.

Calmarius
sumber
Dalam hal ini apakah kata sandi benar-benar dilindungi? Tidak bisakah seseorang mengendus apa yang dikirim dan mendekripsinya menggunakan kunci publik dan kemudian memperbarui stempel waktu ketika mereka menggunakannya nanti? Apakah saya melewatkan sesuatu?
michaellindahl
Enkripsi asimetris @michaellindahl berarti bahwa hanya kunci pribadi - yang tidak pernah meninggalkan server - yang dapat digunakan untuk mendekripsi berbagai hal. Kunci publik hanya dapat digunakan untuk mengenkripsi.
Dan Pantry
2
Komputer antara browser dan server dapat mengubah kunci publik pada halaman login.
Antti
Terima kasih telah membagikan metode Anda, saya menemukan segalanya yang sangat menarik. Stempel waktu yang ditambahkan saat mengirim kredensial adalah hasil yang bagus! Satu pertanyaan tentang penggunaan cookie sesi ekstra yang nilainya berupa string acak: seperti token hanya untuk permintaan berikutnya?
Victor
4

Saya akan menggunakan sistem pertukaran kunci Diffie-Hellman sisi-server dan sisi-klien dengan AJAX atau beberapa pengiriman formulir (saya merekomendasikan yang pertama), meskipun saya tidak melihat implementasi yang baik darinya di internet. Ingatlah bahwa pustaka JS selalu dapat rusak atau diubah oleh MITM. Penyimpanan lokal dapat digunakan untuk membantu memerangi ini, sampai batas tertentu.

nanofarad.dll
sumber
4

Anda dapat menggunakan SRP untuk menggunakan kata sandi aman melalui saluran yang tidak aman. Keuntungannya adalah bahkan jika penyerang mengendus lalu lintas, atau menyusupi server, mereka tidak dapat menggunakan sandi di server lain. https://github.com/alax/jsrp adalah pustaka javascript yang mendukung kata sandi aman melalui HTTP di browser, atau sisi server (melalui node).

Brian Minton
sumber
1

HTTPS sangat kuat karena menggunakan kriptografi asimetris. Jenis kriptografi ini tidak hanya memungkinkan Anda membuat terowongan terenkripsi tetapi Anda juga dapat memverifikasi bahwa Anda berbicara dengan orang yang tepat, dan bukan peretas.

Berikut adalah kode sumber Java yang menggunakan cipher RSA asimetris (digunakan oleh PGP) untuk berkomunikasi: http://www.hushmail.com/services/downloads/

benteng
sumber
0

Anda dapat menggunakan ssl untuk host Anda, ada proyek gratis untuk ssl seperti letsencrypt https://letsencrypt.org/

mk990
sumber
2
Periksa kalimat ketiga yang dimaksud. (Juga, selalu baca jawaban lain untuk memastikan Anda tidak menambahkan duplikat yang kurang mendetail.)
Nathan Tuggy
0

Menggunakan https terdengar pilihan terbaik di sini (sertifikat tidak semahal itu saat ini). Namun jika http merupakan persyaratan, Anda dapat menggunakan beberapa encription - encript di sisi server dan decript di browser pengguna (kirim kunci secara terpisah).

Kami telah menggunakannya saat mengimplementasikan safevia.net - enkripsi dilakukan pada sisi klien (pengirim / penerima), sehingga data pengguna tidak tersedia pada lapisan jaringan atau server.

parvusel elephantus
sumber