Haruskah pembatasan keamanan menyebabkan layanan kembali nol atau melemparkan pengecualian? [Tutup]

11

Saya agak tidak setuju dengan pengembang yang lebih berpengalaman tentang masalah ini, dan bertanya-tanya apa pendapat orang lain tentang hal itu; lingkungan kita adalah Java, EJB 3, layanan, dll.

Kode yang saya tulis memanggil layanan untuk mendapatkan sesuatu dan untuk membuat sesuatu. Masalah yang saya temui adalah bahwa saya mendapat pengecualian null pointer yang tidak masuk akal. Misalnya, ketika saya meminta layanan untuk membuat objek, saya mendapatkan null kembali; ketika saya mencoba mencari objek dengan ID valid yang diketahui, saya mendapatkan null kembali. Saya menghabiskan beberapa waktu untuk mencari tahu apa yang salah dalam kode saya; karena saya kurang berpengalaman, saya biasanya berasumsi saya telah melakukan sesuatu yang salah, tetapi ternyata alasan pengembalian nol adalah keamanan. Jika prinsipal pengguna menggunakan layanan saya tidak memiliki izin yang tepat untuk layanan target, maka itu hanya mengembalikan nol. Sebagian besar layanan lain di sini juga tidak didokumentasikan dengan baik, jadi sepertinya ini hanya sesuatu yang harus Anda ketahui.

Ini agak membingungkan karena pengembang menulis kode yang berinteraksi dengan layanan. Akan jauh lebih masuk akal bagi saya jika layanan mencabut pengecualian yang akan memberi tahu saya bahwa pengguna tidak memiliki izin yang tepat untuk memuat hal ini atau untuk membuat hal itu; Saya kemudian akan segera tahu mengapa layanan saya tidak berfungsi seperti yang diharapkan.

Pengembang yang lebih berpengalaman yang menulis layanan berpendapat bahwa meminta data bukan kondisi kesalahan, dan bahwa pengecualian hanya boleh dilemparkan dalam kondisi kesalahan, bukan ketika pengguna tidak memiliki akses ke data. Data ini sering dicari dalam GUI, dan bagi pengguna tanpa izin yang tepat, hal-hal ini "tidak ada". Jadi, singkatnya: bertanya itu tidak salah, maka tidak terkecuali. Dapatkan metode mengembalikan nol karena bagi pengguna itu hal-hal "tidak ada". Buat metode mengembalikan nol ketika pengguna tidak diizinkan untuk membuat hal itu.

Apakah ini normal dan / atau praktik yang baik? Saya lebih suka menggunakan pengecualian karena saya merasa lebih mudah untuk mengetahui apa yang terjadi. Jadi saya akan misalnya juga lebih suka melempar NotFoundException jika Anda meminta objek dengan ID yang tidak valid, daripada mengembalikan nol.

Svish
sumber
@ ChrisF: 1) adalah tentang orang yang menghindari referensi nol, yang saya tidak lakukan. Dalam banyak kasus mereka sesuai, saya hanya tidak berpikir mereka ada di sini. 2) adalah tentang memeriksa parameter, dan bukankah hasil yang tegas sama dengan melempar pengecualian? 3) pengecualian vs kode kesalahan juga merupakan masalah yang berbeda karena keduanya merupakan cara "menunjukkan" apa yang salah. Kode kesalahan sesuai jika misalnya Anda perlu memberi tahu sistem yang tidak mendukung pengecualian atau jika Anda tidak ingin pengguna akhir melihat hal lain selain kode.
Svish
Masalah yang saya tanyakan di sini adalah tentang "berpura-pura sesuatu tidak ada atau tidak terjadi" vs "mengatakan mengapa sesuatu tidak ada atau tidak terjadi".
Svish
3
Saya tidak menyarankan mereka duplikat - hanya saja mereka mungkin memiliki informasi yang berguna untuk Anda.
ChrisF
Benar, maaf soal itu! Mengambilnya sebagai komentar "kemungkinan duplikat" karena beberapa alasan ... mungkin karena kurang tidur, hehe.
Svish

