Dlaczego nie ujawnić klucza podstawowego

53

W mojej edukacji powiedziano mi, że wadliwym pomysłem jest udostępnianie użytkownikowi rzeczywistych kluczy podstawowych (nie tylko kluczy DB, ale wszystkich głównych akcesorów).

Zawsze myślałem, że to problem z bezpieczeństwem (ponieważ osoba atakująca może próbować czytać rzeczy, które nie są ich własnością).

Teraz muszę sprawdzić, czy użytkownik może mimo to uzyskać dostęp, więc czy kryje się za tym inny powód?

Ponadto, ponieważ moi użytkownicy i tak muszą uzyskać dostęp do danych, muszę mieć gdzieś pomiędzy nimi klucz publiczny dla świata zewnętrznego. Teraz, gdy klucz publiczny ma takie same problemy jak klucz podstawowy, prawda?


W każdym razie pojawiła się prośba o przykład, dlaczego to zrobić, więc oto jeden. Należy pamiętać, że pytanie ma dotyczyć samej zasady, nie tylko jeśli ma zastosowanie w tym przykładzie. Odpowiedzi dotyczące innych sytuacji są wyraźnie mile widziane.

Aplikacja (internetowa, mobilna), która obsługuje aktywność, ma wiele interfejsów użytkownika i co najmniej jeden automatyczny interfejs API do komunikacji międzysystemowej (np. Dział księgowości chce wiedzieć, ile obciążyć klienta na podstawie tego, co zostało zrobione). Aplikacja ma wielu klientów, więc oddzielenie ich danych (logicznie dane są przechowywane w tej samej bazie danych) jest obowiązkowym elementem systemu. Każde żądanie zostanie sprawdzone pod kątem ważności bez względu na wszystko.

Aktywność jest bardzo szczegółowa, dlatego jest połączona w jakimś obiekcie kontenerowym, nazwijmy to „Zadaniem”.

Trzy przypadki użycia:

  1. Użytkownik A chce wysłać użytkownika B do jakiegoś Zadania, więc wysyła mu link (HTTP), aby wykonać tam Aktywność.
  2. Użytkownik B musi wyjść na zewnątrz budynku, aby otworzyć zadanie na swoim urządzeniu mobilnym.
  3. Księgowość chce obciążyć klienta za zadanie, ale korzysta z zewnętrznego systemu księgowego, który automatycznie ładuje zadanie / działanie za pomocą kodu odnoszącego się do interfejsu API REST aplikacji

Każda z przypadków użycia wymaga (lub staje się łatwiejsza, jeśli) agenta, aby mieć adresowalny identyfikator dla zadania i działania.

Angelo Fuchs
źródło
3
powiązane: Czy klucz zastępczy powinien być kiedykolwiek udostępniony użytkownikowi? „Musisz być przygotowany na każdy identyfikator, który jest narażony na potrzebę zmiany użytkowników / klientów, a zmiana tożsamości wiersza w bazie danych i propagowanie tej zmiany do wszystkich kluczy obcych wymaga jedynie przerwania danych ...”
komara
@gnat ON UPDATE CASCADEzostał stworzony do tego (specyficzny dla mysql?), chociaż jeśli problemem jest bezpieczeństwo, to kontrola dostępu powinna znajdować się na
backendie
2
@Izkata Tak, z wyjątkiem sytuacji, gdy odwołujesz się do nich w innym magazynie danych (UserID w LDAP jako prosty przykład) lub musisz odzyskać niektóre dane z kopii zapasowej. komar ma tu rację.
Angelo Fuchs,
Czy potrafisz wyjaśnić, co masz na myśli, mówiąc „narażać”? Rzeczywisty przykład może pomóc. :-)
CodeCaster
„ujawniać” oznacza pokazywanie go użytkownikowi. (Przez użytkownika mam na myśli głównie człowieka, ale pytanie wydaje się dotyczyć także maszyn)
Angelo Fuchs,

Odpowiedzi:

38

Ponadto, ponieważ moi użytkownicy i tak muszą uzyskać dostęp do danych, muszę mieć gdzieś pomiędzy nimi klucz publiczny dla świata zewnętrznego.

