Posisi otoritatif dari kunci kueri HTTP GET duplikat

142

Saya mengalami masalah dalam menemukan informasi otoritatif tentang perilaku dengan bidang duplikat string kueri HTTP GET, seperti

http://example.com/page?field=foo&field=bar 

dan khususnya jika pesanan disimpan atau tidak. Sebagian besar bahasa berorientasi web menghasilkan larik yang berisi foo dan bar yang terkait dengan "bidang" kunci, tetapi saya ingin tahu apakah ada pernyataan otoritatif (misalnya pada RFC) tentang hal ini. RFC 3986 memiliki bagian 3.4. Query, yang mengacu pada pasangan kunci = nilai, tetapi tidak ada yang dijelaskan tentang cara menafsirkan urutan dan bidang duplikat dan seterusnya. Ini masuk akal, karena itu bergantung pada backend, dan bukan dalam cakupan RFC itu ...

Meskipun standar de-facto ada, saya ingin melihat sumber resmi untuk itu, hanya karena penasaran.

Stefano Borini
sumber
Aku juga bertanya-tanya tentang itu. Hal lainnya adalah spesifikasi tentang menggabungkan parameter dari string kueri dengan yang ada di badan POST.
Thilo
Selama di code ranch, orang mengatakan tidak ada jaminan pesanan. Tapi utas itu sudah tua dan tidak ada yang mendukungnya dengan cara apa pun: coderanch.com/t/357197/Servlets/java/getParameterValues-order
Thilo
1
Selain server yang menjaga urutan string kueri, ada juga pertanyaan tentang browser yang mengirimnya dalam urutan DOM (atau beberapa tetap lainnya).
Thilo

Jawaban:

114

Tidak ada spesifikasi tentang ini. Anda dapat melakukan apa yang Anda suka.

Pendekatan tipikal meliputi: first-given, last-given, array-of-all, string-join-with-comma-of-all.

Misalkan permintaan mentahnya adalah:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

Lalu ada berbagai opsi untuk apa yang request.query['tag']harus dihasilkan, tergantung pada bahasa atau kerangka kerjanya:

request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'
yfeldblum
sumber
13
Lebih ke inti pertanyaannya, ada juga opsi ['rails', 'ruby'] (urutan berbeda).
Thilo
2
Seseorang pasti dapat melakukan banyak hal.
yfeldblum
7
NET akan memberikan Anda sebagai sebuah array (saya tidak peduli tentang urutan ketika saya mengujinya), PHP akan selalu memberi Anda yang terakhir dan Java (setidaknya sistem yang saya gunakan berdasarkan Java) selalu nilai pertama. stackoverflow.com/questions/1809494/…
SimonSimCity
17
Ini didasarkan pada serangan yang disebut HTTP Parameter Pollution dan telah dianalisis oleh OWASP: owasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf Di halaman 9 Anda akan menemukan daftar 20 sistem dan penjelasan bagaimana mereka menanganinya masalah ini.
SimonSimCity
1
@SimonSimCity Selain itu, PHP akan benar-benar membuat array jika Anda menambahkan tanda kurung siku dengan indeks opsional ke nama parameter.
Martin Ender
13

Saya dapat mengonfirmasi bahwa untuk PHP (setidaknya dalam versi 4.4.4 dan yang lebih baru) berfungsi seperti ini:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

menghasilkan:

request.query['tag'] => 'rails'

Tapi

GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com

menghasilkan:

request.query['tag'] => ['ruby', 'rails']

Perilaku ini sama untuk data GET dan POST.

SimonSimCity
sumber
1
The []akhiran tampaknya seperti perilaku benar-benar aneh, tetapi jika Anda mencoba untuk mengirim Array sebagai argumen melalui jQuery .ajax(), maka akan secara otomatis menambahkan mereka untuk Anda dengan cara yang sama. Sepertinya ini untuk kepentingan pengguna PHP.
Ian Clark
4
@IanClark Sangat intuitif bagi pembuat kode PHP - dalam PHP biasa, $foo[] = 1ditambahkan ke sebuah array. Django (Python) juga melakukan hal yang sama.
Izkata
Dapat memverifikasi di Apache Tomcat itu mengembalikan string yang digabungkan koma.
Gaurav Ojha
8

