Чому б не відкрити первинний ключ


53

В моїй освіті мені сказали, що це недосконала ідея викрити користувачеві фактичні первинні ключі (не тільки ключі DB, але й усі первинні аксесуари).

Я завжди вважав це проблемою безпеки (тому що зловмисник може намагатися читати речі не свої).

Тепер я маю перевірити, чи має право користувач все-таки отримати доступ, тож чи є інша причина цього?

Крім того, оскільки моїм користувачам доводиться отримувати доступ до даних, мені потрібно буде мати відкритий ключ для зовнішнього світу десь посередині. Тепер цей відкритий ключ має ті самі проблеми, що і первинний ключ, чи не так?


З'явився запит прикладу того, чому це робити все-таки, ось ось один. Майте на увазі, що питання стосується самого принципу не лише, якщо він застосовується в цьому прикладі. Відповіді, що стосуються інших ситуацій, явно вітаються.

Додаток (Web, Mobile), який здійснює діяльність, має декілька інтерфейсів користувача та принаймні один автоматизований API для міжсистемної комунікації (наприклад, бухгалтерія хоче знати, скільки стягувати плату з клієнта на основі зробленого). У додатку є кілька клієнтів, тому розділення їх даних (логічно, що дані зберігаються в одній БД) є обов'язковою системою. Кожен запит перевірятиметься на дійсність незалежно від того.

Діяльність дуже тонка, зерниста, тому вона знаходиться разом у якомусь контейнерному об'єкті, і називаємо це "Завдання".

Три випадки використання:

  1. Користувач A хоче надіслати Користувача B на якесь завдання, щоб він надсилав йому посилання (HTTP), щоб виконати там деяку діяльність.
  2. Користувач B повинен вийти за межі будівлі, щоб він відкрив Завдання на своєму мобільному пристрої.
  3. Бухгалтерський облік хоче стягувати плату з клієнта за завдання, але використовує систему обліку третьої сторони, яка автоматично завантажує завдання / діяльність деяким кодом, який посилається на REST - API програми

Кожен із випадків використання вимагає (або стає простішим, якщо) агента мати якийсь адресаційний ідентифікатор для завдання та діяльності.


3
пов'язано: чи повинен сурогатний ключ коли-небудь піддаватися дії користувача? "Вам потрібно бути готовим до будь-якого ідентифікатора, який піддається користувачам / клієнтам, які потребують змін, а зміна ідентичності рядка в базі даних та розповсюдження цієї зміни на всі закордонні ключі просто вимагає зламати дані ..."
гнат

@gnat ON UPDATE CASCADEбув зроблений для цього (специфічно для mysql?), хоча якщо проблема полягає в безпеці, то перевірка доступу повинна бути в бекенде, а не довіряти користувачеві в будь-якому випадку
Izkata

2
@Izkata Так, за винятком випадків, коли ви посилаєте їх на інший сховище даних (UserID в LDAP як простий приклад), або вам потрібно буде відновити деякі дані з резервної копії. Гнат має хороший момент.
Анджело Фукс

Чи можете ви пелас детально розглянути, що ви маєте на увазі під "викриттям"? Фактичний приклад може допомогти. :-)
CodeCaster

"виставляти" означає показувати це користувачеві. (Під користувачем я маю на увазі людину здебільшого, але питання здається справедливим і для машин)
Angelo Fuchs

Відповіді:


38

Крім того, оскільки моїм користувачам доводиться отримувати доступ до даних, мені потрібно буде мати відкритий ключ для зовнішнього світу десь посередині.

Саме так. Візьміть HTTP без громадянства, який інакше не знатиме, про який ресурс він повинен запитувати: він відкриває ідентифікатор вашого питання 218306в URL. Можливо, вам насправді цікаво, чи може виявлений виявлений ідентифікатор передбачуваний ?

Єдині місця, де я чув негативну відповідь на це, використовували обґрунтування: "Але вони можуть змінити ідентифікатор в URL-адресі!" . Тож вони використовували GUID замість належної авторизації.

