Mengapa tidak membuka kunci utama?

53

Dalam pendidikan saya, saya telah diberitahu bahwa itu adalah ide yang salah untuk mengekspos kunci primer yang sebenarnya (tidak hanya kunci DB, tetapi semua aksesor utama) kepada pengguna.

Saya selalu menganggapnya sebagai masalah keamanan (karena penyerang dapat mencoba membaca barang bukan milik mereka).

Sekarang saya harus memeriksa apakah pengguna diperbolehkan mengakses, jadi apakah ada alasan berbeda di balik itu?

Juga, karena pengguna saya harus mengakses data, saya harus memiliki kunci publik untuk dunia luar di antara keduanya. Sekarang kunci publik memiliki masalah yang sama dengan kunci primer, bukan?


Sudah ada permintaan contoh tentang mengapa melakukan itu, jadi di sini ada satu. Ingatlah bahwa pertanyaan yang dimaksudkan adalah tentang prinsip itu sendiri tidak hanya jika itu berlaku dalam contoh ini. Jawaban yang membahas situasi lain disambut secara eksplisit.

Aplikasi (Web, Mobile) yang menangani aktivitas, memiliki banyak UI dan setidaknya satu API otomatis untuk komunikasi antar sistem (mis. Departemen akuntansi ingin tahu berapa besar biaya pelanggan berdasarkan apa yang telah dilakukan). Aplikasi memiliki banyak pelanggan sehingga pemisahan data mereka (secara logis, data disimpan dalam DB yang sama) harus dimiliki oleh sistem. Setiap permintaan akan diperiksa validitasnya, apa pun yang terjadi.

Aktivitas granular sangat halus sehingga bersama-sama di beberapa objek kontainer, sebut saja "Tugas".

Tiga usecases:

  1. Pengguna A ingin mengirim Pengguna B ke beberapa Tugas sehingga ia mengiriminya tautan (HTTP) untuk menyelesaikan Aktivitas di sana.
  2. Pengguna B harus pergi ke luar gedung sehingga ia membuka Tugas di perangkat selulernya.
  3. Akuntansi ingin menagih pelanggan untuk Tugas, tetapi menggunakan sistem akuntansi pihak ketiga yang secara otomatis memuat Tugas / Kegiatan dengan beberapa kode yang merujuk pada REST - API Aplikasi

Setiap usecases membutuhkan (atau semakin mudah jika) agen untuk memiliki beberapa pengidentifikasi yang dapat dialamatkan untuk Tugas dan Aktivitas.

Angelo Fuchs
sumber
3
terkait: Haruskah kunci pengganti pernah terpapar ke pengguna? "Anda harus siap untuk setiap pengidentifikasi yang terpapar ke pengguna / pelanggan yang perlu diubah, dan mengubah identitas baris dalam database dan menyebarkan bahwa perubahan ke semua kunci asing hanya meminta untuk memecah data ..."
Agak
@gnat ON UPDATE CASCADEdibuat untuk itu (spesifik mysql?), walaupun jika masalahnya adalah keamanan maka pemeriksaan akses harus di backend dan tidak mempercayai pengguna
Izkata
2
@Izkata Ya, kecuali ketika Anda mereferensikannya di datastore yang berbeda (UserID dalam LDAP sebagai contoh sederhana), atau Anda harus memulihkan sebagian data dari cadangan. nyamuk punya poin bagus di sana.
Angelo Fuchs
Bisakah Anda pelase menguraikan apa yang Anda maksud dengan "mengekspos"? Contoh aktual mungkin membantu. :-)
CodeCaster
"mengekspos" berarti menunjukkannya kepada pengguna. (Menurut pengguna, kebanyakan saya adalah manusia, tetapi pertanyaannya tampaknya juga berlaku untuk mesin)
Angelo Fuchs

Jawaban:

38

Juga, karena pengguna saya harus mengakses data, saya harus memiliki kunci publik untuk dunia luar di antara keduanya.