Jawaban:

19

Pengecualian hanya harus dilemparkan ketika ada kesalahan dan meminta sesuatu bukanlah kesalahan.

Meminta sesuatu mungkin bukan kesalahan, tetapi tidak memiliki izin untuk sesuatu yang Anda minta pasti semacam kesalahan. Pengecualian adalah cara alternatif untuk melaporkan kondisi luar biasa, yang akan digunakan alih-alih nilai pengembalian khusus (seperti null, yang, seperti yang Anda tulis, sama sekali tidak membantu jika ada> 1 kemungkinan alasan mengapa segala sesuatunya menjadi serba salah (bahkan jika ada tepat 1 kemungkinan alasan sekarang, mungkin ada 2 alasan yang mungkin di versi berikutnya, jadi menggunakan nullsebagai nilai pengembalian yang menunjukkan kegagalan akan mengecat diri Anda sendiri ke sudut)). Jika layanan tidak melaporkan mengapa tidak melakukan apa yang Anda minta, maka itu pasti desain yang buruk.

Apakah akan menggunakan nilai pengembalian khusus (misalnya bilangan bulat negatif berguna untuk fungsi yang biasanya mengembalikan bilangan bulat negatif), pengecualian, penangan kesalahan global atau pencatat dll, adalah detail implementasi pada akhirnya. Pilihannya tergantung pada bahasa, situasi, konvensi, dan juga masalah selera. Titik utama adalah bahwa harus ada beberapa cara langsung mencari tahu mengapa sesuatu tidak bekerja. Kalau tidak, satu-satunya pilihan Anda adalah mencari sampah dengan opsi yang berbeda dan apa pun untuk mengetahui apa yang berkorelasi dengan perilaku kotak hitam, dan itu membuang-buang waktu.

String.substring()melempar IndexOutOfBoundsExceptionjika indeks di luar batas. Saya tidak bisa memikirkan keuntungan untuk kembali nullsebagai gantinya, meskipun - secara filosofis - orang dapat berargumen bahwa a Stringtidak mengandung apa pun di luar batasnya, jadi itu nullakan menjadi nilai pengembalian logis saat itu. Menjadi logis-filosofis dan praktis adalah dua binatang yang berbeda.

Joonas Pulakka
sumber
Jika substring () akan mengembalikan nilai untuk indeks di luar batas, ia harus mengembalikan bagian string di antara indeks, mungkin kosong. Itu bisa menyimpan tes dalam beberapa kode panggilan.
kevin cline
2
Ya, ada "nilai kosong" yang tidak pernah berakhir ini vs diskusi-nol: haruskah substring untuk indeks keluar menjadi nol, atau string kosong? Saya tidak tahu, keduanya secara efektif "tidak ada" (well, mungkin null adalah "lebih banyak tidak ada" daripada string kosong?), Tetapi keduanya tidak memberikan jumlah informasi yang dikecualikan.
Joonas Pulakka
@ kevincline: Kecuali ada yang menggunakan kerangka kerja di mana referensi nol adalah cara idiomatis untuk menunjukkan string kosong, saya tidak melihat dasar untuk substringmengembalikan referensi nol. IMHO, harus ada dua fungsi terpisah - satu di antaranya berjanji untuk mengembalikan jumlah karakter yang diminta atau melemparkan pengecualian, dan satu di antaranya mengembalikan sebanyak mungkin. Setiap metode akan jauh lebih unggul dari yang lain dalam beberapa konteks.
supercat
@ supercat: Saya tidak mengatakan apa-apa tentang mengembalikan null. Saya berkata 'kembali ... bagian ... mungkin kosong'. String kosong bukan null, kecuali untuk Oracle.
kevin cline
@JoonasPulakka: Saya seharusnya mem-ping Anda ke komentar saya sebelumnya.
supercat
5