Я можу уявити одну ситуацію, коли ви не хочете, щоб ваші ідентифікатори були передбачуваними: збирання ресурсів. Якщо у вас є веб-сайт, на якому публічно розміщуються певні ресурси, іншим може бути цікаво, і ви розміщуєте їх, як, /images/n.jpgабо /videos/n.mp4де nпросто збільшується кількість, кожен, хто шукає трафік на ваш веб-сайт і з нього, може отримати всі ваші ресурси.

Отже, щоб безпосередньо відповісти на ваше запитання: ні, це непогано безпосередньо "викрити" ідентифікатори, які мають лише значення для вашої програми, зазвичай для її роботи потрібно навіть успішно працювати.


2
Невикористовувані URL-адреси (наприклад, містять криптографічно випадковий 128-бітовий маркер) - одна з форм належної авторизації.
CodesInChaos

Правильно, як у надзвичайно чутливих до відтворення атак? Приємно для одноразового використання, як-от URL-адреса для скидання пароля, але менш для того, щоб ідентифікувати статичний ресурс, оскільки коли маркер буде відкритим, кожен може використовувати його, не маючи змоги змінити його, не порушуючи жодної законної посилання на це.
CodeCaster

гм? Очевидно, що він вимагає SSL, але це так, незалежно від того, як ви автентифікуєтесь та авторизувались. Через SSL зловмисник не може вивчити маркер (як і вони не можуть вивчити файли cookie), а також запобігає повторному нападу. Основним недоліком такого підходу є те, що ви не можете відкликати доступ для окремих користувачів, тому я вважаю за краще використовувати його лише для незмінних ресурсів. Скасовувати доступ до незмінних ресурсів безглуздо, оскільки зловмисник може просто зберігати локальну копію.
CodesInChaos

2
Мені, здається, в ці дні я нездатний висловити те, що я маю на увазі, мені шкода. Я маю на увазі використання випадкового маркера для статичного ресурсу на відміну від інкрементального ідентифікатора добре, якщо ви хочете, щоб ресурс був загальнодоступним, але не доцільним. Для будь-якого іншого використання, хоча я віддаю перевагу одноразовому використанню через скасування.
CodeCaster

1
Ні, точно моя думка. Ви можете, можливо, детальніше розібратися з тим, що ви маєте на увазі під «викриттям»?
CodeCaster

29

Не слід виставляти його, оскільки люди, які бачать його, почнуть використовувати його як свій номер рахунку, який НЕ є. Наприклад, для мого банківського рахунку я знаю, що таке номер мого рахунку. Я запам’ятав це, я використовую його по телефону з обслуговуванням клієнтів, я використовую його при заповненні форм для інших банків для здійснення переказів, для юридичних документів, для моєї послуги автоматичної оплати тощо тощо. Я не хочу це змінити. Первинний ключ (для мого облікового запису) з іншого боку, я не знаю і ніколи не бачу.
Система, що зберігає її, змінюється протягом багатьох років від однієї системи до іншої, через злиття банків, оновлення та заміну системи тощо
. Первинні ключі можуть змінюватися через деякі з цих перетворень, тому, якщо його ніколи не викривали, не записували чи не пам'ятали будь-яким постійним користувачем, який "
Ключі без ділового значення часто називають сурогатними ключами і часто (але не завжди) використовуються як первинні ключі.

btw, це навіть відбувається внутрішньо, коли люди будують інтерфейси та програми, які неправильно використовують та відкривають первинні ключі та роблять їх частиною таких систем замість них, роблячи одне - однозначно визначаючи внутрішньо запис бази даних. Я фактично дізнався вище, через 6-річний термін підтримки системи зберігання даних у лікарні.


4
+1, але те, що ви тут описуєте, насправді є сурогатним ключем. Не в кожній таблиці є сурогатний ключ, і навіть якщо він сурогат може бути не "первинним" ключем.
nvogel

2
+1 Я думав, що номер рахунку буде сурогатним ключем, але я прочитав його, і ви на 100% правильні :)
Michael Durrant

2
+1, виставляючи його користувачам, додає неявні вимоги (наприклад, залишаються статичними)
Метт

1
Чудова відповідь. Моє скорочене слово - це те, що сурогатні ключі корисні, оскільки про них ніхто не піклується, і тому ніхто не піклується про те, чи змінити ви їх чи не змінити. Якщо їх викрити, люди почнуть дбати про них.
JimmyJames