Persis. Ambil HTTP stateless, yang seharusnya tidak tahu sumber daya apa yang harus diminta: itu memaparkan ID pertanyaan Anda 218306di URL. Mungkin Anda benar-benar bertanya-tanya apakah pengidentifikasi yang terbuka dapat diprediksi ?

Satu-satunya tempat di mana saya mendengar jawaban negatif untuk itu, menggunakan alasan: "Tetapi mereka dapat mengubah ID di URL!" . Jadi mereka menggunakan GUID alih-alih menerapkan otorisasi yang tepat.

Saya bisa membayangkan satu situasi di mana Anda tidak ingin pengidentifikasi Anda dapat diprediksi: pemanenan sumber daya. Jika Anda memiliki situs yang host publik sumber daya tertentu yang lain mungkin menarik dalam, dan Anda meng-host mereka seperti /images/n.jpgatau /videos/n.mp4di mana nsaja adalah nomor incrementing, siapa pun yang melihat lalu lintas ke dan dari situs web Anda dapat panen semua sumber daya Anda.

Jadi, untuk langsung menjawab pertanyaan Anda: tidak, tidak buruk untuk langsung "mengekspos" pengidentifikasi yang hanya memiliki makna pada program Anda, biasanya bahkan diperlukan agar program Anda berhasil beroperasi.

CodeCaster
sumber
2
Url unguessable (mis. Mengandung token 128 bit kriptografis acak) adalah salah satu bentuk otorisasi yang tepat.
CodesInChaos
Pantas dalam sangat sensitif terhadap serangan replay? Ini bagus untuk penggunaan satu kali seperti URL penyetelan ulang kata sandi, tetapi lebih sedikit untuk mengidentifikasi sumber daya statis, karena begitu token keluar di tempat terbuka siapa pun dapat menggunakannya, tanpa Anda dapat mengubahnya tanpa melanggar referensi yang sah untuk saya t.
CodeCaster
hm Jelas itu membutuhkan SSL, tapi itu masalahnya tidak peduli bagaimana Anda mengotentikasi dan mengotorisasi. Lebih dari SSL, seorang penyerang tidak dapat mempelajari token (sama seperti mereka tidak dapat mempelajari cookie) dan juga mencegah serangan replay. Kelemahan utama dari pendekatan ini adalah Anda tidak dapat mencabut akses untuk masing-masing pengguna, jadi saya lebih suka menggunakannya hanya untuk sumber daya yang tidak dapat diubah. Mencabut akses ke sumber daya yang tidak dapat diubah tidak ada artinya karena penyerang bisa dengan mudah menyimpan salinan lokal.
CodesInChaos
2
Saya tampaknya tidak mampu hari ini untuk benar-benar mengekspresikan apa yang saya maksud, saya minta maaf. Maksud saya menggunakan token acak untuk sumber daya statis sebagai lawan ID tambahan baik-baik saja, jika Anda ingin sumber daya dapat diakses publik tetapi tidak dapat ditebak. Untuk penggunaan lain meskipun saya lebih suka menggunakan satu kali, karena hal pencabutan.
CodeCaster
1
Tidak ada, maksud saya tepatnya. Bisakah Anda menguraikan apa yang Anda maksud dengan "mengekspos"?
CodeCaster
29

Anda tidak boleh mengeksposnya karena orang yang melihatnya akan mulai menggunakannya sebagai 'nomor akun' mereka yang BUKAN. Misalnya, untuk rekening bank saya, saya tahu nomor rekening saya. Saya sudah hafal, saya menggunakannya di telepon dengan layanan pelanggan, saya menggunakannya ketika mengisi formulir untuk bank lain untuk melakukan transfer, untuk dokumen hukum, untuk layanan pembayaran otomatis saya, dll, dll. Saya tidak ingin itu berubah. Kunci utama (untuk akun saya) di sisi lain, saya tidak tahu atau tidak pernah melihat.
Sistem yang menyimpannya berubah selama bertahun-tahun dari satu sistem ke sistem lainnya, melalui penggabungan bank, peningkatan dan penggantian sistem, dll. Dll
. Kunci utama dapat berubah melalui beberapa transformasi ini, jadi jika tidak pernah diekspos, dituliskan atau diingat oleh pengguna biasa yang '
Kunci tanpa makna bisnis sering disebut kunci pengganti dan sering (tetapi tidak selalu) digunakan sebagai kunci utama.

