Mengapa GET meminta data perubahan pada server tidak?

109

Di seluruh internet, saya melihat saran berikut:

GET jangan pernah mengubah data di server - gunakan permintaan POST untuk itu

Apa dasar dari ide ini?

Jika saya membuat layanan php yang memasukkan data dalam database, dan mengirimkannya parameter dalam string kueri GET, mengapa itu salah? (Saya menggunakan pernyataan yang disiapkan, untuk mengurus SQL Injection). Apakah permintaan POST dalam beberapa cara lebih aman?

Atau adakah alasan bersejarah untuk ini? Jika demikian, seberapa validkah nasihat ini hari ini?

Devdatta Tengshe
sumber
35
Ada entri DailyWTF yang relevan .
Joachim Sauer
Terima kasih telah mengajukan pertanyaan ini, dan terima kasih @Daftar untuk jawaban yang diutarakan dengan baik. Saya selalu membutuhkan referensi untuk mengirim orang yang menanyakan pertanyaan ini :)
Benjamin Gruenbaum
Juga lihat HTTP PUT - stackoverflow.com/questions/630453/put-vs-post-in-rest (dengan catatan tentang menjadi idempoten)
Bratch
2
@ JoachimSauer Sementara GET akan menyelamatkan mereka dari perayap, masalah root adalah kurangnya otentikasi. Skrip apa pun yang bocor bisa saja POST mereka lupakan juga.
CodesInChaos

Jawaban:

185

Ini bukan nasihat.

A GETdidefinisikan dengan cara ini dalam protokol HTTP . Seharusnya idempoten dan aman .

Adapun alasannya - a GETbisa di-cache dan di browser, di-refresh. Lagi dan lagi dan lagi.

Ini berarti bahwa jika Anda membuat yang sama GETlagi, Anda akan memasukkan ke dalam basis data Anda lagi .

Pertimbangkan apa artinya ini jika tautan GETmenjadi dan dirayapi oleh mesin pencari. Database Anda akan penuh dengan data duplikat.

Saya juga menyarankan membaca URI, Addressability, dan penggunaan HTTP GET dan POST .


Ada juga masalah dengan pranala tautan di beberapa peramban - mereka akan melakukan panggilan untuk mengambil pranata tautan, bahkan jika tidak ditunjukkan demikian oleh penulis halaman.

Jika, katakanlah, logout Anda berada di belakang "GET", ditautkan dari setiap halaman di situs Anda, orang-orang dapat logout hanya karena perilaku ini.

Oded
sumber
35
Banyak, banyak, banyak alat, utilitas, perayap web, dan hal-hal aneh lainnya menganggap bahwa GETtidak akan pernah menjadi tindakan destruktif (memang demikian, karena sudah ditentukan dengan cara ini). Jika sekarang Anda menghancurkan aplikasi Anda dengan melanggar spesifikasi itu, Anda akan bisa mempertahankan kedua bagian dari aplikasi Anda.
Joachim Sauer
7
@NimChimpsky: itu bisa diubah oleh GET. Nasihat itu benar-benar salah. Aman berarti bahwa pengguna tidak dapat dimintai pertanggungjawaban atas efek samping, bukan karena tidak ada efek samping. Kalau tidak, Anda tidak dapat memiliki file log untuk server Anda, yang tidak masuk akal! Ini dijabarkan dengan sangat jelas di bagian 9.1.1 dari RFC2616.
Jörg W Mittag
8
@ JörgWMittag: Saya tidak akan mengatakan "salah", saya akan mengatakan "diucapkan dengan tidak sempurna". GET seharusnya tidak memiliki perubahan karena tujuannya. Tentu saja Anda diizinkan untuk menghitung, login dan amati permintaan GET. Tetapi seharusnya tidak mengubah data bisnis Anda yang sebenarnya.
Joachim Sauer
23
@NimChimpsky A GETseharusnya tidak mengubah sumber daya yang diminta oleh GET, tetapi itu tidak berarti 'tidak ada di server yang harus berubah'. Tentu saja hal-hal seperti log, penghitung, dan status server lainnya dapat berubah selama permintaan apa pun.
Eric King
8
Beberapa tahun yang lalu, Google merilis add-on browser (iirc) yang akan mengambil halaman sebelumnya melalui tautan. Ini juga terjadi pada beberapa panel kontrol yang dirancang dengan buruk - URL akan menyebabkan catatan atau sesuatu ditulis atau bahkan dihapus di server (think post? Action = delete). Ini menyebabkan tindakan dieksekusi tanpa pengguna menyadarinya. Google menghentikan addon itu karena alasan itu, iirc, bahkan jika itu adalah kesalahan pabrikan webapp untuk menggunakan GET untuk mengubah status.
Cthulhu
24