tl; dr: тому що майбутнє. Якщо щось зовнішнє покладається на ключ, речі стають безладними, якщо впровадження зміниться згодом; тому зберігайте їх більш-менш прихованими, щоб зробити речі простішими.
Адам Толлі

27

Тому що первинні ключі - це деталь реалізації.

Якщо ви мігруєте бази даних, ваші первинні ключі можуть змінитися через порядок вставки, видалення старих записів ... через кілька різних причин. Якщо ви мігруєте платформи баз даних, можливо, у вас більше немає фактичного первинного ключа. Викриття ПК над шаром доступу до даних - це непрохідна абстракція, з якою пов'язані всі проблеми зв'язку.


3
Як рівень програми однозначно ідентифікує ресурс, з якого він хоче отримати або оновити на рівні даних без первинного ключа?
CodeCaster

2
@CodeCaster - або за допомогою якогось унікального індексованого набору даних, або непублічним первинним ключем, який повертається як частина об'єкта, що постачається рівнем доступу до даних.
Теластин

1
@CodeCaster - Існує безліч способів створити маркер, який дозволяє зворотній дзвінок визначати, яка операція робиться, і, звичайно, не всі вони просто передають первинний ключ прямо.
Теластин

2
Але для цього потрібен рівень даних, щоб знати, який маркер належить (або перекладається) до якого ПК. Мені це здається додатковим шаром зайвої складності, просто задля приховування ПК. Якій цілі це служить, крім задоволення архітектора? Я погоджуюся з вашою думкою, я просто не вважаю його застосовним у реальному використанні і буду вдячний за фактичний приклад.
CodeCaster

1
@CodeCaster - Ні, середній рівень фактично виконує свою роботу і резюмує, що доступ до даних взагалі є з інтерфейсу користувача. У світі багато поганих архітекторів, але багато кращих практик розробки програм існують не просто так. Деякі програми можуть ризикувати цією витікаючою абстракцією, а деякі не можуть.
Теластин

10

Це комбінована відповідь інших (ака. Те, що я дізнався). Якщо ви хочете подати заявку на цю заяву, вам слід принаймні відмітити один з інших, як вони виконали фактичну роботу. Якщо вас більше цікавить, прочитайте натомість інші відповіді.

Ви не повинні викривати первинний ключ баз даних, а замість цього використовувати сурогатний ключ

  1. Якщо ви хочете, щоб ваші користувачі могли запам'ятати (принаймні трохи) або розпізнати ідентифікатор запису. ( Відповідь Graystone28s )
  2. Якщо ви хочете планувати заздалегідь і вважаєте, що ви можете змінити системи (База даних чи іншим чином), які, ймовірно, змінять ПК. ( Відповідь Теластіна )
  3. Якщо ви хочете переконатися, що ваші користувачі мають послідовний спосіб доступу до даних, які не змінюються, навіть якщо ваша компанія змінює право власності і ці дані мігруються в іншу систему взагалі. ( Відповідь Майкла Дюранта )
  4. Якщо ваш ПК передбачуваний (як послідовність), ваша система може зазнати проблем зі збиранням ресурсів. ( Відповідь CodeCasters ) Це застосовується лише в тому випадку, якщо у вашій системі є інформація, яку варто збирати і яка доступна будь-яким чи принаймні тим, хто має інтерес до збирання.

Примітка: Ваш створений ключ повинен бути (свого роду) зрозумілим для людини (відповідь Sqlvogels ).

Якщо у вашій системі немає потреби від 1. до 4., немає підстав не використовувати бази даних ПК як свій загальнодоступний ідентифікатор (кілька відповідей). Також безпека тут не є проблемою (кілька відповідей).


8

Однією з причин я виявив, що в повному обсязі я бачив, як кінцеві користувачі просять, щоб їх ідентифікатор щось означав (наприклад, префікс або показник року, коли він був створений). Змінити ПК важко, але сурогат набагато простіше.