Namun, ini bahkan terjadi secara internal ketika orang membangun antarmuka dan program yang menyalahgunakan dan mengekspos kunci primer dan menjadikannya bagian dari sistem semacam itu alih-alih hanya melakukan satu hal - secara unik mengidentifikasi catatan basis data secara internal. Saya benar-benar belajar hal di atas selama 6 tahun mendukung sistem data warehouse di rumah sakit.

Michael Durrant
sumber
4
+1 tetapi apa yang Anda gambarkan di sini sebenarnya adalah kunci pengganti . Tidak setiap tabel memiliki kunci pengganti dan bahkan jika itu pengganti mungkin bukan kunci "utama".
nvogel
2
+1 Saya pikir nomor akun akan menjadi kunci pengganti tetapi saya membacanya dan Anda 100% benar :)
Michael Durrant
2
+1 yang mengeksposnya kepada pengguna menambahkan persyaratan implisit (mis. Tetap statis)
Matt
1
Jawaban yang bagus Cara singkat saya mengatakan ini adalah bahwa kunci pengganti berguna karena tidak ada yang peduli tentang mereka dan karena itu tidak ada yang peduli jika Anda mengubahnya atau tidak mengubahnya. Jika Anda mengeksposnya, orang akan mulai peduli tentang mereka.
JimmyJames
tl; dr: karena masa depan. Jika sesuatu eksternal datang untuk bergantung pada kunci, hal-hal menjadi berantakan jika implementasi berubah nanti; jadi jaga agar mereka lebih atau kurang tersembunyi untuk mempermudah.
Adam Tolley
27

Karena Primary Key adalah detail implementasi.

Jika Anda memigrasi basis data, kunci utama Anda mungkin berubah karena urutan penyisipan, penghapusan catatan lama ... beberapa alasan berbeda. Jika Anda memigrasikan platform basis data Anda mungkin tidak lagi memiliki kunci primer yang sebenarnya sama sekali. Mengekspos PK di atas lapisan akses data adalah abstraksi yang bocor, dengan semua masalah kopling yang menyertainya.

Telastyn
sumber
3
Bagaimana sebuah lapisan aplikasi secara unik mengidentifikasi sumber daya yang ingin diambil atau memperbarui dalam lapisan data tanpa kunci primer?
CodeCaster
2
@CodeCaster - baik oleh beberapa set data unik yang diindeks, atau dengan kunci primer non-publik yang dikembalikan sebagai bagian dari objek yang disediakan oleh lapisan akses data.
Telastyn
1
@CodeCaster - Ada banyak cara untuk membuat token yang memungkinkan panggilan balik untuk menentukan operasi apa yang sedang dilakukan, dan tentu saja tidak semua dari mereka hanya melewati kunci utama.
Telastyn
2
Tetapi itu membutuhkan lapisan data untuk mengetahui token mana yang menjadi milik (atau diterjemahkan menjadi) PK mana. Bagi saya itu terdengar seperti lapisan tambahan kompleksitas yang tidak perlu, hanya demi menyembunyikan PK. Tujuan apa yang dilayaninya, selain untuk memuaskan arsitek? Saya setuju dengan poin Anda, saya hanya tidak menemukan itu berlaku dalam penggunaan dunia nyata dan akan menghargai contoh yang sebenarnya.
CodeCaster
1
@CodeCaster - Tidak, tingkat menengah sebenarnya melakukan tugasnya dan abstrak bahwa ada akses data sama sekali dari UI. Ada banyak arsitek buruk di dunia, tetapi banyak praktik terbaik dari desain program ada karena suatu alasan. Beberapa aplikasi dapat mengambil risiko abstraksi yang bocor dan beberapa tidak.
Telastyn
10