Setiap kata kerja HTTP memiliki tanggung jawabnya sendiri. Misalnya GET, seperti yang didefinisikan oleh RFC

berarti mengambil informasi apa pun (dalam bentuk entitas) yang diidentifikasi oleh Request-URI.

POST, di sisi lain, berarti memasukkan atau lebih formal

Metode POST digunakan untuk meminta server asal menerima
entitas yang dilampirkan dalam permintaan sebagai bawahan baru dari sumber daya yang
diidentifikasi oleh Request-URI di Request-Line

Alasan untuk mempertahankannya seperti ini:

  • Ini sangat sederhana dan berfungsi pada skala Internet global sejak 1991
  • Berpegang teguh pada prinsip tanggung jawab tunggal
  • Pihak lain menggunakan GETuntuk bertindak sebagai sarana pengambilan informasi dan penggalian data
  • GET dianggap sebagai operasi yang aman yang tidak pernah mengubah keadaan sumber daya
  • Pertimbangan keamanan, GETsecara efektif adalah bacaan , sedangkan POSTsecara efektif adalah menulis
  • GET di-cache oleh browser, node dalam jaringan, Penyedia Layanan Internet
  • Kecuali jika kontennya berubah, GETke URL yang sama harus mengembalikan hasil yang sama kepada semua pengguna atau Anda tidak akan memiliki kepercayaan apa pun atas hasil yang dikembalikan

Untuk kelengkapan dan hanya untuk menegakkan penggunaan yang benar (sumber) :

  • GETparameter dilewatkan sebagai bagian dari URL, yang panjangnya 256 karakter dan terbatas, dengan beberapa server mendukung 4000+ karakter. Jika Anda ingin menyisipkan catatan panjang, tidak ada cara yang sah untuk meneruskan data ini
  • Bila menggunakan mengamankan sambungan, ̶ seperti TLS, ̶ URL tidak mendapatkan dienkripsi, ̶ maka semua parameter dari ̶ ̶G̶E̶T̶̶ ditransfer Plain Text. URL sebenarnya dienkripsi dengan TLS, jadi TLS baik-baik saja.
  • Memasukkan data biner atau karakter non-ASCII menggunakan GETtidak praktis
  • GET dieksekusi kembali jika pengguna menekan tombol Kembali di browser
  • Beberapa perayap lama mungkin tidak mengindeks URL dengan ?tanda masuk di dalamnya
oleksii
sumber
1
Apakah Anda yakin bahwa URL tidak dienkripsi melalui TLS? Saya mendapat kesan bahwa jabat tangan SSL / TLS terjadi sebelum tajuk HTTP dipindahkan. Ini adalah alasan mengapa situs hosting HTTPS virtual melalui satu alamat IP sulit. Apakah saya salah?
Brandon
Itu benar, saya memperbaikinya
oleksii
2
@Brandon Browser modern mengirim domain host dengan jelas sebagai bagian dari jabat tangan TLS (dikenal sebagai indikasi nama server), untuk memungkinkan hosting lebih dari satu domain per alamat IP. Bagian jalur / kueri dari url dilindungi oleh TLS. Tidak ada perbedaan antara GET dan kata kerja HTTP lainnya dalam hal ini.
CodesInChaos
9

EDIT: Sebelumnya, saya katakan POST membantu melindungi Anda dari CSRF tetapi ini salah. Saya tidak memikirkan ini dengan benar. Anda harus meminta token tersembunyi unik sesi-lingkup dalam semua permintaan Anda untuk mengubah data agar terlindung dari CSRF.

Pada hari-hari awal internet ada akselerator browser. Program-program ini akan mulai mengklik tautan pada halaman untuk menyimpan konten. Google Web Accelerator adalah salah satu dari program ini. Ini bisa mendatangkan malapetaka pada aplikasi yang membuat perubahan saat tautan diklik. Saya akan membuat asumsi bahwa masih ada orang yang menggunakan perangkat lunak akselerator.

Server dan browser proksi akan men-cache permintaan GET sehingga ketika pengguna mengakses kembali halaman itu mungkin tidak mengirimkan permintaan ke aplikasi Anda sehingga pengguna berpikir mereka mengambil tindakan, tetapi sebenarnya tidak.