Dokładnie. Weźmy bezpaństwowego HTTP, który w przeciwnym razie nie wiedziałby, jakiego zasobu powinien zażądać: ujawnia identyfikator pytania 218306w adresie URL. Być może zastanawiasz się, czy ujawniony identyfikator może być przewidywalny ?

Jedyne miejsca, w których usłyszałem negatywną odpowiedź, posłużyły się uzasadnieniem: „Ale mogą zmienić identyfikator w adresie URL!” . Użyli więc identyfikatorów GUID zamiast implementacji właściwej autoryzacji.

Mogę sobie wyobrazić jedną sytuację, w której nie chcesz, aby twoje identyfikatory były przewidywalne: pozyskiwanie zasobów. Jeśli masz witrynę publicznie udostępniającą pewne zasoby, w której inni mogą być zainteresowani, i hostujesz je w podobny sposób /images/n.jpglub /videos/n.mp4gdzie njest tylko rosnąca liczba, każdy, kto patrzy na ruch do i z Twojej witryny, może zebrać wszystkie twoje zasoby.

Tak więc, aby bezpośrednio odpowiedzieć na twoje pytanie: nie, nie jest źle „bezpośrednio” ujawniać identyfikatory, które mają znaczenie tylko dla twojego programu, zwykle jest to nawet wymagane, aby Twój program działał poprawnie.

CodeCaster
źródło
2
Niewysłowione adresy URL (np. Zawierające kryptograficznie losowy token 128-bitowy) są jedną z form prawidłowej autoryzacji.
CodesInChaos
Właściwy, jak w przypadku bardzo wrażliwych na ataki powtórkowe? Jest to przydatne w przypadku jednorazowego użycia, takiego jak adres URL resetowania hasła, ale w mniejszym stopniu, aby zidentyfikować zasób statyczny, ponieważ gdy token jest już otwarty, każdy może go użyć, bez możliwości zmiany go bez złamania jakiegokolwiek uzasadnionego odniesienia do to.
CodeCaster,
hm? Oczywiście wymaga SSL, ale tak jest bez względu na sposób uwierzytelnienia i autoryzacji. Za pośrednictwem protokołu SSL atakujący nie może nauczyć się tokena (tak jak nie może nauczyć się plików cookie), a także zapobiega atakom polegającym na powtórce. Główną wadą tego podejścia jest to, że nie można cofnąć dostępu poszczególnym użytkownikom, dlatego wolę używać go tylko dla niezmiennych zasobów. Odwołanie dostępu do niezmiennych zasobów jest bez znaczenia, ponieważ osoba atakująca może po prostu przechowywać lokalną kopię.
CodesInChaos
2
Wygląda na to, że w dzisiejszych czasach nie jestem w stanie wyrazić tego, co mam na myśli, przepraszam. Mam na myśli użycie losowego tokena dla zasobu statycznego, w przeciwieństwie do przyrostowego identyfikatora, jest w porządku, jeśli chcesz, aby zasób był publicznie dostępny, ale nie można go zgadnąć. Dla każdego innego zastosowania wolałbym jednak jednorazowe użycie, z powodu odwołania.
CodeCaster,
1
Nie, dokładnie o to mi chodzi. Czy możesz zatem rozwinąć kwestię „ujawniać”?
CodeCaster
29

Nie powinieneś go ujawniać, ponieważ ludzie, którzy go zobaczą, zaczną używać go jako „numeru konta”, którym NIE jest. Na przykład dla mojego konta bankowego wiem, jaki jest mój numer konta. Zapamiętałem go, używam go przez telefon z obsługą klienta, używam go do wypełniania formularzy dla innych banków w celu dokonywania przelewów, dokumentów prawnych, mojej usługi automatycznych płatności itp. Nie chcę to zmienić. Z drugiej strony, klucz podstawowy (dla mojego konta) nie wiem ani nie widzę.
System, który go przechowuje, zmienia się z biegiem lat z jednego systemu do drugiego, poprzez fuzje banków, modernizacje i wymiany systemów itp
. Klucze podstawowe mogą ulec zmianie w wyniku niektórych z tych przekształceń, więc jeśli nigdy nie zostały ujawnione, spisane lub zapamiętane przez każdego zwykłego użytkownika, który „
Klucze bez znaczenia biznesowego są często nazywane kluczami zastępczymi i często (choć nie zawsze) są używane jako klucze podstawowe.