Ini adalah jawaban kombinasi dari yang lain (alias. Apa yang telah saya pelajari). Jika Anda merasa ingin memperbaiki yang ini, Anda setidaknya harus memilih salah satu dari yang lain dan mereka melakukan pekerjaan yang sebenarnya. Jika Anda lebih tertarik, baca jawaban lain sebagai gantinya.

Anda tidak boleh mengekspos kunci primer database tetapi menggunakan kunci pengganti

  1. Jika Anda ingin pengguna Anda dapat mengingat (setidaknya sedikit) atau mengenali pengenal entri. ( Jawaban Graystone28s )
  2. Jika Anda ingin merencanakan ke depan dan mempertimbangkan bahwa Anda mungkin mengubah sistem (Database atau lainnya) yang kemungkinan akan mengubah PK Anda. ( Jawaban Telastyns )
  3. Jika Anda ingin memastikan pengguna Anda memiliki cara yang konsisten untuk mengakses data yang tidak akan berubah bahkan jika perusahaan Anda mengubah kepemilikan dan data tersebut dimigrasikan ke dalam sistem yang berbeda sama sekali. ( Jawaban Michael Durrants )
  4. Jika PK Anda dapat diprediksi (seperti urutan) sistem Anda dapat mengalami masalah panen sumber daya. ( Jawaban CodeCasters ) Ini hanya berlaku jika sistem Anda memiliki informasi yang layak dipanen dan dapat diakses oleh siapa saja atau setidaknya seseorang yang memiliki kepentingan memanen.

Catatan: Kunci yang Anda buat harus (agak) dipahami manusia ( Sqlvogels Answer ).

Jika sistem Anda tidak perlu 1. hingga 4. maka tidak ada alasan untuk tidak menggunakan database PK sebagai pengidentifikasi publik Anda (beberapa jawaban). Keamanan juga tidak menjadi masalah di sini (beberapa jawaban).

Angelo Fuchs
sumber
8

Salah satu alasan saya telah menemukan, dalam waktu yang penuh saya telah melihat pengguna akhir meminta bahwa pengenal mereka berarti sesuatu (seperti memiliki awalan, atau indikator tahun itu ditetapkan). Mengubah PK itu sulit, tetapi ibu pengganti jauh lebih mudah.

Kunci utama Anda kemungkinan akan menjadi sesuatu yang Anda inginkan pengindeksan database Anda untuk alasan kinerja, dan Anda mungkin pada waktunya karena alasan teknis mengubahnya misalnya dari nomor ke panduan ... Anda tidak tahu apa alasan teknologi baru atau pengetahuan mungkin membimbing Anda. Pk Anda adalah item teknis data Anda, kunci publik adalah untuk konsumsi pengguna akhir.

Wayne M.
sumber
7
Pertanyaannya adalah: "Apakah buruk membuka kunci primer?" . Jawaban Anda: "Pengguna mungkin ingin memiliki pengidentifikasi sendiri" . Saya tidak mengerti hubungannya. Saya mengekspos InvoiceNumber, yang memiliki arti untuk dan dapat diubah oleh pelanggan, tetapi saya juga mengekspos InvoiceID, yang digunakan kode saya untuk secara unik mengidentifikasi faktur. Anda tidak harus (dan lebih sering tidak mau ) membiarkan kunci-pengguna menjadi kunci-penyimpanan. Pertanyaan ini tentang yang terakhir.
CodeCaster
Saya pikir ini adalah contoh yang bagus karena jika Anda pindah ke versi multi-penyewa APP Anda, Anda dapat menyimpan sintaks yang sama dan memiliki beberapa faktur yang sama InvoiceNumber(untuk penyewa yang berbeda) tetapi memiliki kunci primer yang berbeda - titik (jenis ) disebutkan dalam jawaban juga.
Merujuk kembali
1
@CodeCaster pertanyaan ini sebenarnya tentang "kenapa kamu tidak ingin mereka sama"?
Angelo Fuchs
Dalam hal itu lihat jawaban Telastyn .
CodeCaster
2