Sarel Botha
sumber
1
CSRF juga dimungkinkan dengan GET dan POST. Misalnya penyerang dapat menyertakan formulir pengiriman otomatis di situs mereka untuk memicu permintaan POST. Pendekatan standar untuk mencegah CSRF secara eksplisit termasuk nilai yang tidak diketahui oleh penyerang dalam permintaan (tidak seperti yang termasuk header cookie).
CodesInChaos
8

Jika saya membuat layanan php yang memasukkan data dalam database, dan mengirimkannya parameter dalam string kueri GET, mengapa itu salah?

Jawaban paling sederhana adalah "karena bukan itu GETartinya."

Menggunakan GETuntuk meneruskan data untuk pembaruan seperti menulis surat cinta dan mengirimkannya dalam amplop bertanda "PENAWARAN KHUSUS - BERTINDAK SEKARANG!" Dalam kedua kasus, Anda seharusnya tidak terkejut penerima dan / atau perantara salah menangani pesan Anda .

Nathan Long
sumber
5

Untuk operasi CRUD Anda dalam aplikasi berbasis database gunakan skema berikut:

Gunakan HTTP DAPATKAN untuk Operasi Baca (SQL SELECT)

Gunakan HTTP PUT untuk Operasi Pembaruan (SQL UPDATE)

Gunakan HTTP POST untuk Membuat Operasi (SQL INSERT)

Gunakan HTTP DELETE untuk Menghapus Operasi (SQL DELETE)


sumber
3
Pasang vs pos tidak seperti yang Anda sebutkan. Put adalah untuk saat klien memodifikasi sumber daya di lokasi yang diberikan tepat. Untuk sebuah posting, server akhirnya memutuskan Uri yang tepat untuk sumber daya.
Andy
Bukankah HTTP PUT lebih seperti SQL DELETE dan INSERT daripada UPDATE? SQL UPDATE juga dapat memperbarui banyak catatan sekaligus, tetapi HTTP PUT hanya akan memperbarui satu hal.
Backwards_Dave
0

GET jangan pernah mengubah data di server - gunakan permintaan POST untuk itu

Nasihat itu, dan semua jawaban di sini salah. Jelas saya terlalu dramatis, jawaban lainnya sangat bagus, tetapi saya percaya saran yang tepat harus diberikan sebagai:

GET harus jarang mengubah data di server - gunakan permintaan POST untuk itu

Mengatakan "tidak pernah" terlalu ekstrim, dan meskipun jawaban lain di sini secara akurat menjelaskan mengapa Anda "jarang" melakukannya, ada beberapa skenario di mana sangat masuk akal untuk mengubah data dengan GET. Contohnya adalah tautan verifikasi email sekali pakai. Biasanya tautan ini berisi GUID yang ketika diakses harus mengubah data. Jika diterapkan dengan benar, permintaan GET identik berikutnya akan diabaikan.

Ini jelas merupakan kasus tepi, tetapi tentu patut dicatat.

TTT
sumber
3
Bagaimana jika klien email Anda memutuskan untuk mengambil tautan tanpa Anda mengkliknya? Misalnya karena ingin memindai malware. Pendekatan yang tepat untuk tautan berhenti berlangganan adalah mengarah ke halaman di mana pengguna dapat mengklik tombol untuk berhenti berlangganan (di mana klik tombol memicu permintaan POST).
CodesInChaos
@CodesInChaos - titik luar biasa! Saya setuju denganmu. Saya telah menghapus contoh berhenti berlangganan dan telah meninggalkan verifikasi email sebagai satu-satunya contoh. Mungkin ada orang lain selain verifikasi email di mana GET masuk akal, tapi saya tidak bisa memikirkannya saat ini.
TTT
Masalah dengan GET memiliki efek samping berlaku sama untuk konfirmasi email. Sekarang klien yang mengikuti tautan akan mengonfirmasi akun yang dibuat orang lain menggunakan email Anda, memungkinkan mereka untuk menyamar sebagai Anda.
CodesInChaos
@CodesInChaos - yang itu adalah peregangan. Peniruan yang Anda bicarakan akan berasal dari nama pengguna atau nama pribadi publik yang sama, bukan alamat email yang sama, dan itu bisa terjadi terlepas dari alamat email apa yang mereka gunakan (biasanya hanya server yang tahu alamat email pemegang akun itu). Selain itu, tidak ada gunanya membuat akun dengan alamat email orang lain. Bagaimana itu bisa membantu mereka? Mereka tidak dapat mengontrol akun mereka sendiri.
TTT