przy okazji, dzieje się tak nawet wewnętrznie, gdy ludzie budują interfejsy i programy, które niewłaściwie używają i ujawniają klucze podstawowe i sprawiają, że stają się częścią takich systemów, zamiast robić tylko jedną rzecz - jednoznaczne wewnętrzne identyfikowanie rekordu bazy danych. Tak naprawdę nauczyłem się tego przez 6 lat pracy w systemie hurtowni danych w szpitalu.

Michael Durrant
źródło
4
+1, ale to, co tu opisujesz, jest w rzeczywistości kluczem zastępczym . Nie każda tabela ma klucz zastępczy, a nawet jeśli tak, to może nie być kluczem „podstawowym”.
nvogel
2
+1 Myślałem, że numer konta będzie kluczem zastępczym, ale przeczytałem go, a masz 100% poprawność :)
Michael Durrant
2
Dawanie +1 użytkownikom dodaje domniemane wymagania (np. Pozostają statyczne)
Matt
1
Świetna odpowiedź. Mój skrótowy sposób powiedzenia tego jest taki, że klucze zastępcze są użyteczne, ponieważ nikt nie dba o nie i dlatego nie obchodzi ich, czy je zmienisz, czy nie. Jeśli je zdemaskujesz, ludzie zaczną się nimi przejmować.
JimmyJames
tl; dr: ponieważ przyszłość. Jeśli coś zewnętrznego opiera się na kluczu, sprawy stają się nieuporządkowane, jeśli implementacja zmieni się później; więc trzymaj je mniej więcej w ukryciu, aby było łatwiej
Adam Tolley,
27

Ponieważ klucze podstawowe są szczegółami implementacji.

W przypadku migracji baz danych klucze podstawowe mogą ulec zmianie z powodu kolejności wstawiania, usuwania starych rekordów ... z kilku różnych powodów. Jeśli przeprowadzasz migrację platform baz danych , możesz w ogóle nie mieć rzeczywistego klucza podstawowego. Ujawnienie PK powyżej warstwy dostępu do danych jest nieszczelną abstrakcją, z którą wiążą się wszystkie obawy związane z łączeniem.

Telastyn
źródło
3
W jaki sposób warstwa aplikacji jednoznacznie identyfikuje zasób, który chce odzyskać lub zaktualizować w warstwie danych bez klucza podstawowego?
CodeCaster
2
@CodeCaster - albo przez jakiś unikalny indeksowany zestaw danych, albo przez niepubliczny klucz podstawowy zwracany jako część obiektu dostarczanego przez warstwę dostępu do danych.
Telastyn
1
@CodeCaster - Istnieje wiele sposobów na utworzenie tokena, który pozwala oddzwonieniu określić, jakie operacje są wykonywane, a na pewno nie wszystkie z nich przekazują klucz podstawowy.
Telastyn
2
Ale to wymaga, aby warstwa danych wiedziała, do którego tokena należy (lub tłumaczy) do której PK. Dla mnie to brzmi jak dodatkowa warstwa niepotrzebnej złożoności, tylko ze względu na ukrywanie PK. Jaki cel ma to oprócz zaspokojenia architekta? Zgadzam się z twoją tezą, po prostu nie uważam, aby miała ona zastosowanie w rzeczywistych zastosowaniach i byłbym wdzięczny za prawdziwy przykład.
CodeCaster,
1
@CodeCaster - Nie, środkowa warstwa faktycznie wykonuje swoją pracę i streszcza, że ​​w ogóle istnieje dostęp do danych z interfejsu użytkownika. Na świecie jest wielu złych architektów, ale z wielu powodów istnieje wiele najlepszych praktyk projektowania programów. Niektóre aplikacje mogą ryzykować wyciek abstrakcyjny, a niektóre nie.
Telastyn
10