Untuk sebagian besar aplikasi, sangat penting bagi Anda untuk mengekspos kunci kepada pengguna. Untuk menggunakan sistem informasi secara efektif, pengguna sistem itu biasanya membutuhkan cara untuk mengidentifikasi informasi di dalamnya dan menghubungkan informasi itu dengan sesuatu di dunia di luar basis data. Dalam istilah basis data relasional, pengidentifikasi tersebut adalah kunci.

Salah satu pola desain yang digunakan adalah untuk membuat kunci tambahan, murni "teknis" untuk tabel database sebagai sarana abstraksi. Misalnya untuk memberikan kunci yang stabil (relatif tidak berubah) di mana beberapa kunci alternatif dapat berubah. Kunci teknis semacam itu biasanya tidak terpapar kepada pengguna akhir karena hal itu merusak abstraksi yang dimaksudkan dari persyaratan pengguna. Itu tidak ada hubungannya dengan keamanan.

Masalah / kesalahpahaman tersirat dalam pertanyaan Anda adalah karena penggunaan yang tidak tepat dari istilah kunci primer . Kunci utama hanya satu di antara beberapa kunci "kandidat" (beberapa kemungkinan pengidentifikasi dalam tabel database). Kunci utama tidak selalu memerlukan properti yang berbeda secara fundamental untuk kunci lain sehingga pernyataan dan prinsip desain yang berlaku khusus untuk kunci primer dan tidak untuk kunci lain selalu dicurigai dan sering salah.

Mengingat bahwa Anda biasanya perlu mengekspos kunci kepada pengguna Anda, apa yang seharusnya menjadi kunci itu? Cobalah untuk membuat kunci Anda Akrab, Sederhana dan Stabil. Keakraban dan kesederhanaan membuat kunci mudah dibaca dan diingat dan akan membantu menghindari kesalahan entri data. Stabilitas berarti perubahan kunci yang jarang yang juga membantu menghindari kemungkinan kesalahan identifikasi.

nvogel
sumber
1
itu tergantung ... pada apa? Saya ingin belajar apa alasan di balik konsep generik untuk mengetahui kapan menerapkannya dan kapan tidak.
Angelo Fuchs
1
Hai Pelanggan, tolong beri saya id Anda sehingga saya dapat membantu Anda. Tentu, gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456. Hmm, bagaimana dengan sosial Anda? ... surrogate id
Michael Durrant
@Michael, Jawaban diperbarui. Apakah itu kunci yang akrab, sederhana dan stabil?
nvogel
1

Ini dari komentar pada jawaban Greystone28 oleh CodeCaster. Ini adalah contoh dari apa yang Anda katakan:

Saya mengekspos InvoiceNumber, yang memiliki arti untuk dan dapat diubah oleh pelanggan, tetapi saya juga mengekspos InvoiceID, yang digunakan kode saya untuk mengidentifikasi faktur secara unik. Anda tidak harus (dan lebih sering tidak mau) membiarkan kunci-pengguna menjadi kunci-penyimpanan. Pertanyaan ini tentang yang terakhir.

Apa tujuan dalam aplikasi Anda yang memutar layanan InvoiceID?

Dengan mengekspos, saya berasumsi maksud Anda pengguna dapat melihatnya. Hanya mengeksposnya jika pengguna membutuhkannya untuk menggunakan aplikasi Anda. Ini dapat digunakan oleh dukungan teknis atau beberapa hal administratif. Saya telah bekerja dengan beberapa aplikasi yang melakukan ini. Itu membuatnya lebih mudah untuk memberikan dukungan ketika saya tahu catatan spesifik yang dimaksud.