Ваш первинний ключ, ймовірно, буде те, на що ви хочете, щоб ваша база даних індексувалась з міркувань продуктивності, і ви можете вчасно з технічних причин змінити її, наприклад, з числа на настанову ... ви просто не знаєте, які причини нові технології чи знання може направити вас вниз. Ваш ПК - це ваші технічні дані, відкритий ключ - для споживання кінцевими користувачами.


7
Питання: "Чи погано виставляти первинні ключі?" . Ваша відповідь: "Користувачі, можливо, хочуть мати свої ідентифікатори" . Я не маю стосунку. Я викриваю InvoiceNumber, що має значення для клієнта і його змінює, але я також розкриваю InvoiceID, який мій код використовує для однозначної ідентифікації рахунку. Вам не потрібно (а частіше не хочеться ), щоб ключ користувача був ключем зберігання. Це питання стосується останнього.
CodeCaster

Я вважаю, що це приємний приклад, тому що якщо ви переходите до версії додатка для кількох орендарів, ви можете зберігати один і той же синтаксис і мати декілька однакових рахунків InvoiceNumber(для різних орендарів), але мати різні первинні ключі - крапка (вид ) згадується у відповіді також.
відійти

1
@CodeCaster це питання насправді про "чому ви не хочете, щоб вони були однаковими"?
Анджело Фукс

У такому випадку дивіться відповідь Теластіни .
CodeCaster

2

Для більшості додатків дуже важливо, щоб ви не виставляли ключі користувачам. Для ефективного використання інформаційної системи користувачам цієї системи, як правило, потрібен спосіб ідентифікувати інформацію всередині неї та пов’язати цю інформацію з чимось у світі поза базою даних. У реляційних умовах бази даних ці ідентифікатори є ключами.

Один добре використаний шаблон дизайну полягає у створенні додаткового, чисто "технічного" ключа для таблиць баз даних як засобу абстрагування. Наприклад, щоб забезпечити стабільний (відносно незмінний) ключ, коли якийсь альтернативний ключ може змінюватися. Такі технічні ключі зазвичай не піддаються кінцевим користувачам, оскільки це підриває передбачувану абстракцію від вимог користувачів. Це не має нічого спільного з безпекою.

Проблема / непорозуміння, що маються на увазі у вашому питанні, пов'язані з невідповідним використанням терміна первинний ключ. Первинний ключ - це лише один з декількох ключів "кандидат" (кілька можливих ідентифікаторів у таблиці бази даних). Первинний ключ не обов'язково вимагає будь-якого принципово іншого властивості для будь-якого іншого ключа, тому твердження та принципи дизайну, які застосовуються спеціально до первинних ключів, а не до інших ключів, завжди підозрювані та часто помиляються.

Зважаючи на те, що зазвичай потрібно виставити ключ своєму користувачеві, яким він повинен бути? Спробуйте зробити свої ключі Знайомими, простими та стабільними. Ознайомлення та простота роблять ключі зручними для читання та запам'ятовування та допоможуть уникнути помилок введення даних. Стабільність означає ключові зміни нечасто, що також допомагає уникнути можливості неправильної ідентифікації.


1
це залежить ... від чого? Я хочу дізнатися, які причини стоять за цією загальною концепцією, щоб знати, коли її застосовувати, а коли ні.
Анджело Фукс

1
Привіт клієнту, будь ласка, дайте мені свій ідентифікатор, щоб я міг вам допомогти. Звичайно, його gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456. Хм, а як щодо вашого соціального? ... сурогатний ідентифікатор
Michael Durrant

@Michael, відповідь оновлено. Це звичний, простий і стабільний ключ?
nvogel

1

Це з коментаря до відповіді Greystone28 від CodeCaster. Це приклад того, що ви говорите:

Я виставляю InvoiceNumber, який має значення для клієнта і його змінює, але я також розкриваю InvoiceID, який мій код використовує для унікальної ідентифікації рахунку. Вам не потрібно (а частіше не хочеться), щоб ключ користувача був ключем зберігання. Це питання стосується останнього.

Якій цілі у вашій програмі слугує показ відображення InvoiceID?