To jest kombinacja odpowiedzi pozostałych (czyli tego, czego się nauczyłem). Jeśli masz ochotę głosować za tym, powinieneś przynajmniej głosować za jednym z nich, tak jak oni wykonali swoją pracę. Jeśli jesteś bardziej zainteresowany, przeczytaj pozostałe odpowiedzi.

Nie należy ujawniać klucza podstawowego bazy danych, ale zamiast tego należy użyć klucza zastępczego

  1. Jeśli chcesz, aby użytkownicy mogli zapamiętać (przynajmniej trochę) lub rozpoznać identyfikator wpisu. ( Graystone28s Odpowiedź )
  2. Jeśli chcesz planować z wyprzedzeniem i wziąć pod uwagę, że możesz zmienić systemy (bazy danych lub inne), które prawdopodobnie zmienią twoje PK. ( Odpowiedź Telastyns )
  3. Jeśli chcesz zapewnić swoim użytkownikom spójny sposób uzyskiwania dostępu do danych, które nie ulegną zmianie, nawet jeśli Twoja firma zmieni właściciela, a dane zostaną przeniesione w tysiące do innego systemu. ( Odpowiedź Michaela Durranta )
  4. Jeśli twoje PK jest przewidywalne (jak sekwencja), twój system może mieć problemy z pozyskiwaniem zasobów. ( Odpowiedź CodeCasters ) Ma to zastosowanie tylko wtedy, gdy twój system ma informacje, które warto zebrać i które są dostępne dla każdego lub przynajmniej dla kogoś, kto jest zainteresowany zbieraniem.

Uwaga: Utworzony klucz powinien być (w pewnym sensie ) zrozumiały dla człowieka ( odpowiedź Sqlvogels ).

Jeśli twój system nie potrzebuje 1. do 4., nie ma powodu, aby nie używać baz danych PK jako publicznego identyfikatora (kilka odpowiedzi). Również bezpieczeństwo nie jest tutaj problemem (kilka odpowiedzi).

Angelo Fuchs
źródło
8

Jednym z powodów, które znalazłem, był czas, kiedy użytkownicy końcowi żądali, aby ich identyfikator coś znaczył (na przykład posiadanie prefiksu lub wskaźnika roku, w którym został przyjęty). Zmiana PK jest trudna, ale surogat jest znacznie łatwiejszy.

Twój klucz podstawowy prawdopodobnie będzie czymś, o co chcesz zaindeksować bazę danych ze względów wydajnościowych, a z czasem z przyczyn technicznych możesz zmienić go na przykład z numeru na przewodnik ... po prostu nie wiesz, z jakich powodów nowe technologie lub wiedza może cię poprowadzić. Twój pk to techniczny element danych, klucz publiczny służy do konsumpcji przez użytkowników końcowych.

Wayne M.
źródło
7
Pytanie brzmi: „Czy ujawnianie kluczy podstawowych jest złe?” . Twoja odpowiedź: „Użytkownicy mogą chcieć mieć własne identyfikatory” . Nie rozumiem związku. Ujawniam InvoiceNumber, co ma znaczenie i może być zmieniane przez klienta, ale też ujawniam InvoiceID, których mój kod używa do jednoznacznej identyfikacji faktury. Nie musisz (a częściej nie chcesz ) pozwolić, aby klucz użytkownika był kluczem do przechowywania. To pytanie dotyczy tego drugiego.
CodeCaster,
Myślę, że to dobry przykład, ponieważ jeśli przejdziesz do wersji aplikacji z wieloma dzierżawcami, możesz zachować tę samą składnię i mieć wiele faktur InvoiceNumber(dla różnych dzierżawców), ale mieć różne klucze podstawowe - punkt (rodzaj ) wspomniane również w odpowiedzi.
recluze
1
@CodeCaster to pytanie dotyczy w zasadzie „dlaczego nie chcesz, żeby były takie same”?
Angelo Fuchs
W takim przypadku zobacz odpowiedź Telastyns .
CodeCaster,
2