Turun ke apa kontrak itu. Jika kontrak Anda mengatakan Anda dapat meminta sesuatu yang tidak ada, itu harus mengatakan apa yang terjadi (null, atau null object).

Di sisi lain, jika kontrak Anda mengatakan Anda harus memanggil metode yang berbeda terlebih dahulu ( DoesSomethingExist()) dan kemudian memanggil Getmetode tersebut, maka kontrak Anda mungkin mengatakan bahwa Anda hanya bisa mendapatkan hal-hal yang memang ada, dan melemparkan pengecualian jika tidak. Pesan pengecualian bisa mengatakan sesuatu seperti, "Pastikan untuk menelepon DoesSomethingExist()dulu" yang merupakan pesan kesalahan yang berguna.

Scott Whitlock
sumber
Dalam hal ini saya akan mengatakan itu tidak normal untuk meminta sesuatu yang tidak ada, karena Anda mungkin tidak akan meminta id yang tidak ada. Biasanya Anda pertama kali mendapatkan daftar hal-hal dan kemudian mencari yang khusus untuk lebih jelasnya. Jadi jika ada findAllThingsmetode, maka saya akan mengatakan pantas untuk mengembalikan daftar kosong atau subset jika ada beberapa atau semua hal yang tidak boleh Anda lihat. Dengan cara yang sama saya mungkin hanya menulis posting di blog untuk diedit milik pengguna saat ini. Tetapi jika pengguna itu kemudian mencoba mengubah url dan mengedit posting yang berbeda ...
Svish
4

Tidak ada jawaban tunggal untuk semua pertanyaan. Apakah akan menggunakan pengecualian atau mengembalikan null tergantung pada situasinya.

Alih-alih melihat ini murni dari sudut pandang dogmatis, lihatlah antarmuka sebagai antarmuka pengguna . Antarmuka pengguna harus dapat digunakan . Jadi, terlepas dari pendapat Anda sendiri tentang cara "benar" untuk melakukan sesuatu, pilih metode yang paling dapat digunakan dari perspektif seseorang yang menggunakan antarmuka Anda.

Jika penelepon perlu tahu mengapa suatu objek tidak dikembalikan, pengecualian sesuai. Namun, jika konsep umum adalah "jika Anda tidak memiliki izin, itu tidak ada", nol dapat diterima.

Khususnya dalam kasus Anda, saya akan mengatakan nulls sangat dapat diterima untuk mencari item jika penelepon pertama kali diminta untuk masuk atau terhubung ke server. Saat itulah Anda akan diberitahu bahwa Anda memiliki atau tidak memiliki izin. Setelah Anda melewati gerbang masuk akal bahwa ketika Anda mencari sesuatu yang Anda tidak memiliki izin untuk melihat (atau bahkan tahu itu ada), Anda harus mendapatkan nol.

Di sisi lain, jika Anda tidak memiliki koneksi awal atau langkah masuk, pengecualian masuk akal. Jika penelepon mengetahui ada item dan mereka tidak mendapatkannya kembali, API tidak membantu untuk hanya mengembalikan nol.

Namun untuk membuat item, itu cerita yang berbeda. Mungkin ada banyak alasan untuk itu gagal - tidak ada izin, parameter buruk, server kehabisan memori, dll. Jika pengembang diberi nol untuk semua kondisi tersebut, mereka tidak memiliki cara untuk menentukan tindakan yang tepat .

Jadi, untuk menjawab pertanyaan, tanyakan pada diri Anda apa solusi yang paling bermanfaat dari sudut pandang seseorang yang menggunakan layanan ini. Bisa jadi cara Anda menggunakannya tidak lazim, dan untuk kasus yang paling umum, nol adalah jawaban yang tepat.

Jadi, jangan terlibat dalam perang agama karena ini, putuskan apa yang tepat untuk masalah khusus ini.