Експонуючи, я припускаю, що ви маєте на увазі, що користувач може його бачити. Викрийте його лише у тому випадку, якщо користувачеві потрібно його використовувати ваш додаток. Це може бути використане технічною підтримкою або деякими адміністративними речами. Я працював з кількома програмами, які роблять це. Це полегшує надання підтримки, коли я знаю конкретний запис.


Рахунки-фактури мають природні ідентифікатори (цифри), але лише для тих, що ви пишете. А що з тими, що отримуєш? У них є рахунки InvoiceNumbers, але вони перекриваються (оскільки дві компанії використовують один і той же, і обидва надсилають вам рахунок-фактуру). У цій ситуації ваш InvoiceID унікальний, номер не є, і те, що робить його унікальним, було б ім'ям клієнта, який не є хорошим ідентифікатором даних (занадто довго, змінюється занадто часто, може містити незрозумілі символи ...)
Angelo Fuchs

@AngeloNeuschitzer - Якщо користувач може однозначно ідентифікувати рахунок-фактуру за іменем і номером Клієнта, користувачеві не потрібен ПК-рахунок InvoiceID, але база даних та базовий код можуть використовувати його. Вони взаємовиключні функції.
JeffO

Дивіться випадки 1 - 3 мого прикладу. У жодному з цих випадків Ім'я Клієнта не є корисним способом вирішення цього Об'єкта для Користувача (будь то людина чи машина). Рахунок-фактура PK є.
Анджело Фукс

1

Це цілком нормально, коли суб'єкти мають унікальний ідентифікатор, який піддається зовнішньому світу. Для деяких об'єктів можливо знайти ідентифікатор, який насправді має значення (наприклад, номер рахунку-фактури), але для інших такого ідентифікатора не існує, тому його потрібно генерувати.

Для послідовності та читабельності я вважаю гарною практикою для всіх організацій системи використовувати для свого ідентифікатора точно такий же тип та ім’я. Зазвичай цей ідентифікатор буде виставлений ( <type> getId()) у деякому абстрактному базовому класі.

З цієї ж причини кожна служба в системі (наприклад, служба виставлення рахунків-фактур) повинна надавати однакові методи доступу до об'єктів за їх ідентифікатором. Зазвичай цей метод ( findById(<type> id)) успадковується від загального інтерфейсу обслуговування або базового класу.

Цей ідентифікатор не повинен бути первинним ключем сутності, але він може бути одним. Єдине, що потрібно забезпечити, це те, що стратегія генерації ключів створює досить унікальні ідентифікатори (не потрібні універсально унікальні, але принаймні в межах системи).

Якщо пізніше система буде переміщена (велика, якщо на мій досвід), до іншої бази даних, тоді для створення ідентифікаторів не проблема використовувати іншу стратегію (не засновану на первинних ключах), поки стратегія сумісна з оригінальною.


Чи можете ви пояснити, що у вашій відповіді не було відповідено в інших?
Анджело Фукс

2
У своїй відповіді я не згоден принаймні з пунктами 2. та 3. вашого резюме. Я не думаю, що це поважні причини не використовувати ПК як ідентифікатори об'єктів.
Мутон

0

Первинний ключ є саме так, як ручка до кортежу (запис, рядок), до якого ви намагаєтесь отримати доступ як розробник. Він також використовується в референтній цілісності (обмеження іноземних ключів), і, можливо, він також має один або кілька випадків використання.

По суті, немає нічого поганого в тому, щоб відкрити його користувачам, або навіть хакерам. Тому що я не знаю про атаку, яка, наприклад, використовує первинний ключ.

Але в безпеці у нас є багато принципів (які ми приймаємо і не схвалюємо), і нам потрібно їх дотримуватися:

  1. Принцип пільги на оренду
  2. Безпека через незрозумілість

І деякі інші принципи. Що вони говорять по суті, це те, що:

Якщо вам не потрібно виставляти свої дані, навіщо вам взагалі?


Частина ручки - це там, де я згоден. Гарантія ні. Це може бути важливо для безпеки, але наявність незалежного внутрішнього ключа, який не видно користувачеві, здебільшого не стосується безпеки. Я б назвав це приємним побічним ефектом.
JensG

Чому б ти: дивись приклад, який я додав до запитання.
Анджело Фукс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.