W przypadku większości aplikacji bardzo ważne jest, abyś udostępniał klucze użytkownikom. Aby skutecznie korzystać z systemu informatycznego, użytkownicy tego systemu będą zwykle potrzebowali sposobu na identyfikację zawartych w nim informacji i powiązanie tych informacji z czymś na świecie poza bazą danych. W kategoriach relacyjnych baz danych te identyfikatory są kluczami.

Jednym z często używanych wzorców projektowych jest stworzenie dodatkowego, czysto „technicznego” klucza dla tabel bazy danych jako sposobu abstrakcji. Na przykład, aby zapewnić stabilny (względnie niezmienny) klucz, w przypadku którego klucz alternatywny może ulec zmianie. Takie klucze techniczne zwykle nie są narażone na ryzyko dla użytkowników końcowych, ponieważ podważa to zamierzoną abstrakcję wymagań użytkownika. Nie ma to nic wspólnego z bezpieczeństwem.

Problem / nieporozumienie zawarte w twoim pytaniu wynika z niewłaściwego użycia terminu klucz podstawowy . Klucz podstawowy jest tylko jednym z kilku kluczy „kandydujących” (kilka możliwych identyfikatorów w tabeli bazy danych). Klucz podstawowy niekoniecznie wymaga zasadniczo innej właściwości niż jakikolwiek inny klucz, dlatego twierdzenia i zasady projektowania, które dotyczą konkretnie kluczy podstawowych, a nie innych kluczy, są zawsze podejrzane i często błędne.

Biorąc pod uwagę, że zwykle będziesz musiał ujawnić klucz użytkownikowi, jaki powinien być ten klucz? Staraj się, aby klucze były znane, proste i stabilne. Znajomość i prostota sprawiają, że klucze są łatwe do odczytania i zapamiętania oraz pomogą uniknąć błędów wprowadzania danych. Stabilność oznacza rzadkie kluczowe zmiany, co pomaga również uniknąć możliwości błędnej identyfikacji.

nvogel
źródło
1
to zależy ... od czego? Chcę dowiedzieć się, jakie są przyczyny tej ogólnej koncepcji, aby wiedzieć, kiedy ją zastosować, a kiedy nie.
Angelo Fuchs
1
Cześć kliencie, proszę podaj mi swój identyfikator, abym mógł ci pomóc. Jasne, jego gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456. Hmm, a co ze społecznością? ... identyfikator zastępczy
Michael Durrant
@Michael, Odpowiedź zaktualizowana. Czy to znajomy, prosty i stabilny klucz?
nvogel
1

Wynika to z komentarza CodeCaster do odpowiedzi Greystone28. To przykład tego, co mówisz:

Udostępniam numer faktury, który ma znaczenie i może być zmieniany przez klienta, ale ujawniam też identyfikator faktury, którego mój kod używa do jednoznacznej identyfikacji faktury. Nie musisz (a częściej nie chcesz) pozwolić, aby klucz użytkownika był kluczem do przechowywania. To pytanie dotyczy tego drugiego.

Jaki cel w Twojej aplikacji ma wyświetlenie InvoiceID?

Przez ujawnienie, zakładam, że masz na myśli, że użytkownik może to zobaczyć. Udostępniaj go tylko wtedy, gdy użytkownik potrzebuje go do korzystania z Twojej aplikacji. Może być wykorzystany przez wsparcie techniczne lub niektóre czynności administracyjne. Pracowałem z kilkoma aplikacjami, które to robią. Ułatwia to wsparcie, gdy znam konkretny rekord.