JeffO
sumber
Faktur memiliki pengidentifikasi alami (angka) tetapi hanya untuk yang Anda tulis. Bagaimana dengan yang Anda dapatkan? Mereka memiliki InvoiceNumber tetapi mereka tumpang tindih (karena dua perusahaan menggunakan yang sama dan keduanya mengirimkan faktur kepada Anda). Dalam situasi ini InvoiceID Anda unik, Nomor tidak dan apa yang membuatnya unik adalah Customername yang bukan pengenal yang baik untuk data (terlalu lama, perubahan terlalu sering, mungkin mengandung karakter yang tidak jelas ...)
Angelo Fuchs
@AngeloNeuschitzer - Jika pengguna dapat secara unik mengidentifikasi faktur berdasarkan nama dan nomor Pelanggan, pengguna tidak memerlukan PK Faktur, tetapi database dan kode yang mendasarinya dapat menggunakannya. Mereka adalah fungsi yang saling eksklusif.
JeffO
Lihat kasus 1 - 3 dari contoh saya. Dalam kasus apa pun, Nama Pelanggan adalah cara yang berguna untuk menangani Obyek untuk Pengguna (baik manusia atau mesin). InvoiceID PK adalah.
Angelo Fuchs
1

Ini benar-benar normal karena entitas memiliki pengidentifikasi unik yang terpapar ke dunia luar. Untuk beberapa objek dimungkinkan untuk menemukan pengidentifikasi yang benar-benar memiliki makna (misalnya nomor faktur) tetapi untuk yang lain tidak ada pengidentifikasi tersebut dan oleh karena itu harus dihasilkan.

Demi konsistensi dan keterbacaan, saya menemukan ini praktik yang baik bagi semua entitas dalam sistem untuk menggunakan jenis dan nama yang sama persis untuk pengenal mereka. Biasanya pengidentifikasi ini akan diekspos ( <type> getId()) di beberapa kelas dasar abstrak.

Untuk alasan yang sama, setiap layanan dalam sistem (misalnya layanan faktur) harus menyediakan metode yang identik untuk mengakses entitas dengan pengidentifikasi mereka. Biasanya metode ini ( findById(<type> id)) akan diwarisi dari antarmuka layanan umum atau kelas dasar.

Identifier ini tidak harus menjadi kunci utama dari entitas tetapi dapat menjadi satu. Satu-satunya hal yang harus dipastikan adalah bahwa strategi generasi kunci menghasilkan pengidentifikasi unik yang cukup (tidak perlu unik secara universal tetapi setidaknya dalam sistem).

Jika sistem ini kemudian dimigrasikan (besar jika menurut pengalaman saya) ke database lain maka itu bukan masalah untuk menggunakan strategi yang berbeda (tidak didasarkan pada kunci primer) untuk membuat pengidentifikasi selama strategi tersebut kompatibel dengan yang asli.

Muton
sumber
Bisakah Anda menjelaskan apa jawaban Anda yang belum dijawab?
Angelo Fuchs
2
Dalam jawaban saya, saya tidak setuju setidaknya dengan poin 2. dan 3. dari ringkasan Anda. Saya tidak berpikir ini adalah alasan yang sah untuk tidak menggunakan PK sebagai pengidentifikasi objek.
Muton
0

Kunci primer ada di sana, sama seperti pegangan untuk tuple (catatan, baris) yang Anda coba akses sebagai pengembang. Ini juga digunakan dalam integritas referensial (batasan kunci asing), dan mungkin memiliki satu atau lebih kasus penggunaan juga.

Pada dasarnya, tidak ada yang buruk tentang mengeksposnya kepada pengguna, atau bahkan peretas. Karena saya tidak tahu tentang serangan yang menggunakan kunci utama misalnya.

Namun dalam keamanan, kami memiliki banyak prinsip (yang kami terima dan tidak setujui) dan kami harus mematuhinya:

  1. Prinsip hak istimewa sewa
  2. Keamanan melalui ketidakjelasan

Dan beberapa prinsip lainnya. Apa yang mereka katakan pada dasarnya adalah:

Jika Anda tidak perlu memaparkan data Anda, mengapa Anda melakukannya?

Saeed Neamati
sumber
Bagian pegangan adalah tempat saya setuju. Keamanan tidak. Ini mungkin relevan dengan keamanan, tetapi memiliki kunci internal independen yang tidak terlihat oleh pengguna sebagian besar sebenarnya bukan tentang keamanan. Saya akan menyebutnya efek samping yang bagus.
JensG
Mengapa Anda: lihat contoh yang saya tambahkan ke pertanyaan.
Angelo Fuchs