Bryan Oakley
sumber
Tidak berencana memakai perlengkapan perang untuk ini, hehe. Hanya ingin tahu apakah saya benar-benar salah dalam berpikir apa yang saya pikirkan atau tidak. Saya ingin belajar, tetapi saya tidak suka melompat ke sesuatu hanya karena satu orang mengatakan demikian. Dan terutama tidak jika itu bertentangan dengan pengalaman dan logika saya sendiri (tidak peduli seberapa kecil). Bagaimanapun, saya sepenuhnya setuju bahwa jika ini adalah antarmuka pengguna akhir maka itu memang masuk akal. Namun, karena ini adalah kacang yang, sejauh yang saya tahu, hanya dapat diakses oleh kode, saya akan mengatakan bahwa saya, sebagai pengembang, adalah pengguna.
Svish
1
Dan sebagai pengembang saya peduli mengapa ada sesuatu yang salah, terlepas dari apa yang harus diketahui pengguna akhir tentang hal itu.
Svish
Sepenuhnya setuju dengan Bryan. Bahkan develpers adalah pengguna, yaitu mengkonsumsi beberapa kode pengembang lain. Descisions of throw atau null adalah sejenis antarmuka / gui yang seharusnya membantu untuk tugas tertentu. Bukan hanya dengan istilah umum logika atau filsafat.
Independen
3

Saya pasti berpikir itu adalah desain yang buruk . Null-pointer bukan jawaban yang valid untuk saya dan itu bisa rumit untuk dikelola.

Jika pengguna mencoba menghubungkan layanan tanpa kredensial yang tepat, saya harus menjawab dengan jawaban yang jelas dan ringkas. Jawabannya bisa berupa pengecualian atau objek khusus tetapi tidak nol.

Anda harus meninggalkan jawaban nol ketika tautan jaringan rusak atau kerusakan kritis tak terduga lainnya.

Selain itu, waktu yang Anda habiskan untuk memahami mengapa Anda mendapat nol adalah argumen yang kuat. Setiap potongan kode harus mudah dipahami dan digunakan. Tidak memiliki nilai nol.

Amine
sumber
Dengan kalimat terakhir Anda, maksud Anda "Anda harus mengembalikan nol hanya ketika tautan jaringan rusak dll." atau "Anda harus berhenti mengembalikan nol ketika tautan jaringan rusak dll." ?
Péter Török
@ Péter Török: Saya tidak merekomendasikan penggunaan eksplisit "return null;". Namun ketika gangguan besar terjadi, beberapa layanan dapat mengembalikan nol.
Amine
Bukankah pengecualian akan lebih tepat jika terjadi kerusakan kritis yang tidak terduga?
Svish
2
@Amine: Saya akan mengatakan bahwa itu adalah kasus yang paling tidak sesuai untuk mengembalikan null.
Michael Borgwardt
@Vish: jika Anda dapat mendeteksi gangguan besar, tentu saja pengecualian akan sangat bagus.
Amine
3

Mengingat desain perangkat lunak yang baik dalam pikiran, Anda harus berpikir tentang kehidupan proyek Anda.
Dengan kembali null, seperti yang telah dikatakan, Anda tidak memberikan informasi apa pun kepada klien. Lihatlah apa yang terjadi pada Anda, pada awalnya Anda tidak menyadari di mana masalahnya. Apalagi, jika tidak ada dokumentasi yang diberikan, ini berantakan.

Dengan melemparkan pengecualian, Anda dapat mengetahui apa yang salah. Anda bahkan dapat menyesuaikan teks yang ditampilkan agar lebih spesifik jika Anda mau.

Di sisi lain, dengan kembali nullAnda membuat klien menyelidiki apa yang sedang terjadi.

Selanjutnya, Anda menyadari bahwa ada masalah karena Anda mendapat tempat lain NullPointerException. Sekarang bayangkan Anda tidak menyimpan kembalinya fungsi itu ... Anda akan dipaksa untuk mengelilingi setiap panggilan ke fungsi itu dengan sebuah if elseblok ...