JeffO
źródło
Faktury mają identyfikatory naturalne (liczby), ale tylko te, które piszesz. Co z tymi, które dostajesz? Mają numery faktur, ale nakładają się na siebie (ponieważ dwie firmy używają tego samego i obie wysyłają fakturę). W tej sytuacji Twój identyfikator faktury jest unikalny, numer nie jest, a to, co czyni go unikalnym, to nazwa niestandardowa, która nie jest dobrym identyfikatorem danych (zbyt długo, zmiany zbyt często mogą zawierać nieznane znaki ...)
Angelo Fuchs,
@AngeloNeuschitzer - jeśli użytkownik może jednoznacznie zidentyfikować fakturę według nazwy i numeru klienta, użytkownik nie potrzebuje InvoiceID PK, ale baza danych i kod źródłowy mogą z niego korzystać. Są to wzajemnie wykluczające się funkcje.
JeffO
Zobacz przypadki 1–3 mojego przykładu. W żadnym z tych przypadków Nazwa klienta nie jest użytecznym sposobem adresowania tego obiektu dla użytkownika (człowieka lub maszyny). Faktura ID PK to.
Angelo Fuchs
1

Jest to zupełnie normalne, że istoty mają unikalny identyfikator, który jest wystawiony na świat zewnętrzny. W przypadku niektórych obiektów może być możliwe znalezienie identyfikatora, który faktycznie ma znaczenie (na przykład numer faktury), ale w przypadku innych takich identyfikatorów nie ma i dlatego należy je wygenerować.

Ze względu na spójność i czytelność uważam, że dobrą praktyką jest, aby wszystkie podmioty w systemie używały tego samego typu i nazwy dla swojego identyfikatora. Zwykle ten identyfikator byłby narażony ( <type> getId()) w jakiejś abstrakcyjnej klasie bazowej.

Z tego samego powodu każda usługa w systemie (na przykład usługa fakturowania) powinna zapewniać identyczne metody dostępu do podmiotów według ich identyfikatora. Zwykle ta metoda ( findById(<type> id)) byłaby dziedziczona z ogólnego interfejsu usługi lub klasy bazowej.

Ten identyfikator nie musi być kluczem podstawowym encji, ale może nim być. Jedyne, co trzeba zapewnić, to to, że strategia generowania klucza generuje racjonalnie unikalne identyfikatory (niekoniecznie uniwersalnie unikalne, ale przynajmniej w systemie).

Jeśli system zostanie później migrowany (duża, o ile mi wiadomo) do innej bazy danych, wówczas nie jest problemem użycie innej strategii (nie opartej na kluczach podstawowych) do tworzenia identyfikatorów, o ile strategia jest zgodna z oryginalną.

Muton
źródło
Czy możesz wyjaśnić, na co w twojej odpowiedzi nie ma odpowiedzi w pozostałych?
Angelo Fuchs
2
W mojej odpowiedzi nie zgadzam się przynajmniej z punktami 2. i 3. twojego streszczenia. Nie sądzę, że są to uzasadnione powody, dla których nie używamy PK jako identyfikatorów obiektów.
Muton
0

Jest tam klucz podstawowy, podobnie jak uchwyt do krotki (rekord, wiersz), do którego próbujesz uzyskać dostęp jako programista. Jest również używany w integralności referencyjnej (ograniczenia klucza obcego), i może ma też jeden lub więcej przypadków użycia.

Zasadniczo nie ma nic złego w udostępnianiu go użytkownikom, a nawet hakerom. Ponieważ nie znam ataku, który wykorzystuje na przykład klucz podstawowy.

Ale jeśli chodzi o bezpieczeństwo, mamy wiele zasad (które akceptujemy i nie zatwierdzamy) i musimy je przestrzegać:

  1. Zasada przywileju najmu
  2. Bezpieczeństwo dzięki niejasnościom

I kilka innych zasad. Mówią w istocie, że:

Jeśli nie musisz ujawniać swoich danych, dlaczego w ogóle miałbyś to robić?

Saeed Neamati
źródło
Część uchwytu jest tam, gdzie się zgadzam. Bezpieczeństwo nie jest. Może to być związane z bezpieczeństwem, ale posiadanie niezależnego klucza wewnętrznego, który nie jest widoczny dla użytkownika, tak naprawdę nie dotyczy bezpieczeństwa. Nazwałbym to miłym efektem ubocznym.
JensG
Dlaczego miałbyś: patrz przykład, który dodałem do pytania.
Angelo Fuchs,