Jawaban yfeldblum sempurna.

Hanya catatan tentang perilaku kelima yang saya perhatikan baru-baru ini: di Windows Phone , membuka aplikasi dengan uri dengan kunci kueri duplikat akan mengakibatkan NavigationFailed dengan:

System.ArgumentException: Item dengan kunci yang sama telah ditambahkan.

Pelakunya adalah System.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults).

Jadi sistem tidak akan membiarkan Anda menanganinya seperti yang Anda inginkan, itu akan melarangnya. Anda memiliki satu-satunya solusi untuk memilih format Anda sendiri (CSV, JSON, XML, ...) dan uri-escape-it.

Cœur
sumber
2
Itu tampak seperti bug internal dari fungsi itu, daripada pilihan desain. Fungsi mungkin tidak memeriksa kunci duplikat dalam Kamus yang dibuatnya. Kamus, tentu saja, membutuhkan kunci yang unik.
gligoran
1
Jadi browser klien - bukan server - membuat kesalahan dalam situasi ini? Sepertinya itu bug. Saya ingin tahu apakah bug ini masih ada sampai sekarang?
Jon Schneider
1
@JonSchneider Ya, klien membuang NavigationFailedURI tersebut. Tapi, maafkan saya, saya menghentikan pengembangan Windows (Telepon) sebulan setelah posting ini dan saya pindah ke macOS (iOS), jadi saya tidak dapat membantu lagi untuk melacak masalah ini saat ini.
Cœur
5

Sebagian besar (semua?) Kerangka tidak menawarkan jaminan, jadi asumsikan kerangka tersebut akan dikembalikan dalam urutan acak.

Selalu ambil pendekatan yang paling aman.

Misalnya, antarmuka HttpServlet java: ServletRequest.html # getParameterValues

Bahkan metode getParameterMap tidak menyebutkan urutan parameter (urutan iterator java.util.Map juga tidak dapat diandalkan.)

Photodeus
sumber
3

Biasanya, nilai parameter duplikat seperti

http://example.com/page?field=foo&field=bar

menghasilkan parameter queryString tunggal yang berupa larik:

field[0]=='foo'
field[1]=='bar'

Saya telah melihat perilaku ini di ASP, ASP.NET, dan PHP4.

Simpan
sumber
tepatnya, ini adalah standar de-facto, tetapi sejauh yang saya lihat tidak ada keputusan resmi tentangnya. Karena saya tidak percaya ini masalahnya, saya tidak kompeten untuk menemukannya.
Stefano Borini
2
Ya, mungkin semua orang pernah melihat perilaku itu. Pertanyaannya adalah apakah itu sebenarnya ditentukan di suatu tempat.
Thilo
-1

Saya memiliki pertanyaan yang sama. Saya menulis fungsi javascript untuk mengurai dan merangkai kueri. Saya tidak tahu apakah string kueri memiliki nama duplikat atau nama dengan tanda kurung, seperti x [] = 1 & x [] = 2, adalah standar meskipun beberapa bahasa mendukung format ini.

Tetapi saya menemukan bahwa Chrome dan Firefox memiliki Kelas baru bernama URLSeachParamsdan itu hanya mendukung format yang paling sederhana seperti name=value. Jika ada nama duplikat dalam string kueri, getmetode URLSearchParamshanya mengembalikan yang pertama.

Jadi secara pribadi, mungkin url nama yang paling sederhana dan tidak ada duplikat jauh lebih aman untuk masa depan.

LCB
sumber
1
Jika ada nama duplikat dalam string kueri, metode get dari URLSearchParams hanya mengembalikan yang pertama. Ini tidak benar: Anda dapat mengambil semua nilai sebagai array menggunakanURLSearchParams.getAll('x')
Blaise
@Blaise Terima kasih banyak, saya salah paham tentang fitur ini sebelumnya.
LCB