Dari sudut pandang saya, kembali nulladalah praktik yang buruk.

Eversor
sumber
2

Pengembang yang lebih berpengalaman yang menulis layanan berpendapat bahwa meminta data bukan kondisi kesalahan, dan bahwa pengecualian hanya boleh dilemparkan dalam kondisi kesalahan, bukan ketika pengguna tidak memiliki akses ke data.

Dari sudut pandang saya, ini tidak masuk akal.

Permintaan data tanpa izin harus menghasilkan pengecualian, karena ini merupakan hasil yang tidak terduga - untuk tidak mendapatkan hasil - tanpa akses yang tepat.

Analogi : Responsecode untuk GETtanpa otorisasi bukan 200 oktanpa data, sebenarnya 401 Unauthorized.

Thomas Junk
sumber
1

Mengembalikan nol tidak bagus. Ini tidak memberi tahu Anda apa-apa. Sebagai contoh, jika suatu aplikasi mencoba mencari sesuatu dan jawabannya adalah nol untuk kedua masalah keamanan dan jika item tersebut tidak ada, lalu bagaimana Anda membedakan antara keduanya?

Respons yang berarti dapat memungkinkan aplikasi untuk membuat pilihan logis tentang apa yang harus dilakukan selanjutnya atau bagaimana menyelesaikan masalah.

Qwerky
sumber
Anda bertanya bagaimana Anda membedakan antara objek yang tidak ada, dan Anda kurang izin untuk melihatnya. Mungkin desain sistem mengharuskan Anda tidak tahu. Saya rasa kami tidak memiliki cukup informasi untuk menjawab dalam kasus khusus ini, dan tidak ada jawaban yang berfungsi dalam semua kasus. Ada kasus penggunaan yang benar-benar valid di mana, jika Anda tidak dapat melihatnya secara efektif tidak ada. Dan, ada kasus penggunaan di mana jika Anda tidak bisa melihatnya Anda harus diberi pengecualian untuk mengatakan mengapa Anda tidak bisa melihatnya.
Bryan Oakley
Apa yang Anda maksud dengan "desain sistem mengharuskan Anda tidak tahu"? Desain seperti apa itu?
Svish
2
Jika kebijakan keamanan mengatakan Anda tidak diizinkan melihatnya, maka dalam kebanyakan kasus Anda juga tidak boleh tahu bahwa itu ada. Itu membuat pengembalian "tidak ditemukan" dapat diterima dengan sempurna.
Blrfl
1

Jika akar penyebabnya adalah pengguna yang tidak diautentikasi maka saya lebih suka respons HTTP 401 yang keras mungkin dengan mengarahkan ulang ke halaman pesan-cantik (dan pemberitahuan kepada seseorang yang peduli). Penyebab terkait otorisasi lebih banyak kasus per kasus; ada argumen untuk mengembalikan kesalahan HTTP (403, katakanlah) dan argumen untuk mengembalikan kode / pesan khusus yang terbentuk dengan baik dalam respons layanan.

Pengecualian hanya boleh digunakan dalam situasi khusus dan berarti ada sesuatu yang salah. Saya tidak setuju bahwa mereka harus kelebihan beban berarti "tidak diizinkan". (Hal yang sama berlaku untuk nilai pengembalian nol: Saya tidak setuju bahwa itu harus digunakan untuk berarti "tidak diizinkan".)

