Ankündigung

Einklappen
Keine Ankündigung bisher.

Benutzerregistrierung - Verschiedene Ansätze, welcher ist der "richtige"?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Benutzerregistrierung - Verschiedene Ansätze, welcher ist der "richtige"?

    Hallo zusammen,

    ich arbeite gerade an einer Benutzerregistrierung und versuche herauszufinden, welcher der richtige Ansatz ist...

    Ansatz 1: Benutzerregistrierung direkt in die users-Tabelle
    • Eine neue Benutzerregistrierung fügt direkt in die Benutzer-Tabelle einen Eintrag ein
    • Dieser wird über ein disabled-Flag deaktiviert wird und über ein email_confirmed_at = null als unbestätigt markiert
    • Dann wird eine E-Mail mit einem signierten Link und einer Gültigkeitsdauer verschickt, um den Benutzer freizuschalten
    • Beim Klick auf den Link wird das disabled flag entfernt und das Datum für email_confirmed_at gesetzt

    Vorteil:
    • Validierung findet nur an einer Stelle statt
    • Bereits vorhandene Benutzer und E-Mail-Adressen lassen sich leicht prüfen
    • Man kann einfach herausfinden, wie viele unbestätigte Registrierungen es gibt (Statistik)

    Nachteil:
    • User-Tabelle wird unnötig voll
    • Falls es eine Sicherheitslücke gibt, kann man die users-Tabelle manipulieren


    Ansatz 2: Daten in eine eigene registrations-Tabelle integrieren
    • Eine neue Benutzerregistrierung wird in eine Extra Tabelle registrations gespeichert, die weitgehend der User-Tabelle entspricht
    • Dann wird eine E-Mail mit einem signierten Link und einer Gültigkeitsdauer verschickt, um den Benutzer freizuschalten
    • Beim Klick auf den Link wird der Eintrag in die users-Tabelle kopiert / verschoben

    Vorteil:
    • Sicherheitslücken wirken sich nicht direkt aus, sondern vorerst nur indirekt
    • Die users-Tabelle wird nicht unnötig gefüllt
    • Man kann leicht herausfinden, welche unbestätigten Registrierungen es gibt

    Nachteil:
    • Die Prüfung vorhandener Benutzernamen und E-Mail-Adressen erfolgt in 2 Tabellen
    • Der Aufbau der beiden Tabellen muss synchron gehalten werden (z.B. wenn eine neue Spalte in der users-Tabelle hinzukommt, muss diese auch in der registrations-Tabelle hinzugefügt werden)

    Ansatz 3: Daten vollständig in Link integrieren
    • Eine neue Benutzerregistrierung wird vollständig AES verschlüsselt in den Bestätigungslink integriert, dann signiert.
    • Beim Klick auf den Link werden die Daten entschlüsselt, validiert und ein Eintrag in die users-Tabelle eingefügt

    Vorteil:
    • Es müssen keine unnötigen Daten gespeichert werden
    • Die users-Tabelle wird nicht unnötig gefüllt

    Nachteil:
    • Begrenzte Datenmenge in den Links (z.B. 4000 Zeichen für maximale URL-Länge)
    • Bereits vorhandene Benutzer können durch eine zeitliche Verschiebung doppelt vergeben werden
    • Validierung beim Generieren und Bestätigen des Links erforderlich
    • Unbestätigte Registrierungen können nicht statistisch erfasst werden (jedenfalls ohne extra Logik / Datenspeicherung nicht)

    Aktuell tendiere ich zu einem direkten Eintrag in die users-Tabelle.

    Habe ich vielleicht einen Ansatz komplett vergessen?
    Wie funktionieren gängige Systeme?
    Spricht etwas gegen Ansatz 1, was ich übersehen habe?
    Tutorials zum Thema Technik:
    https://pilabor.com
    https://www.fynder.de

  • #2
    Ansatz 1 ist der gängige.

    User-Tabelle wird unnötig voll
    Wird sie das nicht sowieso? Du kannst ja User wieder löschen, die nach 3 Tagen ihre Email noch nicht verifiziert haben.

    Falls es eine Sicherheitslücke gibt, kann man die users-Tabelle manipulieren
    Falls es eine Sicherheitslücke gibt kann man alles manipulieren

    ann wird eine E-Mail mit einem signierten Link
    Was denn für einen signierten Link? Und was hast du mit deiner AES-Verschlüsselung u.s.w.? Alles was du brauchst ist eine zufällige Zeichenkette die du an den Link anhängst und in der Datenbank mit dem User zusammen speicherst. Hast du einen User mit der im Link mitgegebenen Zeichenkette wird seine E-Mail verifiziert, fertig.
    [QUOTE=nikosch]Macht doch alle was Ihr wollt mit Eurem Billigscheiß. Von mir aus sollen alle Eure Server abrauchen.[/QUOTE]

    Kommentar


    • #3
      Ansatz 1 ist der gängige.
      Prima, erstmal danke für dein Feedback.

      Wird sie das nicht sowieso?
      Naja, die Größe der Tabelle wird durch viele unbestätigte Registrierungen unnötig aufgebläht, allerdings sollte ich tatsächlich wohl realistisch bleiben Es ging auch nur um den bestmöglichen Ansatz.

      Du kannst ja User wieder löschen, die nach 3 Tagen ihre Email noch nicht verifiziert haben.
      So war es gedacht. Die Frage war nur, ob es Sinn macht, das ganze in einer extra Tabelle zu speichern, um die Abfragen auf die users-Tabelle schnell bzw. die Suchmenge klein zu halten. Wobei man wahrscheinlich nie mehr als 100000 User in der Tabelle verwalten muss und somit die Praxisrelevanz des Performanceunterschieds wohl eher gering ist (solange man nicht facebook erfolgreich nachprogrammiert

      Falls es eine Sicherheitslücke gibt kann man alles manipulieren
      Das halte ich für zu allgemein. Sicherheitslücken beziehen sich nicht zwangsläufig auf die gesamte Anwendung. Könnte ich beispielsweise beliebige Einträge in die registrations-Tabelle schreiben, weil die Registrierung eine Lücke aufweist, die users-Logik wäre aber korrekt, somit wäre das System nicht vollständig gefährdet (Sicherheitslücken können z.B. kritisch, hoch, mittel oder niedrig eingestuft werden). Die users-Tabelle ist ein sehr kritischer Aspekt der Anwendung, aber grundsätzlich sollte man natürlich Lücken allgemein vermeiden, das ist klar.

      Was denn für einen signierten Link? Alles was du brauchst ist eine zufällige Zeichenkette
      Nun, einen Link kryptografisch zu signieren (mit einem keyed-Hash über hash_hmac oder einer RSA-Signatur über openssl_sign) hat gegenüber der zufällig generierten Zeichenkette den Vorteil, dass nichts gespeichert werden muss und man trotzdem die Gültigkeit verifizieren kann. Ich möchte vermeiden, dass eine Spalte "random_key" in der Benutzer-Tabelle hinterlegt ist, der fast überall einen NULL-Wert oder einen nicht mehr benötigten Wert enthält. Ich halte den kryptografischen Ansatz für eleganter (aber das soll nicht zu einer Grundsatzdiskussion ausarten, davon gibt es genug im Netz). Ich versuche generell die Datenbank frei von unnötigen Daten zu halten, wie man schon an der Fragestellung erkennt. Ich kenne Systeme mit users-Tabellen, da wird einem Angst und Bange vor lauter Spalten (z.B. https://wiki.phpbb.com/Table.phpbb_users


      Und was hast du mit deiner AES-Verschlüsselung u.s.w.?
      Die AES-Verschlüsselung könnte man verwenden, um den gesamten Benutzer-Datensatz (username, gehashtes Passwort, Vorname, Nachname, etc.) in einem json-encodierten String zu verschlüsseln und in dem Bestätigungslink komplett hinterlegen (der wäre dann sehr groß). Dann müsste man gar nichts mehr in der Tabelle eintragen, sondern nur beim Klick auf den Link die Daten aus einem Parameter extrahieren und den Benutzer anlegen. Das war aber nur ein sehr theoretischer Ansatz, der einige Schwächen hat...


      Tutorials zum Thema Technik:
      https://pilabor.com
      https://www.fynder.de

      Kommentar


      • #4
        Zitat von Andreas Beitrag anzeigen
        [...] So war es gedacht. Die Frage war nur, ob es Sinn macht, das ganze in einer extra Tabelle zu speichern, um die Abfragen auf die users-Tabelle schnell bzw. die Suchmenge klein zu halten. Wobei man wahrscheinlich nie mehr als 100000 User in der Tabelle verwalten muss und somit die Praxisrelevanz des Performanceunterschieds wohl eher gering ist (solange man nicht facebook erfolgreich nachprogrammiert
        Nein, macht es nicht. Unter 1 Million Einträge pro Tabelle langweilt sich deine Datenbank eh nur.

        Das halte ich für zu allgemein. Sicherheitslücken beziehen sich nicht zwangsläufig auf die gesamte Anwendung. Könnte ich beispielsweise beliebige Einträge in die registrations-Tabelle schreiben, weil die Registrierung eine Lücke aufweist, die users-Logik wäre aber korrekt, somit wäre das System nicht vollständig gefährdet (Sicherheitslücken können z.B. kritisch, hoch, mittel oder niedrig eingestuft werden). Die users-Tabelle ist ein sehr kritischer Aspekt der Anwendung, aber grundsätzlich sollte man natürlich Lücken allgemein vermeiden, das ist klar.
        Das halte ich für falsch. Wenn dein System einen Eindringspunkt aufweist ist davon auszugehen, dass der Angreifer auf alles Zugriff erhält.
        Nun, einen Link kryptografisch zu signieren (mit einem keyed-Hash über hash_hmac oder einer RSA-Signatur über openssl_sign) hat gegenüber der zufällig generierten Zeichenkette den Vorteil, dass nichts gespeichert werden muss und man trotzdem die Gültigkeit verifizieren kann. Ich möchte vermeiden, dass eine Spalte "random_key" in der Benutzer-Tabelle hinterlegt ist, der fast überall einen NULL-Wert oder einen nicht mehr benötigten Wert enthält. Ich halte den kryptografischen Ansatz für eleganter (aber das soll nicht zu einer Grundsatzdiskussion ausarten, davon gibt es genug im Netz). Ich versuche generell die Datenbank frei von unnötigen Daten zu halten, wie man schon an der Fragestellung erkennt. Ich kenne Systeme mit users-Tabellen, da wird einem Angst und Bange vor lauter Spalten (z.B. https://wiki.phpbb.com/Table.phpbb_users
        Du kannst auch eine zusätzliche Tabelle machen (user_random_keys) und die (noch) gültigen Keys in dieser Tabelle ablegen. Die zufällige Generierung ist üblich und hat auch ihre Berechtigung. Eine nicht zufällige Generierung erlaubt einem Angreifer, wenn er Zugriff auf den Code erhält, beliebige Werte zu berechnen und somit z.B. die Registration für jemand drittes abschliessen zu können. Ist der Wert zufällig, kann er das nicht.

        Zugriff auf den Code kann er z.B. erhalten, wenn dein Apache-Handler ausfällt. Ja, das ist realistisch, passierte bei meinem Hoster einmal. Damit hat er allerdings noch keinen Zugriff auf die Datenbank.

        Die AES-Verschlüsselung könnte man verwenden, um den gesamten Benutzer-Datensatz (username, gehashtes Passwort, Vorname, Nachname, etc.) in einem json-encodierten String zu verschlüsseln und in dem Bestätigungslink komplett hinterlegen (der wäre dann sehr groß). Dann müsste man gar nichts mehr in der Tabelle eintragen, sondern nur beim Klick auf den Link die Daten aus einem Parameter extrahieren und den Benutzer anlegen. Das war aber nur ein sehr theoretischer Ansatz, der einige Schwächen hat...
        Ja genau. Das wäre dann ähnlich wie ein "serialisieren". PHP hat dazu eine sehr gute Vorgeschichte, die praktisch in "serialisiere nie, nie, nie, nie!" endet. Ein Angreifer kann potentiell den String manipulieren und dir somit gefährliche Daten unterjubeln, ohne dass du es merkst.

        Grundsätzlich gilt: Keine Security-by-Obscurity. Das sind die schlimmsten Ansätze. Einfache, offene und bewährte Prinzipien anwenden. Denk immer "Wäre es sinnvoll, meinem Benutzer den verwendeten Algorhytmus vorzulegen?". Wäre es sinnvoll, deinen AES-RSA-Was-auch-immer deinem Benutzer vorzulegen, oder wäre es sinvoll(er), die Zufallsvariante vorzulegen? Mit welcher Variante erschaffst du einen Angriffspunkt?

        [URL="https://github.com/chrisandchris"]GitHub.com - ChrisAndChris[/URL] - [URL="https://github.com/chrisandchris/symfony-rowmapper"]RowMapper und QueryBuilder für MySQL-Datenbanken[/URL]

        Kommentar


        • #5
          Zugriff auf den Code kann er z.B. erhalten, wenn dein Apache-Handler ausfällt. Ja, das ist realistisch, passierte bei meinem Hoster einmal. Damit hat er allerdings noch keinen Zugriff auf die Datenbank.
          Danke für den Tipp, dass ist ein interessanter Aspekt. Das ist tatsächlich ein denkbares Szenario.

          Besteht diese Gefahr dann auch noch wenn man den Code außerhalb webroots des Virtual-Hosts ablegt (/src/public/index.php ==> www.meinedomain.de/index.php, src/app/mein_anderer_code.php) ==> kein Zugriff?

          Obwohl ich einsehe, dass die Datenbank auch gegen fremden Zugriff geschützt werden kann, wenn man nur Connections vom localhost erlaubt, bin ich der Ansicht, dass externer Zugriff auf die PHP/Konfigurations-Dateien, in denen die Zugangsdaten der Datenbank stehen bzw. in meinem Fall auch die Private-Keys stehen, als absolut nicht hinnehmbare Sicherheitslücke zu betrachten ist. Daher lebe ich wohl mit dem Risiko einer nicht zufällig generierten Zeichenkette, sofern die Auslagerung des Webroots ausreichend Schutz bietet.
          Tutorials zum Thema Technik:
          https://pilabor.com
          https://www.fynder.de

          Kommentar


          • #6
            Nein, das ist auch der Ansatz den die meisten Frameworks nehmen. Bei Symfony z.B. legt man nur einen 10 Zeiler im Web-Root ab, die ganze Source liegt ausserhalb des Doc-Roots.
            [URL="https://github.com/chrisandchris"]GitHub.com - ChrisAndChris[/URL] - [URL="https://github.com/chrisandchris/symfony-rowmapper"]RowMapper und QueryBuilder für MySQL-Datenbanken[/URL]

            Kommentar


            • #7
              Alles klar, vielen Dank an alle... eine sehr erhellende Diskussion Also noch mal mein gewählter Ansatz zusammengefasst:

              Ansatz 1: Benutzerregistrierung direkt in die users-Tabelle
              • Eine neue Benutzerregistrierung fügt direkt in die Benutzer-Tabelle einen Eintrag ein
              • Dieser wird über ein disabled-Flag deaktiviert wird und über ein email_confirmed_at = null als unbestätigt markiert
              • Dann wird eine E-Mail mit einem signierten Link und einer Gültigkeitsdauer verschickt, um den Benutzer freizuschalten
              • Beim Klick auf den Link wird das disabled flag entfernt und das Datum für email_confirmed_at gesetzt
              • Keys zum erzeugen der Signatur werden in einer Datei außerhalb des Webroots abgelegt (war schon vorher so, soll nur der Vollständigkeit halber noch einmal erwähnt werden)

              Tutorials zum Thema Technik:
              https://pilabor.com
              https://www.fynder.de

              Kommentar

              Lädt...
              X