Strategia generowania unikalnych i bezpiecznych identyfikatorów do wykorzystania w aplikacji internetowej" czasami offline"

Mam projekt internetowy, który pozwala użytkownikom pracować zarówno online, jak i offline i szukam sposobu na generowanie unikalnych identyfikatorów dla rekordów po stronie klienta. Chciałbym, aby podejście, które działa, gdy użytkownik jest offline (tj. nie może rozmawiać z serwerem), jest gwarantowane, aby być unikalne i jest bezpieczne. Mówiąc "Bezpieczny", szczególnie martwię się, że klienci przesyłają duplikaty identyfikatorów (złośliwie lub w inny sposób), a tym samym sieją spustoszenie w integralności danych.

I ' ve been doing trochę googlowania, mając nadzieję, że to już rozwiązany problem. Nie znalazłem niczego, co jest bardzo definitywne, zwłaszcza jeśli chodzi o podejścia, które są stosowane w systemach produkcyjnych. Znalazłem kilka przykładów systemów, w których użytkownicy będą mieli dostęp tylko do danych, które utworzyli (np. Lista zadań, która jest dostępna na wielu urządzeniach, ale tylko przez użytkownika, który ją utworzył). Niestety, potrzebuję czegoś bardziej wyszukanego. Znalazłem kilka naprawdę dobrych pomysłów , które są zgodne z tak myślałem, że to może zadziałać.

Poniżej moje proponowane rozwiązanie.

Niektóre Wymagania

    ID powinno być unikalne globalnie (lub przynajmniej unikalne w systemie) [11]} generowane na kliencie (np. przez javascript w przeglądarce)
  1. Secure (jak opisano powyżej i nie tylko)
  2. dane mogą być przeglądane/edytowane przez wielu użytkowników, w tym użytkowników, którzy nie są ich autorami
  3. nie powoduje istotnych problemów z wydajnością dla backend db (takich jako MongoDB lub CouchDB)

Proponowane Rozwiązanie

Kiedy użytkownicy tworzą konto, otrzymują uuid, który został wygenerowany przez serwer i znany jako unikalny w systemie. Ten identyfikator nie może być taki sam jak token uwierzytelniania użytkowników. Nazwijmy to id użytkownikami "id token".

Gdy użytkownik tworzy nowy rekord, generuje nowy uuid w javascript (generowany przy użyciu window.crypto, gdy jest dostępny. Zobacz przykłady tutaj ). Ten identyfikator jest połączony z "Token id", który Użytkownik otrzymał podczas tworzenia konta. Ten nowy identyfikator złożony (Token id po stronie serwera + uuid po stronie klienta) jest teraz unikalnym identyfikatorem rekordu. Gdy użytkownik jest online i przesyła ten nowy rekord do serwera zaplecza, serwer będzie:

    W tym celu należy wykonać następujące czynności:]}
  1. sprawdzanie poprawności obu części klucza złożonego są poprawnymi uuid
  2. sprawdź, czy dostarczona część" id token " złożona id jest poprawne dla bieżącego użytkownika (tzn. odpowiada tokenowi id serwera przypisanemu użytkownikowi podczas tworzenia konta)
  3. Jeśli wszystko jest copasetic, wstawić dane do db (uważając, aby zrobić insert, a nie "upsert" tak, że jeśli id Nie już istnieje, to nie aktualizuje istniejącego rekordu przez pomyłkę)

Zapytania, aktualizacje i usuwanie nie wymagałyby żadnej specjalnej logiki. Po prostu użyliby identyfikatora dla rekordu w taki sam sposób, jak tradycyjne zastosowania.

Jakie są zalety tego podejścia?

  1. Kod Klienta może tworzyć nowe dane w trybie offline i natychmiast znać identyfikator tego rekordu. Rozważałem alternatywne podejścia, w których tymczasowy identyfikator byłby generowany na kliencie, który później byłby zamieniany na" ostateczny " identyfikator, gdy system był online. Było to jednak bardzo kruche. Zwłaszcza, gdy zaczynasz myśleć o tworzeniu danych potomnych za pomocą kluczy obcych, które również muszą bądź na bieżąco. Nie wspominając już o adresach URL, które zmieniałyby się po zmianie identyfikatora.

  2. Tworząc identyfikatory złożone z wartości Wygenerowanej Przez Klienta i wartości wygenerowanej przez serwer, każdy użytkownik skutecznie tworzy identyfikatory w piaskownicy. Ma to na celu ograniczenie szkód, które mogą zostać wyrządzone przez złośliwego / nieuczciwego klienta. Ponadto wszelkie kolizje identyfikatorów są zależne od użytkownika, a nie globalne dla całego systemu.

  3. Ponieważ token users id jest powiązany z ich kontem, identyfikatory mogą być tylko generowane w piaskownicy użytkowników przez klientów, które są uwierzytelnione (tzn. gdzie użytkownik pomyślnie zalogował się). Ma to na celu powstrzymanie złośliwych klientów przed tworzeniem złych identyfikatorów dla użytkownika. Oczywiście, jeśli Token auth użytkownika zostanie skradziony przez złośliwego klienta, mogą zrobić złe rzeczy. Ale gdy Token auth zostanie skradziony, Konto i tak zostanie naruszone. W przypadku, gdyby tak się stało, wyrządzone szkody będą ograniczone do zagrożonego konta (a nie całego system).

