rolfrost: Brauche einen eindeutigen und zufälligen String...

Hallo,

siehe Betreff. Mein Versuch mit

=try...
my @sessions;
for (1..60){
 my $session = time.$$;
 my $salt = int rand 98 + 1;
 $session = crypt($salt,$session);
 push @sessions, $session;
}

print sort join "\n", @sessions, "\n";
=cut

zeigt jedoch dass es doppelte IDs gibt. Hat jemand einen besseren Vorschlag?

Viele Grüße, Rolf

--

SELFforum - Das Tor zur Welt!
  1. wenn ich dich richt verstanden habe mmöchtest du eine session id erzeugen
    verwende diese methode:

    sub create_session_id()
    {
     my $self = shift;

    my $session_id = int(rand(6000000));
     $session_id = unpack("H*", pack("Nnn", time, $$, $session_id));

    return $session_id;
    }

    gruss bleau

    1. hi,

      vielen Dank!

      wenn ich dich richt verstanden habe mmöchtest du eine session id erzeugen

      yes.

      verwende diese methode:

      sub create_session_id()
      {
       my $self = shift;

      my $session_id = int(rand(6000000));
       $session_id = unpack("H*", pack("Nnn", time, $$, $session_id));

      return $session_id;
      }

      gruss bleau

      ergibt leider ein paar duplikate, hier meine testmethode:

      my @sessions;
      for(1..600){
       my $session = &create_session_id;
       push @sessions, $session;
      }

      my %keys = map{ $_,1}@sessions;
      print scalar keys %keys, "\n"; # soll: 600 ist: 591

      Viele Grüße, Rolf

      --

      SELFforum - Das Tor zur Welt!
      1. verwende doch noch die ip des benutzers dann bist du auf der sichern seite

        $ENV{'REMOTE_ADDR'};

        entweder an die session id (evtl. die punkte herausfilten) anhängen oder setze die ip in deine session db, cookie oder so

        gruss bleau

        1. hi,

          die IP mit einbeziehen - gute Idee ;-)

          Mittlerweile hab ich auch was eigenes gebaut:

          =sessions
          my @sessions;
          my $tests = 100000;
          for(1..$tests){
           my @salts;
           my $salt;
           my $zufall;
           my @menge;
           # erzeuge ausgangsmenge
           for("a".."z"){ push @menge, $_ }

          # die ausgangsmenge mischen
           shuffle(@menge);

          # das zufallswort zusammensetzen
           $zufall =  join "", @menge;

          # salts erzeugen
           for("a".."z"){ push @salts, $_ }
           shuffle(@salts);
           $salt = join "", @salts;

          # und nun crypten
           $zufall = crypt($salt,$zufall);

          # zufallsworte einlesen
           push @sessions, $zufall;
          }

          teste

          my %keys = map{ $_,1}@sessions;
          print scalar keys %keys, "\n$tests\n";
          =cut

          Ist vielleicht ein bischen ACID aber auch bei 100000 tests gibt es keine Duplikate...

          Viele Grüße, Rolf

          --

          SELFforum - Das Tor zur Welt!
          1. kannst es auch so machen - haste dann weniger code und funzt genauso gut

            $session_id =
             unpack("H*", pack("Nnn", time + int(rand(6000000)) , $$, int(rand(6000000)));

            gruss bleau

            1. hi danke,

              nur 13 Duplikate bei 1 Mio Tests... aber schön schnell ;-)

              Viele Grüße, Rolf

              kannst es auch so machen - haste dann weniger code und funzt genauso gut

              $session_id =
               unpack("H*", pack("Nnn", time + int(rand(6000000)) , $$, int(rand(6000000)));

              gruss bleau

              --

              SELFforum - Das Tor zur Welt!
  2. Hi,

    es kommt auch in Betracht die ID vom RDBMS erzeugen zu lassen. Das kann das bestimmt besser.

    Gruss,
    Lude

  3. Hallo,

    siehe Betreff. Mein Versuch mit

    =try...
    my @sessions;
    for (1..60){
     my $session = time.$$;
     my $salt = int rand 98 + 1;
     $session = crypt($salt,$session);
     push @sessions, $session;
    }

    print sort join "\n", @sessions, "\n";
    =cut

    zeigt jedoch dass es doppelte IDs gibt. Hat jemand einen besseren Vorschlag?

    Einerseits weiß ich nicht ob dein salt nicht schlecht gewählt ist, da es ja ein String sein sollte. anderseits ist time natürlich zu lahm, aber anderseits in der Praxis sollte es ausreichen, wenn nicht probier das mal (dauert aber wesentlich länger):

    use strict;
    use Time::HiRes qw/gettimeofday/;

    my @sessions;
    my $salt = 'XX';

    for (1..600)
    {
     my $session = (gettimeofday)[1];
     my $salt = getSalt();
     $session = crypt($salt,$session);
     push @sessions, $session;
    }

    my %keys = map{ $_, 1} @sessions;

    print scalar keys %keys, "\n"; # soll: 600 ist: 591

    sub getSalt
    {
        my $anzahl = shift || 2;
        return join '', map { (0..9, 'A'..'Z', 'a'..'z')[rand 64]; } (0..$anzahl);
    }

    Struppi.

    1. hi Struppi,

      use Time::HiRes qw/gettimeofday/;

      habch leider nicht auf der Büchse... aber ich denke mal, dass time.$$ auf LINUXn so ziemlich eindeutig sein sollte. Meine Lösung ganz wird somit ein bischen vereinfacht:

      use strict;

      my @sessions;
      my $tests = 10000;
      for(1..$tests){
       my @salts;
       my $salt;

      # salts erzeugen
       for("a".."z"){ push @salts, $_ }
       shuffle(@salts);
       $salt = join "", @salts;

      # und nun crypten
       my $zufall = crypt($salt,time.$$);

      # zufallsworte einlesen
       push @sessions, $zufall;
      }

      teste

      my %keys = map{ $_,1}@sessions;
      print scalar keys %keys, "\n$tests\n";
      print "$sessions[0]\n";

      subfunktion menge mischen (siehe PERL Doku: fisher_yates_shuffle)

      sub shuffle{
       my $array = shift;
       my $i;
       for ($i = @$array; --$i;){
        my $j = int rand ($i+1);
        next if $i == $j;
        @$array[$i,$j] = @$array[$j,$i];
       }
      }

      ... und der Abend ist gerettet ;-)

      Viele Grüße, Rolf

      1. hi Struppi,

        use Time::HiRes qw/gettimeofday/;

        habch leider nicht auf der Büchse... aber ich denke mal, dass time.$$ auf LINUXn so ziemlich eindeutig sein sollte. Meine Lösung ganz wird somit ein bischen vereinfacht:

        Naja, wenn's so wäre würde es ja ausreichen. Ich hatte beim meinen tests 2 x 6000 einmalige Strings.

        salts erzeugen

        for("a".."z"){ push @salts, $_ }
        shuffle(@salts);
        $salt = join "", @salts;

        und nun crypten

        my $zufall = crypt($salt,time.$$);

        salt braucht nur 2 stellig zu sein, bzw. es werden nur die ersten beiden Stellen verwendet. siehe mein Beispiel für einen zufälligen Wert.

        Struppi.

  4. Moin!

    siehe Betreff. Mein Versuch mit

    =try...
    my @sessions;
    for (1..60){
     my $session = time.$$;
     my $salt = int rand 98 + 1;
     $session = crypt($salt,$session);
     push @sessions, $session;
    }

    print sort join "\n", @sessions, "\n";
    =cut

    zeigt jedoch dass es doppelte IDs gibt. Hat jemand einen besseren Vorschlag?

    In ziemlich vielen Apache-Installationen war das Modul mod_unique_id installiert, dessen einzige Aufgabe es ist, bei jedem Request eine eindeutige ID in die Umgebungsvariablen einzufügen.

    Auch wenn dein Apache dieses Modul nicht aktiviert hat: Die Überlegungen, wie man zu einer eindeutigen ID kommt, sind nicht uninteressant: http://httpd.apache.org/docs/mod/mod_unique_id.html

    Allerdings ist diese ID komplett auf berechenbaren Komponenten aufgebaut. Gerade bei Session-IDs sollte sowas aber nicht passieren, denn damit kann man die generierten Session-IDs bei Kenntnis des Algorithmus raten.

    - Sven Rautenberg

    --
    ss:) zu:) ls:[ fo:} de:] va:) ch:] sh:) n4:# rl:| br:< js:| ie:( fl:( mo:|
    1. hi Sven,

      Auch wenn dein Apache dieses Modul nicht aktiviert hat: Die Überlegungen, wie man zu einer eindeutigen ID kommt, sind nicht uninteressant: http://httpd.apache.org/docs/mod/mod_unique_id.html

      yes it is. Aber so was richtig zufälliges gibts ja in der EDV nicht wirklich...

      Allerdings ist diese ID komplett auf berechenbaren Komponenten aufgebaut.

      ...eben deswegen. Auch bei anderen Lösungen...

      Gerade bei Session-IDs sollte sowas aber nicht passieren, denn damit kann man die generierten Session-IDs bei Kenntnis des Algorithmus raten.

      Es gibt noch einen anderen Grund dafür zu sorgen dass eine sessionID eindeutig ist: Das recyclen der sessionDB auf dem Server. Mal angenommen es haben einige 1000 User Sessions aufgebaut wofür eine Auth. erforderlich war. Von diesen Sessions könnten einige als *Leichen* in der DB bestehen bleiben und: wie es der Zufall so will kommt einer mit einer SessionID daher die es noch in der DB gibt. Aber das wäre ja dann wirklich Zufall...

      Viele Grüße, Rolf

      --

      SELFforum - Das Tor zur Welt!
      1. Hi,

        yes it is. Aber so was richtig zufälliges gibts ja in der EDV nicht wirklich...

        es gibt wirklich keinen Zufall.   ;-)

        Es gibt noch einen anderen Grund dafür zu sorgen dass eine sessionID eindeutig ist: Das recyclen der sessionDB auf dem Server.

        Du kannst voellig ohne Tricks sicherstellen, dass eine SessionID eindeutig ist, wenn Du bereits vergebene SessionIDs speicherst. Was ist uebrigens Recyceln einer Session-DB?

        Mal angenommen es haben einige 1000 User Sessions aufgebaut wofür eine Auth. erforderlich war. Von diesen Sessions könnten einige als *Leichen* in der DB bestehen bleiben und: wie es der Zufall so will kommt einer mit einer SessionID daher die es noch in der DB gibt. Aber das wäre ja dann wirklich Zufall...

        Sessions sollten austimen, oder?

        Gruss,
        Lude

      2. Moin!

        Allerdings ist diese ID komplett auf berechenbaren Komponenten aufgebaut.

        ...eben deswegen. Auch bei anderen Lösungen...

        ...auch bei deiner Lösung. ;)

        Gerade bei Session-IDs sollte sowas aber nicht passieren, denn damit kann man die generierten Session-IDs bei Kenntnis des Algorithmus raten.

        Hier hätte ich jetzt lieber "besser raten" geschrieben. Wenn klar ist, dass die Session-ID von ein paar quasi-konstanten Werten und der Zeit abhängt, und diese Daten dann allesamt durch einen Verwürfelungsalgorithmus geschickt werden (crypt ist in diesem Falle noch schlimmer, als MD5, weil kürzer), dann kann man leicht brute-forcen.

        Andererseits: Wenn man eine augenscheinlich zufällige Session-ID sieht, und nicht mehr, dann kann man noch soviel Rumprobieren und Raten und wird trotzdem nicht auf den Algorithmus kommen.

        Dazu reicht ja im Prinzip schon eine einzige, nicht im Algorithmus festgelegte Komponente, auf die auch sonst niemand kommt, also beispielsweise ein fester Salt-Wert, der immer noch mit ins MD5 eingeht.

        Ich behaupte mal, dass die UNIQUE_ID, die aktuelle Zeit sowie ein fester, aber je Installation unterschiedlicher Wert zusammengenommen reichlich wechselnde Informationen liefern, um mit MD5 einen schön zufälligen Wert für eine Session-ID zu gewinnen.

        Wenn du befürchten mußt, dass ein Angreifer den konfigurierten Festwert kennt, dann hast du ohnehin ganz andere Systemsicherheitsprobleme.

        Es gibt noch einen anderen Grund dafür zu sorgen dass eine sessionID eindeutig ist: Das recyclen der sessionDB auf dem Server. Mal angenommen es haben einige 1000 User Sessions aufgebaut wofür eine Auth. erforderlich war. Von diesen Sessions könnten einige als *Leichen* in der DB bestehen bleiben und: wie es der Zufall so will kommt einer mit einer SessionID daher die es noch in der DB gibt. Aber das wäre ja dann wirklich Zufall...

        Das ist alles eine Frage des angebotenen Zahlenraumes für die Session-ID.

        Wenn du mit Crypt arbeitest, dann kriegst du als Resultat einen 13 Zeichen langen String mit alphanumerischen Zeichen heraus. Crypt selbst liefert nur 56 Bit = 7,2e+16 verschiedene, gleichverteilte Werte.

        MD5 hingegen liefert einen 16-Byte-Wert, also 128 Bits. Das sind 3,4e+38 verschiedene Werte.

        Und wenn alle Stricke reißen, nimmst du SHA1 als Verwürfler: Der Algorithmus liefert 160 Bit = 1,4e+48 verschiedene Werte.

        Die einzige Möglichkeit, zufälliger als beim Lotto auf eine existierende Session zu treffen, ist durch a) identische Eingaben an die Verwürflungsfunktionen, oder b) durch Kollisionen in den Verwürflungsfunktionen (unterschiedliche Eingaben ergeben denselben Ausgabewert).

        Für MD5 möchte ich mal ausschließen, dass es zu Kollisionen kommt, wenn man den Algorithmus mit weniger als 128 Bit langen, garantiert unterschiedlichen Strings füttert. Insbesondere sollte es keinerlei Kollision bei sehr ähnlichen Strings geben - also ist eine ständig wachsende Komponente wie die Zeit an dieser Stelle nicht verkehrt. Sie ändert nur wenig am String, was aber große Auswirkungen beim Resultat hat.

        Abgesehen davon gilt das von Lude gesagte: Eine Session darf nicht unendlich lange offen bleiben, sondern muß ein Verfallsdatum haben. Ist dieses überschritten, werden alle Sessiondaten gelöscht.

        Was deinen Test angeht: Wenn du zeitbasiert Session-IDs generierst und in einer schnellen Schleife prüfst, ob identische IDs vorkommen, sagt das nicht so viel über die Brauchbarkeit des Algorithmus aus. Zeit ist ein kritischer, aber auch der limitierende Faktor. Ein Webserver erhält nur eine gewisse Anzahl von Requests pro Zeit. Aber was vermieden werden sollte ist, dass zwei Requests, die gleichzeitig ablaufen (bei Mehrprozessormaschinen ist das sogar möglich) nicht dieselbe SID erhalten.

        - Sven Rautenberg

        --
        ss:) zu:) ls:[ fo:} de:] va:) ch:] sh:) n4:# rl:| br:< js:| ie:( fl:( mo:|
        1. hi Sven

          klaro, MD5 ;-)

          muss mal testen.... kleine Tücke: mein Provider gibt mir keine shell. d.h., ich muss mir für solche sachen was einfallen lassen ;-))

          Rolf

          und mir fällt meistens was ein.

  5. Hi,

    zeigt jedoch dass es doppelte IDs gibt. Hat jemand einen besseren Vorschlag?

    Warum das Rad neu erfinden? Wenn du die Möglichkeit hast, eigene Module einzubauen, schau dir doch mal CGI::Session an: http://search.cpan.org/~sherzodr/CGI-Session-3.95/Session.pm

    HTH

    wunderwarzenschwein

    --
    ss:} zu:$ ls:} fo:| de:] va:) ch:? sh:( n4:# rl:? br:> js:| ie:( fl:{ mo:)
  6. Hallo,

    for (1..60){
    my $session = time.$$;
    }

    zeigt jedoch dass es doppelte IDs gibt. Hat jemand einen besseren Vorschlag?

    Du hast ja auch blos ein Script, da steckst du dann eine Schleife rein. Aber im realen Einsatz soltle dein Script pro Request ja nur eine Session erzeugen. Da $$ die Prozess-ID ist ist der Inhalt dieser Variablen dann natürlich auch bei jedem Aufruf deines Scriptes ein anderer. Das sollte dann die doppelten Session IDs ausschließen.

    Bau dir doch einfach eine ID aus folgenden Komponenten:

    • Zeit (Hast du ja schon)
    • PID  (dito)
    • IP des Clients von dem der Request kam
    • Halbwegs große Zufallszahl

    Da sollte eigentlich nix doppeltes bei rauskommen.

    Viele Grüße,

    Stefan

    --
    Lass dir das Tanzen NICHT verbieten
    http://tanzverbot.de
  7. hi!

    vielen Dank für die vielen und guten Tipps!

    'Schwerd's beschde draus mache :-)

    Viele Grüße, Rolliwitsch