Menandai
sumber
Nah, di GUI Anda bisa melakukan ini, tetapi untuk kacang menerapkan layanan yang melakukan hal-hal di belakang layar Anda hanya memiliki pengecualian dan nilai pengembalian khusus yang Anda inginkan. Saya tentu saja tidak berarti bahwa pengguna harus mendapatkan pengecualian, tetapi pengecualian misalnya dapat ditangkap di layanan web / servlet / apa pun dan kemudian melakukan apa yang sesuai. Redirect ke suatu tempat, halaman http keras 4xx, atau yang lainnya.
Svish
Poin bagus, tetapi Anda bisa menggunakan paradigma seperti AOP untuk menangkap kasus-kasus ini. Aspek dapat menguji untuk hak istimewa untuk memanggil operasi yang diberikan dan mengarahkan / mengizinkan pemrosesan untuk melanjutkan sebagaimana mestinya.
Markus
0

Untuk berperan sebagai advokat setan, saya akan berusaha mengambil sisi mengembalikan null.

Menurut pendapat saya hanya ada satu situasi di mana respons semacam ini hampir dapat diterima dan itu adalah, seperti dalam kasus ini, ketika keamanan terlibat.

Sangat mudah untuk secara tidak sengaja memberikan rincian sistem Anda yang tidak perlu diketahui orang yang tidak berwenang. Ini harus dihindari.

Ambil, misalnya, nama pengguna dan pemeriksa kata sandi. Mengembalikan kesalahan "Nama pengguna tidak ditemukan" dan kesalahan "Kata sandi salah" karena kode kesalahan yang terpisah jelas akan membuka Anda terhadap masalah keamanan serius karena seseorang pertama-tama dapat mencari nama pengguna yang valid dan kemudian mencari kata sandi. Mengembalikan "nama pengguna / kata sandi" generik akan menjadi opsi yang lebih baik.

Jadi, dalam kasus khusus ini saya akan mengatakan bahwa hampir tidak masalah untuk kembali nulltetapi saya setuju, akan sangat tidak menyenangkan untuk bekerja dengannya.

OldCurmudgeon
sumber
Ya, saya tidak setuju. Tanggapan yang tepat menurut saya akan menjadi pengecualian, tetapi yang sama untuk kedua nama pengguna tidak ditemukan dan kata sandi salah. FailedToLogin, InvalidCredentials, apa pun.
Svish
@Vish - Tetapi jika Anda mencoba untuk tidak memberikan petunjuk sama sekali tentang alasan kegagalan maka kembali nulladalah jawaban yang paling tidak membantu. Hampir semua hal lain berpotensi digunakan untuk menemukan sesuatu tentang sistem. Alasan OP mengeluh adalah karena tidak hanya nullmengembalikan tidak menjelaskan apa-apa itu bahkan tidak membantu. Itu adalah tujuan yang disengaja ... untuk tidak mengatakan apa - apa dan tidak membantu. Misi tercapai dalam pandangan saya.
OldCurmudgeon
Yah, mungkin memang begitu, tetapi saya masih mengatakan bahwa melakukan itu buruk. Setidaknya di dalam suatu sistem. Di tepi tempat pengguna akhir melihat sesuatu, maka tentu saja, saya setuju. Namun di dalam sistem, kami para pengembang adalah pengguna, dan mengapa kami ingin membuat hal-hal lebih membingungkan bagi diri kami sendiri? Seolah-olah mengembangkan perangkat lunak belum cukup sulit ...
Svish
1
Dan dengan contoh login, saya akan mengatakan itu buruk bagi pengalaman pengguna untuk tidak setidaknya mengatakan sesuatu tentang mengapa tidak ada yang terjadi ketika mereka (berpikir mereka) memasukkan kredensial mereka. Jika halaman hanya menyegarkan dan sepertinya mengabaikan usaha saya untuk masuk, saya akan berasumsi ada yang salah dengan sistem, bukan apa yang saya masukkan salah.
Svish
-2

Saya pikir return null tidak ramah, ketika klien memanggil metode ini dan mengembalikan null, klien tidak tahu apa yang terjadi dan mengapa itu mengembalikan null. Jadi kita harus membuang eksekusi yang masuk akal dan memberikan dokumentasi untuk mendeskripsikan eksekusi ini.

Tandai xie
sumber