Dotyczy

Oto niektóre z moich obaw związanych z tym podejściem

  1. Czy wygeneruje to wystarczająco unikalne identyfikatory dla aplikacji na dużą skalę? Czy jest jakiś powód, aby sądzić, że spowoduje to kolizje tożsamości? Czy javascript może wygenerować wystarczająco losowy uuid, aby to działało? Wygląda jak okno.crypto jest dość szeroko dostępne i ten projekt wymaga już dość nowoczesnych przeglądarek. (to pytanie ma teraz osobne Więc pytanie własne)

  2. Czy są jakieś luki, których mi brakuje, które mogłyby pozwolić złośliwemu użytkownikowi na skompromitowanie systemu?

  3. Czy istnieje powód, aby martwić się o wydajność DB przy pytaniu o klucz złożony składający się z 2 uuid. Jak należy przechowywać ten identyfikator, aby uzyskać najlepszą wydajność? Dwa oddzielne pola czy jedno pole obiektu? Czy byłoby inne "najlepsze" podejście do Mongo vs kanapa? Wiem, że posiadanie niesekwencyjnego klucza podstawowego może spowodować znaczące problemy z wydajnością podczas wykonywania wkładek. Czy mądrzej byłoby mieć automatycznie wygenerowaną wartość dla klucza podstawowego i przechowywać ten identyfikator jako oddzielne pole? (to pytanie ma teraz osobne więc pytanie własne)

  4. Dzięki tej strategii łatwo byłoby ustalić, czy dany zestaw rekordów został utworzony przez tego samego użytkownika (ponieważ wszyscy będą mieli ten sam publicznie widoczny token id). Chociaż nie widzę żadnych natychmiastowych problemów z tym, zawsze lepiej nie wyciek więcej informacji o wewnętrznych szczegółach niż jest to potrzebne. Inną możliwością byłoby zahaszowanie klucza kompozytowego, ale wydaje się, że może to być więcej kłopotów niż jest warte.

  5. W przypadku kolizji id użytkownika nie ma prostego sposobu na odzyskanie. Przypuszczam, że klient może wygenerować nowy identyfikator, ale to wygląda na dużo pracy dla sprawy edge, która naprawdę nigdy nie powinna się wydarzyć. Zamierzam zostawić to bez odpowiedzi.

  6. Tylko uwierzytelnione użytkownicy mogą przeglądać i / lub edytować dane. Jest to dopuszczalne ograniczenie dla mojego systemu.

Podsumowanie

Czy powyżej rozsądnego planu? Zdaję sobie sprawę, że część z tego sprowadza się do oceny opartej na pełniejszym zrozumieniu danego zastosowania.

Author: Community, 2014-04-18

2 answers

Twoje podejście zadziała. Wiele systemów zarządzania dokumentami korzysta z tego typu podejścia.

Jedną rzeczą do rozważenia jest to, że nie musisz używać zarówno uuid użytkownika, jak i losowego id elementu jako części łańcucha. Można zamiast tego hash konkatinacji obu. Daje to krótszy identyfikator i prawdopodobnie inne korzyści, ponieważ wynikowe identyfikatory będą bardziej równomiernie rozłożone (lepiej zrównoważone dla indeksowania i przechowywania plików, jeśli przechowujesz pliki na podstawie ich uuid).

Inną opcją jest wygenerowanie tylko tymczasowego identyfikatora uuid dla każdego elementu. Następnie, gdy połączysz się i opublikujesz je na serwerze, serwer generuje (gwarantowane) uuid dla każdego elementu i zwraca je do ciebie. Następnie aktualizujesz lokalną kopię.

 4
Author: GrandmasterB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 16:35:55

Musisz oddzielić te dwie kwestie:

  1. generowanie ID: klient musi być w stanie wygenerować unikalny identyfikator w systemie rozproszonym
  2. problem bezpieczeństwa: klient musi mieć ważny token uwierzytelniania użytkownika i token uwierzytelniania jest ważny dla tworzonego/modyfikowanego obiektu

Rozwiązanie tych dwóch niestety jest oddzielne, ale na szczęście nie są one niezgodne.

Troskę o generowanie ID można łatwo rozwiązać generując z UUID, do tego jest przeznaczony UUID; jednak w trosce o bezpieczeństwo wymagane jest sprawdzenie na serwerze, czy dany token uwierzytelniania jest autoryzowany do tej operacji (tzn. jeśli token uwierzytelniania jest przeznaczony dla użytkownika, który nie posiada wymaganych uprawnień dla danego obiektu, to musi zostać odrzucony).

Jeśli obsługa jest prawidłowa, kolizja nie stanowi problemu z bezpieczeństwem (użytkownik lub klient po prostu zostanie poproszony o ponowne spróbowanie operacji z innym UUID).

 13
Author: Lie Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-21 11:37:53