[php] veiligheid login systeem

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Ik heb een heel mooi login systeem geimplementeerd aan de hand van Crisp's stappen plan:
crisp in "[PHP] BeveiligingsTips nodig"

Het werkt allemaal perfect. En heb er zelf nog een salt aan toegevoegd en in een class gezet.

Maar waar ik over twijfel is het volgende.
Per pagina die beveiligd moet worden moet hetvolgende gedaan worden:
+ Kijken of er een cookie is, met daarin een SessieId
+ SID opzoeken in tabel, kijken of TTD niet verstreken is
+ dingen ophalen voor in sessie object

Mocht iemand nu dus een cookie spoofen met daarin een bestaand sessie id; dan heeft deze persoon dus gewoon toegang tot het systeem. Wat natuurlijk niet wenselijk is.

Het SID is als volgt opgebouwd:
PHP:
1
2
3
4
5
6
function _generateSessieID(){
        list($usec, $sec) = explode(' ', microtime());
        $seed = (float) $sec + ((float) $usec * 100000);
        
        return md5(time()*microtime()*$seed);;
   }

Dus dit is wel lekker random zullen we maar zeggen.
Maar dan nog, als iemand de $sid raadt, of gokt dan kan je gewoon doen wat je wilt.

Is er hier een oplossing voor? Of maak ik me nu zorgen over een kans van 1 op tig miljoen?

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

  • ShitHappens
  • Registratie: Juli 2008
  • Laatst online: 20-09 19:09
IP erbij laten onthouden? Samen met de sessie in een cookie en DB... of is dat nou een slechte suggestie?

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
True; Dat ben ik nu aan het implementeren.

Maar
1) IP's zijn ook te spoofen.....
2) Plus als je een laptop hebt en je werkt op twee plaatsen, dan blijf je dus ook niet ingelogd.

[ Voor 17% gewijzigd door hobbeldebobbel op 30-11-2009 17:28 ]

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
hobbeldebobbel schreef op maandag 30 november 2009 @ 17:22:
Dus dit is wel lekker random zullen we maar zeggen.
Dat zou ik juist niet zeggen, als je weet hoelaat het sessie-id gecreëerd is, is vinden ervan opeens een stuk minder werk.

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Woops....
Dat is inderdaad waar. Er moet dus nog een andere string bij. Gewoon een lange blowfish dus. Thanx voor het opmerken!
Heb er nu de user agent, remote_ip, en een random string van 36 karakter in gebakken.

[ Voor 35% gewijzigd door hobbeldebobbel op 30-11-2009 17:40 ]

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Waarom zou je uitgelogd zijn bij 2 sessies? Gewoon je sessie zelf op ip locken (als extra! niet iedereen heeft een vast ip!)

Overigens werkt het op heel veel sites zo (ook hier) dat als je toevallig een juiste session id weet te vinden je ingelogd bent als die persoon (tenzij de sessie beveiligd is op ip dus).

edit:
waarom maar 32 karakters als random key? Pak iets als SHA256 of Whirlpool en je hebt ineens een bak meer mogelijkheden :)

[ Voor 17% gewijzigd door Cartman! op 30-11-2009 17:53 ]


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Een paar mogelijke aandachtspuntjes:

1) Controleer of je niet vatbaar bent voor session fixation.
2) Verander van session id zodra je authenticatieniveau verandert (hangt samen met 1).
3) Zorg voor een mogelijkheid voor de eindgebruiker om sessions te verwijderen.

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
De sessie generator is nu de volgende method geworden en hopelijk een stuk minder makkelijk te raden.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   function _generateSessieID(){
        list($usec, $sec) = explode(' ', microtime());
        $seed = (float) $sec + ((float) $usec * 100000);
        
        $str = hash('sha256',$this->_rnd());
        $remip = $_SERVER["REMOTE_ADDR"];
        $ua = $_SERVER['HTTP_USER_AGENT'];
        $tim = (time()*microtime())/$seed;
        
        return md5($str.$remip.md5($tim.$ua));
        
        
   }
   
   function _rnd($l=36){
        $keuze = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        $keuze = str_split($keuze);
        $ret = '';
        for($i=0;$i <= $l;$i++){
            $ret .= $keuze[rand(0,count($keuze))];
            
        }
        return $ret;
   }


De drie punten van de poster hier boven mij heb ik deels wel al geintegreerd.
Op het moment van bezoeken van de inlogpagina wordt er een sessie id aangemaakt. Slaagt het in loggen word die getrashed en een nieuwe aangemaakt. Die nieuwe word weggeschreven in een cookie.
Is het te overdreven om bij iedere page load de sessie id te vervangen? Of om de twee drie uur of iets dergelijks? Of heeft dat geen effect op de sterkte?

Met de term session fixation kan ik weer verder zoeken naar nieuwe versterkingen; bedankt daarvoor.

Vooralsnog zit ik aan de volgende versterkingen / extra challenges te denken: Met session fixation in mijn achterhoofd.
1-aan ip gekoppelde sessie
2-useragent ook gebruiken als challenge.

[ Voor 7% gewijzigd door hobbeldebobbel op 30-11-2009 20:38 . Reden: teovoeging ]

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

Verwijderd

Volgens mij ben je verschrikkelijk aan het overdrijven.

Het fixen van het IP is genoeg want het IP zijn bij HTTP en daarmee TCP niet effectief te spoofen. Je zou wel een HTTP request kunnen sturen maar het antwoord zou altijd naar het ge-spoofde IP worden verstuurd. Je zult dus je kritische formulieren wel 2 weg moeten maken door hier simpelweg een random id aan toe te voegen en deze weer controleren. Op deze manier heb je een waterdicht systeem waarbij een sessie niet valt te stelen tenzij je toevallig via dezelfde proxy of NAT verbindt maar dat kun je fixen denk ik door HTTPS te gebruiken.

PHP:
1
2
3
4
5
6
7
8
9
10
 function _generateSessieID(){
   $seed = microtime();
   $salt = "Dit is mijn salt";
   $rnd = rand(PHP_INT_MIN, PHP_INT_MAX);
   $ip = $_SERVER["REMOTE_ADDR"];
   $ua = $_SERVER["HTTP_USER_AGENT"];

   $hash = sha1($seed.$salt.$rnd.$ip.$ua);
  return $hash;
 }

Dit zou genoeg moeten zijn. Net zoals dubbel hashen niet meer beveiliging geeft kun je alle eigenschappen dus gewoon op 1 hoop gooien en er 1 sha1 hash van maken. De combinatie van microtime, salt en een random number is genoeg om de kans op het raden van een sessie id zeer onwaarschijnlijk te maken en mocht het toch op een of andere manier weglekken dan kun je het alleen van een enkele IP gebruiken. Ruim voldoende dus.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Wat is de gedachte aan gegevens ( als een ip / ua ) + rnd() in een hash stoppen? Je kan er nooit meer tegen controleren vanwege je rnd(). Ik zie het even niet.

Ik zou je UA / IP gewoon opslaan in aparte kolommen in je sessie tabel en daar gewoon op vergelijken mocht je het willen. Een IP versleutelt in een hash heb je gewoon niets aan, sla je hem los op dan kun je hem als extra check gebruiken, hetzelfde met een UA.

Hetzelfde geldt wmb voor een tijd in je hash.

Een hash is non-reversible, in theorie is enkel een lang genoege random string al voldoende, maar vanwege rainbow tables moet je er nog een salt bijgooien. Tijd / ip's / ua's moet je gewoon uit je hash trekken en los controleren...

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Die hash functie die hierboven staat gebruik ik enkel om een unieke sessie id te maken die zo veel mogelijk uniek is. Vandaar ook de naam: _generateSessieID().
In de sessie tabel staan uiteraard nog de kolommen voor UA en IP. Dat ze in de hash voorkomen is gewoon een extraatje om de string waar de md5 van gemaakt word unieker en tijdstip onafhankelijker te maken.

De challenge op de IP en UA gebeurd uiteraard aan de hand van de sessie tabel en natuurlijk niet vanuit de hash!

@docey
Gelukkig zeg je dat ik aan het overdrijven bent. Beter dan dat je zou zeggen dat het zo lek is als een mandje :) Dat is ook mijn grootste gebrek. Ik weet niet wanneer iets veilig genoeg is. Er zitten uiteraard geen top secret CIA gegevens achter de login; maar toch.

Als je dubbel hashed dan moet je toch om alle gegevens eruit te halen twee keer "kraken" dat is toch moeilijker dan 1 keer kraken.

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

  • Hipska
  • Registratie: Mei 2008
  • Laatst online: 15-09 21:08
PHP:
2
3
list($usec, $sec) = explode(' ', microtime()); 
$seed = (float) $sec + ((float) $usec * 100000);

wat is er mis met dit?
PHP:
1
$seed = microtime(true);
hobbeldebobbel schreef op maandag 30 november 2009 @ 20:37:Is het te overdreven om bij iedere page load de sessie id te vervangen? Of om de twee drie uur of iets dergelijks? Of heeft dat geen effect op de sterkte?
Dat vraag ik mij ook af of dat overdreven zou zijn. Je kan makkelijk session_regenerate_id() op elke pagina-request aanroepen, maar wat dat voor consequenties heeft weet ik niet.
Vooralsnog zit ik aan de volgende versterkingen / extra challenges te denken: Met session fixation in mijn achterhoofd.
1-aan ip gekoppelde sessie
2-useragent ook gebruiken als challenge.
Deze dingen zitten nu al in je session ID, maar ik besef net dat je er niet op controlleert bij de volgende pagina request.
Ik heb dit opgelost door de session ID door php te laten genereren (weet trouwens niet waarom je die niet zou laten door de standaard php genereren?), maar de cookie name oftewel session_name() hangt af van IP en user agent en een pepper + salt.
Hierdoor zoekt ie enkel naar een session ID in de juiste cookie. Bij andere personen die de cookie kopiëren heeft het geen werking (omdat hun ip en browser ID normaal niet dezelfde zijn), enkel bij diegene die in hun session cookie dit ander id invullen is er nog controle omdat ik het session_name ook nog es in de sessie zelf gestoken had en bij verschillende waardes is er heel zeker gesjoemel..

Acties:
  • 0 Henk 'm!

  • hostname
  • Registratie: April 2009
  • Laatst online: 01:08
hobbeldebobbel schreef op maandag 30 november 2009 @ 20:37:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   function _generateSessieID(){
        list($usec, $sec) = explode(' ', microtime());
        $seed = (float) $sec + ((float) $usec * 100000);
        
        $str = hash('sha256',$this->_rnd());
        $remip = $_SERVER["REMOTE_ADDR"];
        $ua = $_SERVER['HTTP_USER_AGENT'];
        $tim = (time()*microtime())/$seed;
        
        return md5($str.$remip.md5($tim.$ua));
        
        
   }
   
   function _rnd($l=36){
        $keuze = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        $keuze = str_split($keuze);
        $ret = '';
        for($i=0;$i <= $l;$i++){
            $ret .= $keuze[rand(0,count($keuze))];
            
        }
        return $ret;
   }
Waarom niet gewoon een sha256 van $this->_rnd() . microtime() . time() . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] doen, als je die er allemaal in wilt verwerken? Sowieso lijkt mij time() en microtime() nogal dubbelop, en hashes van hashes is nogal overbodig lijkt mij?

offtopic:
Kijk voor je _rnd() eens naar array_rand().


Een andere truc die je kan toepassen is het elke request wijzigen van je sid. De kans dat iemand die dan raad, en snel genoeg is, is wel een heel stuk kleiner, en er zitten ook geen nadelen aan (behalve elke keer het setten van het cookie)?

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
hobbeldebobbel schreef op maandag 30 november 2009 @ 22:21:
Als je dubbel hashed dan moet je toch om alle gegevens eruit te halen twee keer "kraken" dat is toch moeilijker dan 1 keer kraken.
Nope.

Even aan de hand van een iets simpeler uit te leggen voorbeeld : md5(md5(rnd() . UA ))
1e x gaat de hash over een string van x tekens ( onbekend omdat je de UA niet weet en die kan redelijk lang zijn :) ), 2e x gaat de hash enkel nog maar over 32 tekens.

Hashes zijn niet te "kraken", want ze zijn niet terug te halen, je kan enkel colissions genereren en dat is met een pool van 32 tekens simpeler.

Je hoeft nooit de binnenste hash te "kraken", je hoeft enkel de buitenste te raden, dat is waarmee gecommuniceerd wordt.
hostname schreef op maandag 30 november 2009 @ 22:33:
[...]
Een andere truc die je kan toepassen is het elke request wijzigen van je sid. De kans dat iemand die dan raad, en snel genoeg is, is wel een heel stuk kleiner, en er zitten ook geen nadelen aan (behalve elke keer het setten van het cookie)?
Tja, redelijk duur trucje wat ook nog redelijk errorgevoelig is als mensen met meerdere tabbladen oid browsen, of je ajax oid gebruikt.
Gewoon je sid enkel wijzigen als het nodig is ( een verhoogd level bijvoorbeeld )

[ Voor 27% gewijzigd door Gomez12 op 30-11-2009 22:49 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Wat wordt er weer moeilijk gedaan over iets dat PHP zelf al prima kan. Session ID's genereren.

Een session ID raden... doe je best. Raad maar raak. De kans is dat je een session ID juist raadt is zo klein dat het belachelijk is om het te proberen.

Als het écht heel belangrijk is, moet je bij elke belangrijke actie trouwens om authenticatie vragen, en zijn sessies zwaar onvoldoende. Kortom, wat is veiligheid eigenlijk? In elk geval een directe vijand van gebruikersgemak.

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 20-09 00:06
hobbeldebobbel schreef op maandag 30 november 2009 @ 20:37:
PHP:
1
2
3
4
5
6
   function _rnd($l=36){
        $keuze = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        $keuze = str_split($keuze);
        $ret = '';
        for($i=0;$i <= $l;$i++){
            $ret .= $keuze[rand(0,count($keuze))];
Hier heb je een off-by-one error: rand(a, b) geeft max b terug en niet b-1, dus mogelijk indexeer je je array met de lengte van de array.

Gebruik gewoon de standaard session van PHP, die maakt ook een prachtig niet te raden id, kijk maar.
hobbeldebobbel schreef op maandag 30 november 2009 @ 22:21:
Die hash functie die hierboven staat gebruik ik enkel om een unieke sessie id te maken die zo veel mogelijk uniek is. Vandaar ook de naam: _generateSessieID().
In de sessie tabel staan uiteraard nog de kolommen voor UA en IP. Dat ze in de hash voorkomen is gewoon een extraatje om de string waar de md5 van gemaakt word unieker en tijdstip onafhankelijker te maken.

De challenge op de IP en UA gebeurd uiteraard aan de hand van de sessie tabel en natuurlijk niet vanuit de hash!
De check of het IP wel hetzelfde is als bij het inloggen is geen "challenge" in de technische betekenis van het woord, maar het is op zich wel een zinnige check.

Een "echte" challenge voorkomt dat een aanvaller met gesniffte communicatie van de inlogactie kan inloggen op het systeem doordat de authenticatiegegevens in het loginrequest maar een enkele keer gebruikt kan worden.

Dit kan worden bereikt door in plaats van het plaintext wachtwoord (of alleen een hash ervan die voor een "replay attack" kan worden gebruikt) de client een hash te laten sturen van een nonce (number used once) en het wachtwoord. Server side controleer je of de gehashte waarde overeenkomt met de hash van de nonce+wachtwoord die je uit de db haalt.

Maar je kan ook gewoon SSL voor het inloggen verplichten - bij het opzetten van de beveiligde verbinding gebeuren dit soort dingen allemaal al, en veel beter getest en uitgedacht dan dat wanneer je het zelf maakt (vooral met crips' overgecompliceerde tig-stappenplan).

[ Voor 5% gewijzigd door matthijsln op 30-11-2009 23:04 ]


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 19-09 11:00

Ventieldopje

I'm not your pal, mate!

Als het echt zo veilig moet zijn waarom gebruik je dan niet gewoon SSL? En je loginsysteem is waarschijnlijk veilig genoeg, mensen moeten er ook nog achter komen hoe het helemaal in elkaar zit, en tenzij je dit voor iets waardevols gaat gebruiken gaan mensen dat niet eens proberen ;)

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

Verwijderd

SSL beveiligt je verbinding wel, maar is echt niet de heilige graal. Het voorkomt het sniffen van wachtwoorden, maar het wachtwoord moet nog steeds naar de server. Daarom toch altijd challenge/response gebruiken, ook al maak je gebruik van SSL.

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Ok. Ik ga morgen ochtend even alles goed door lezen en beantwoorden.

In mijn systeem wordt er geen wachtwoord of hash van het wachtwoord over het net gestuurd. Het wordt clientside als volgt behandeld: md5(md5(wachtwoord) + gebruikerid + sessionid) die hash gaat over het net en serverside gecontroleerd aan de hand van dezelfde gegevens.

De sessionID wordt bij iedere opvraging van het login formulier aangemaakt met een bepekte geldigheids duur van 15 minuten en een userid '0', ip en ua. De key vervliegt dus na 15 minuten.

Na het controleren wordt de initiële sessie getrashed (de formulier sessie zeg maar) en een nieuwe aangemaakt inclusief de appropriate gegevens. Deze nieuwe session id wordt dan in een cookie gezet.

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

Verwijderd

Nog 1 ding: sla je wachtwoord in de database op met een salt die voor elke gebruiker anders is, bijvoorbeeld het emailadres of de username. Op die manier kun je niet tegen iets heel simpels aanlopen, namelijk dat er twee hashes in de database gelijk zijn. Gelijke hashes betekent met een gelijke salt vrijwel zeker dat het dezelfde wachtwoorden zijn. En twee dezelfde wachtwoorden betekent over het algemeen twee zwakke wachtwoorden. Die zijn dus het eerste doelwit als de database op straat ligt.

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 20-09 00:06
hobbeldebobbel schreef op maandag 30 november 2009 @ 23:56:
md5(md5(wachtwoord) + gebruikerid + sessionid)
Is dus minder veilig dan md5(wachtwoord + gebruikerid + sessionid) - maar dat lees je dus nog wel :)

En dit is inderdaad wel een challenge, maar veel complexer dan nodig. Het gebruikerid in de hash gebruiken voegt praktisch niks toe, de sessionid die hier gebruikt wordt als nonce is voldoende. Dus gewoon PHP sessies met een nonce is een veel simpelere oplossing. Het session id veranderen is in principe dan ook niet nodig, maar kan eventueel wel met set_session_id().

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 20-09 00:06
Verwijderd schreef op maandag 30 november 2009 @ 23:21:
SSL beveiligt je verbinding wel, maar is echt niet de heilige graal. Het voorkomt het sniffen van wachtwoorden, maar het wachtwoord moet nog steeds naar de server. Daarom toch altijd challenge/response gebruiken, ook al maak je gebruik van SSL.
Alleen SSL is anders beter dan alleen challenge/response. MITM attack helpt challenge/response niet tegen, bij SSL krijg je dan hopelijk nog een certificaatfout.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ik heb t eerder gezegd maar waarom nog steeds md5 nemen als je veiligheid wil? Neem een sterkere hashmethode (sha256, sha512, whirlpool) en je mogelijkheden zijn eindeloos*

Het zo lastig mogelijk maken van je generatie van een random session_id is imo ook overtrokken. Als iemand in je code kan kijken hoe ze gegenereerd worden dan ben je toch al de sjaak.

* niet helemaal natuurlijk, maar extreem veel

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Om deze
md5(wachtwoord + gebruikerid + sessionid)
serverside te genereren zal ik het wachtwoord ook in de database moeten hebben staan. In plain text is dat.
Vandaar de md5( md5(wachtwoord) + gebruikerid + sessieid). Dan heb ik in mijn database iig niet de plain text wachtwoorden staan.

De md5 ga ik inderdaad nog omzetten naar sha256. Ik wil het ook voor systemen met php<5 maken dus daar is de hash functie niet aanwezig... even een oplossing daarvoor zoeken.

Het probleem van twee dezelfde hashes in het ww-veld is inderdaad een probleem. Maar dat ga ik op de manier van cheetah oplossen. Met behulp van de gebruikersnaam; aangezien ik die ook aan de client kant heb.

Thanx voor het meedenken!!

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Waarom nog voor PHP4 maken? Dat is al jaren depricated. Als iemand een hostingpartij heeft met PHP4 dan moet ie gewoon opzeggen en een echte host zoeken.

Overigens kun je ook vast wel een PHP implementatie van SHA256 kunt vinden gezien je zelfs javascript kunt vinden die dit kunnen.

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Cartman! schreef op dinsdag 01 december 2009 @ 08:57:
Het zo lastig mogelijk maken van je generatie van een random session_id is imo ook overtrokken. Als iemand in je code kan kijken hoe ze gegenereerd worden dan ben je toch al de sjaak.
Wat een onzin... waarom zou je het niet veilig maken ook als iemand je code heeft? Je moet het gewoon van een echt random systeemprocess laten afhangen en dat is best te doen op verschillende manieren.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Imo heeft veiligheid niet zozeer veel te maken met hoe je een random session_id genereert in dit systeem. Het moet iets unieks worden en daar zorgt je hashing algoritme keurig voor. Als je gewoon een sterk algoritme pakt dan heb je vrijwel eindeloze mogelijkheden. Een simpele "microtime() . rand(1,9999) . microtime()" is daar genoeg voor. Veiligheid daarna maak je meer door session fixation tegen te gaan, of dmv. ipcheck (als de user dit heeft gekozen).

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Cartman! schreef op dinsdag 01 december 2009 @ 15:04:
Imo heeft veiligheid niet zozeer veel te maken met hoe je een random session_id genereert in dit systeem. Het moet iets unieks worden en daar zorgt je hashing algoritme keurig voor. Als je gewoon een sterk algoritme pakt dan heb je vrijwel eindeloze mogelijkheden. Een simpele "microtime() . rand(1,9999) . microtime()" is daar genoeg voor. Veiligheid daarna maak je meer door session fixation tegen te gaan, of dmv. ipcheck (als de user dit heeft gekozen).
Maar in dit geval hangt je session id af van 2 * microtime en een rand ( die waarschijnlijk ook met de tijd geseed word ), en dus kun je het session_id raden als je weet wanneer de sessie ongeveer gestart is.

Je hoeft echt niet een complex algoritme te bedenken, maar je moet gewoon een goede random source hebben.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ik snap je punt zeker. Maar je gaat er dan vanuit dat een ander weet hoe jouw algoritme (ook al is ie simpel) in elkaar steekt. Als iemand dat kan achterhalen dan heeft ie blijkbaar al meer toegang dan ie hoort te krijgen. Als je gewoon je gebruikers aanmoedigt om hun sessies te koppelen aan hun ip-adres dan is daar sowieso al geen probleem mee.

Zelf pak ik overigens vaak username+microtime, username is immers toch uniek maar de microtime+rand is even een voorbeeld. M'n punt is dat ik de stukken code die eerder gezet zijn absolute overkill vind voor wat het moet doen.

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Voor mijn wachtwoord codering, volstaat dan sha1? Of moet ik sha256 gaan gebruiken?

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

Verwijderd

hobbeldebobbel schreef op woensdag 02 december 2009 @ 18:12:
Voor mijn wachtwoord codering, volstaat dan sha1? Of moet ik sha256 gaan gebruiken?
MD5 voldoet ook wel hoor. Veel developers ijlen een beetje onnodig over sommige zwaktes van MD5.
Dat heeft meestal te maken met het kunnen veroorzaken van collisions. In gevallen als deze maakt het niet uit. De enige reden om het wachtwoord te hashen (wel met salt!) is immers om het originele wachtwoord te beschermen.

Als iemand aan je password hashes kan komen heb je wel een ander probleem en maak je je allerminst zorgen om collisions.

Acties:
  • 0 Henk 'm!

  • hobbeldebobbel
  • Registratie: Februari 2001
  • Laatst online: 15-02-2023
Ok. Ik heb zojuist alles omgebouwd naar sha1 :) dus dat laat ik maar lekker zo zitten dan.

Is de gebruikersnaam als salt ok?

hier zou een slimme opmerking kunnen staan
maar die staat er niet


Acties:
  • 0 Henk 'm!

Verwijderd

Uiteraard. De gebruikersnaam is sowieso bekend, en uniek. Dat geeft bijna 100% garantie op een unieke hash, zelfs bij twee gelijke (en overigens dus te eenvoudige) wachtwoorden. Alleen in uiterst zeldzame gevallen die nooit zullen voorkomen krijg je een collision. Maar zelfs dan maakt het je niet uit.

Je kunt de hash dan makkelijk client-side maken door gebruikersnaam en wachtwoord samen te hashen. Op de server staat die hash in de database. Technisch gezien hoeft de server dus nooit het origineel te kennen.

Aangezien dezelfde hash client-side en server-side beschikbaar zijn, kun je een challenge/response daarmee doen. Zowel client als server kan een hash maken van de challenge en de passwordhash. Daarmee kunnen ze elkaar dus valideren, en hoeft zelfs de passwordhash maar één keer ooit over het netwerk, namelijk bij het instellen van het wachtwoord.

Acties:
  • 0 Henk 'm!

  • JefSnare
  • Registratie: Augustus 2007
  • Laatst online: 09-11-2020
kan iemand mij vertellen of dit dan gewoon overkill is voor een normaal inlog systeem of niet?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
 function _generateSessieID(){
   $seed = microtime();
   $salt = "Dit is mijn salt";
   $rnd = rand(PHP_INT_MIN, PHP_INT_MAX);
   $ip = $_SERVER["REMOTE_ADDR"];
   $ua = $_SERVER["HTTP_USER_AGENT"];

   $hash = sha1($seed.$salt.$rnd.$ip.$ua);
  return $hash;
 }
?>


Waarom zou je zo'n hash bouwen en is een sessie ID dan niet voldoende?
Verwijderd schreef op woensdag 02 december 2009 @ 18:44:
[...]

Uiteraard. De gebruikersnaam is sowieso bekend, en uniek. Dat geeft bijna 100% garantie op een unieke hash, zelfs bij twee gelijke (en overigens dus te eenvoudige) wachtwoorden. Alleen in uiterst zeldzame gevallen die nooit zullen voorkomen krijg je een collision. Maar zelfs dan maakt het je niet uit.

Je kunt de hash dan makkelijk client-side maken door gebruikersnaam en wachtwoord samen te hashen. Op de server staat die hash in de database. Technisch gezien hoeft de server dus nooit het origineel te kennen.

Aangezien dezelfde hash client-side en server-side beschikbaar zijn, kun je een challenge/response daarmee doen. Zowel client als server kan een hash maken van de challenge en de passwordhash. Daarmee kunnen ze elkaar dus valideren, en hoeft zelfs de passwordhash maar één keer ooit over het netwerk, namelijk bij het instellen van het wachtwoord.
Goed, dus we creëren dan dus een eigen hash die "veiliger" kan/moet zijn dan een sessie id? Wat is dan het principe nog van een response, moet je die dan nog maken? Of ben ik in de war... :?

Twitter Flickr


Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Als je een cookie set met userid en een cookie met een sessie dan moeten ze de sessie en het userid goed hebben. Dan maak je de kans aanzienlijk kleiner.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
JefSnare schreef op woensdag 02 december 2009 @ 22:27:
kan iemand mij vertellen of dit dan gewoon overkill is voor een normaal inlog systeem of niet?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
 function _generateSessieID(){
   $seed = microtime();
   $salt = "Dit is mijn salt";
   $rnd = rand(PHP_INT_MIN, PHP_INT_MAX);
   $ip = $_SERVER["REMOTE_ADDR"];
   $ua = $_SERVER["HTTP_USER_AGENT"];

   $hash = sha1($seed.$salt.$rnd.$ip.$ua);
  return $hash;
 }
?>
Ja, ik vind dat overkill... zie eerder voor m'n motivatie :)

Acties:
  • 0 Henk 'm!

  • JefSnare
  • Registratie: Augustus 2007
  • Laatst online: 09-11-2020
Cartman! schreef op woensdag 02 december 2009 @ 22:42:
[...]

Ja, ik vind dat overkill... zie eerder voor m'n motivatie :)
I agree met je eerder gegeven reden. Een sessie_id hashen met bijvoorbeeld microtime moet inderdaad mij genoeg lijken. Ik gebruik nu in mijn scripts: md5(session_id + md5(username) + microtime).

Twitter Flickr


Acties:
  • 0 Henk 'm!

Verwijderd

Je vergeet btw wel een belangrijke regel, elke client input filteren!

code:
1
 $ua = $_SERVER["HTTP_USER_AGENT"]


de http_user_agent kan je gewoon aanpassen in je http request. Stel dat je je $ua in een sql query gebruikt kan er gewoon sql injection plaatst vinden. Zal hier wel loslopen omdat je het alleen in een hash functie gebruikt.

edit: Daarnaast je hash functie md5 bevat cryptografische zwakheden waardoor de kans op collision kan worden afgedwongen, het is raadzaam om dit voor een beter hash algoritme (sha512) te vervangen.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Het nemen van de username als salt is een goed idee, alleen als je iemand zijn username verandert moet je verplicht iemand z'n password resetten, hoe gaan jullie daar mee om? :)

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 11:52:
Je vergeet btw wel een belangrijke regel, elke client input filteren!
Je moet user input alleen filteren op dingen die je niet wil hebben, en voor een hash functie haalt het niet zo veel uit.

Alleen vind ik het dan wel weer gek om een session id te laten afhangen van een user-agent.

In feite wil je dat hij niet te voorspellen is, en dus wil je er iets randoms in stoppen. Ik snap dan ook niet de meerwaarde om zowel rand() als microtime() in je hash mee te nemen. Beide zijn afhankelijk van de huidige tijd, dus als je die weet, en je weet het algoritme, kun je achterhalen welk session id er gegenereerd word. Het is IMHO dat ook zinloos om er veel meer dingen bij te betrekken.

simpel zou ik gewoon Hash( Microtime() + Username + Secret ) doen. De usename om te voorkomen dat 2 mensen hetzelfde session id krijgen als ze precies op dezelfde tijd gegenereerd worden. Het secret moet je dan ook buiten je algoritme houden, en zodra je secret per ongeluk op straat komt te liggen verander je die.

Dan heb je IMHO een simpel maar zeker veilig genoeg algoritme voor session id generatie. Verder kun je natuurlijk nog allerlei checks inbouwen zoals ip/useragent/weetikveelwat checks. Die hoef je echter niet mee te nemen in de generatie van je session id

[ Voor 3% gewijzigd door Woy op 03-12-2009 12:29 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Woy schreef op donderdag 03 december 2009 @ 12:28:
[...]

Je moet user input alleen filteren op dingen die je niet wil hebben, en voor een hash functie haalt het niet zo veel uit.
Die mening deel ik niet, je moet alle input altijd filteren.

A ) Je weet nooit of de code uitgebreid wordt door iemand anders waarmee je een potentieel lek aanvaard. Ja de uitbreider is hier verantwoordelijk voor maar over het algemeen vergeten mensen dat $_SERVER ook client invoer is waar mee gerommeld kan worden. Als je alle input altijd filtert ben je je in ieder geval een stuk bewuster van de data binnen je (web)app.

B ) Ook in dit geval, op het moment dat ook in het sha algoritme meerdere zwakheden ontstaan is in dit geval de UA exploitable voor zo'n attack aangezien je een string met willekeurige lengte erin kan stoppen wat weer tot collission kan leiden.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 12:44:
[...]


Die mening deel ik niet, je moet alle input altijd filteren.

A ) Je weet nooit of de code uitgebreid wordt door iemand anders waarmee je een potentieel lek aanvaard. Ja de uitbreider is hier verantwoordelijk voor maar over het algemeen vergeten mensen dat $_SERVER ook client invoer is waar mee gerommeld kan worden. Als je alle input altijd filtert ben je je in ieder geval een stuk bewuster van de data binnen je (web)app.

B ) Ook in dit geval, op het moment dat ook in het sha algoritme meerdere zwakheden ontstaan is in dit geval de UA exploitable voor zo'n attack aangezien je een string met willekeurige lengte erin kan stoppen wat weer tot collission kan leiden.
Tuurlijk moet je je er van bewust zijn dat het user-input is. Maar je hebt het bijvoorbeeld over SQL injection. Maar als je het voor een hash functie gebruikt heeft het 0,0 zin om bijvoorbeeld te gaan escapen voor SQL Injection.

Je moet kijken waar je de user-input voor gebruikt. Als er bij je hash algoritme bijvoorbeeld een limitatie aan de lengte zit, dan zul je daar ook zeker rekening mee moeten houden.

Maar je moet wel degelijk in de context waarin je aan het werken bent kijken wat je limitaties zijn. Anders ga gekke dingen krijgen zoals magic-quotes. Dat zijn dingen die nergens op slaan. Je zult dus eerst moeten kijken waar je in die bepaalde context op moet filteren. Zo is het bijna ondoenlijk om een user agent string te valideren.

Verder kun je er natuurlijk nooit rekening mee houden wat iemand allemaal aan je functie gaat veranderen. Ik ben dan ook wel benieuwd wat jij in deze functie aan filtering zou willen doen op de user-agent string. ( Buiten het feit dat ik voor deze functie dus nooit de user-agent string zou gebruiken )

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Woy schreef op donderdag 03 december 2009 @ 13:02:
[...]

Ik ben dan ook wel benieuwd wat jij in deze functie aan filtering zou willen doen op de user-agent string. ( Buiten het feit dat ik voor deze functie dus nooit de user-agent string zou gebruiken )
Ik zou de lengte limiteren, en in mijn php aps heb ik een functie whitelistchars(level,string, cscustom).

Level 1: a..z A..Z
Level 2: level1 + 0..9
Level 3: level2 + cscustom
level *: *

Invoer: whitelistchars(1,"ab3gda","");
Invoer2: whitelistchars(3,"ab3g#$%da","$,%");
Uitvoer: abgda
Uitvoer2: ab3g$%da

Op die manier vergeet je het niet en dwing je jezelf na te denken bij elke var. Overigens is het wat overdreven maar uit ervaring weet ik dat heel veel mensen de SERVER vars en cookie var vergeten als het om security gaat. De urlparameters zijn gesneden koek maar het lijkt alsof het begrip client invoer nog niet helemaal is doorgedrongen mede vandaar de opmerking.

nogmaals als je later weer verder gaat coden en je wil bijv. de ua op gaan slaan in een db is een foutje snel gemaakt vandaar dat het goed werkt voor mij om het bij decleratie al te fixen. (Dit is natuurlijk voor elke iedereen anders).
Woy schreef op donderdag 03 december 2009 @ 13:02:
[...]
( Buiten het feit dat ik voor deze functie dus nooit de user-agent string zou gebruiken )
Agree!

[ Voor 8% gewijzigd door Verwijderd op 03-12-2009 13:22 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 13:21:
[...]
Ik zou de lengte limiteren, en in mijn php aps heb ik een functie whitelistchars(level,string, cscustom).

Level 1: a..z A..Z
Level 2: level1 + 0..9
Level 3: level2 + cscustom
level *: *

Invoer: whitelistchars(1,"ab3gda","");
Invoer2: whitelistchars(3,"ab3g#$%da","$,%");
Uitvoer: abgda
Uitvoer2: ab3g$%da

Op die manier vergeet je het niet en dwing je jezelf na te denken bij elke var. Overigens is het wat overdreven maar uit ervaring weet ik dat heel veel mensen de SERVER vars en cookie var vergeten als het om security gaat. De urlparameters zijn gesneden koek maar het lijkt alsof het begrip client invoer nog niet helemaal is doorgedrongen mede vandaar de opmerking.
Maar wat is een geldige whitelist voor een user-agent? Wat mij betreft mogen daar ook best chinese tekens in zitten. Ik zie dan nog eerder wat in een black-list ( Control characters zijn immers niet echt nuttig in een user-agent ).

Lengte valideren zou ik ook alleen doen als je weet dat de functie waar je hem voor gebruikt een limitatie is. Voor zover ik weet is er voor sha1/md5 geen limitatie op lengte ( Niet voor zover ik zo snel in de documentatie zie ), en dus zou ik voor dit geval geen reden zien om daar dan op te filteren.
nogmaals als je later weer verder gaat coden en je wil bijv. de ua op gaan slaan in een db is een foutje snel gemaakt vandaar dat het goed werkt voor mij om het bij decleratie al te fixen. (Dit is natuurlijk voor elke iedereen anders).
Maar bij welke declaratie wil je het dan fixen. Het slaat nergens op om in je front-end al te gaan escapen ( misschien zelfs getarget op een bepaald RDBMS ) tegen SQL injectie. Misschien gebruik ik die input ook wel om ergens een PDF te genereren, dan moet ik op die plek eerst de string weer gaan parsen.

Escapen moet je op de plek doen waar je een context switch maakt die dat nodig hebt, en voor SQL injectie moet je dus in je data laag escapen.

Een functie die een session-id genereert heeft daar helemaal niks mee van doen, net zoals elke andere functie/class die niks met SQL te maken heeft.

Door dit soort dingen meteen bij binnenkomst in het script te doen, ben je het gewoon in de verkeerde context aan het doen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

10.15 User-Agent
The User-Agent request-header field contains information about the user agent originating the request. This is for statistical purposes, the tracing of protocol violations, and automated recognition of user agents for the sake of tailoring responses to avoid particular user agent limitations. Although it is not required, user agents should include this field with requests. The field can contain multiple product tokens (Section 3.7) and comments identifying the agent and any subproducts which form a significant part of the user agent. By convention, the product tokens are listed in order of their significance for identifying the application.

User-Agent = "User-Agent" ":" 1*( product | comment )
product = token ["/" product-version ]
product-version = token
comment = "(" *( ctext | comment ) ")"
ctext = <any TEXT excluding "(" and ")">
token = 1*<any CHAR except CTLs or tspecials>
tspecials = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
Dus token en tspecials waar de problemen naar je DB eventueel kunnen optreden kunnen gewoon weg.


--
Qua md5 en sha1 is er wel degelijk een imitatie, de uitvoer is 128 bits. Als je invoer onbeperkt is en je uitvoer beperkt dan weetje dat er collision op kan treden. Stel dat je het koppelt aan een ip en ik genereer een zelfde sessie met een ander IP kan ik alsnog die sessie overnemen. De uitvoerbaarheid van zo'n aanval is niet heel reeel maar op de langere termijn niet ondenkbaar. Waarom risico op de lange termijn nemen als je het simpel kan afvangen?


----
Over de context ben ik het met je eens dat het ook op een andere laag kan, ik doe het alleen liever gelijk want dan weet ik zeker dat het niet vergeten wordt. Echter gaat het hier niet alleen sql injectie maar ook dingen als xss, CSRF etc. Voor deze functie maakt het niks uit omdat die een hash aflevert, maar in het algemeen geldt dat je ze wel moet filteren en daarmee vind ik het een goede gewoonte om het altijd te doen.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 13:52:
[...]
Dus token en tspecials waar de problemen naar je DB eventueel kunnen optreden kunnen gewoon weg.
De definitie geeft inderdaad perfect weer dat het kansloos is om met een whitelist te werken. Er staat duidelijk dat een token een willekeurig character kan zijn behalve een ControlChar of een van de special chars. Dan is het toch niet slim om met een whitelist te werken. Die blacklist ligt immers vast, een whitelist zal een enorme lijst zijn die bijna alle unicode mogelijkheden bevat.
Qua md5 en sha1 is er wel degelijk een imitatie, de uitvoer is 128 bits. Als je invoer onbeperkt is en je uitvoer beperkt dan weetje dat er collision op kan treden. Stel dat je het koppelt aan een ip en ik genereer een zelfde sessie met een ander IP kan ik alsnog die sessie overnemen. De uitvoerbaarheid van zo'n aanval is niet heel reeel maar op de langere termijn niet ondenkbaar. Waarom risico op de lange termijn nemen als je het simpel kan afvangen?
Die koppeling aan IP adres moet je ook niet via het genereren van het session id doen. Die moet je gewoon als informatie aan de session hangen, en die kun je dan perfect valideren. Dat de uitvoer 128 bits is is ook niet interessant, want er is sowieso kans op een collision, maar dat hoeft voor de session-id generatie helemaal geen probleem te zijn.

De enige vereiste is dat het niet voorspelbaar is wat het session id is, want dan zou iemand een session over kunnen nemen door de session-id zelf te genereren. Dit vang je af door een random waarde te gebruiken. Echter zijn bijna alle random generatoren afhankelijk van de tijd, en dus ook weer te voorspellen. Dan kun je kiezen om een random generator te zoeken die onafhankelijk van de tijd is, en dus niet te voorspellen (Dat zal echter wel lastig zijn), of je kiest ervoor om ook nog een extra Secret ( Private-Key zeg maar ) te introduceren. Het idee van deze hashing algoritme is dat als er niet aan de output van de functie te achterhalen is hoeveel er aan de input veranderd is.
Over de context ben ik het met je eens dat het ook op een andere laag kan, ik doe het alleen liever gelijk want dan weet ik zeker dat het niet vergeten wordt. Echter gaat het hier niet alleen sql injectie maar ook dingen als xss, CSRF etc. Voor deze functie maakt het niks uit omdat die een hash aflevert, maar in het algemeen geldt dat je ze wel moet filteren en daarmee vind ik het een goede gewoonte om het altijd te doen.
Dan zijn we het toch niet helemaal eens, want mijn mening is juist dat je het op een andere laag moet doen. Als je het gelijk doet dan ben je verkeerd bezig. Als je alle input, bij binnenkomst, gaat escapen tegen bijvoorbeeld xss is dat nogal stom, want die input gebruik je misschien wel helemaal niet alleen voor output naar HTML. Als je het in een andere context output zul je dan eerst die escaping weer moeten verwijderen.

Escaping moet je altijd doen op het punt waar het nodig is, en niet eerder of later.

Bij input validatie is dat natuurlijk een ander punt. Als je verwacht dat je een getal binnen krijgt, dan moet je natuurlijk wel valideren of het ook daadwerkelijk een getal is, maar je moet niet in je front-end gaan escapen tegen dingen als XSS of SQL Injection.

[ Voor 4% gewijzigd door Woy op 03-12-2009 14:18 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Woy schreef op donderdag 03 december 2009 @ 14:15:
[...]

De definitie geeft inderdaad perfect weer dat het kansloos is om met een whitelist te werken. Er staat duidelijk dat een token een willekeurig character kan zijn behalve een ControlChar of een van de special chars. Dan is het toch niet slim om met een whitelist te werken. Die blacklist ligt immers vast, een whitelist zal een enorme lijst zijn die bijna alle unicode mogelijkheden bevat.
Voorbeeld van wanneer dit fout ging, een blacklist bevatte ' echter ` stond er niet op waardoor de app nog steeds kwetsbaar was voor sql-injectie. Dit had met een whitelist nooit voor kunnen komen. Impliciet autoriseer je met het blacklist idee alle ideeen uit de toekomst qua datasets etc plus alles wat je over het hoofd ziet.
Woy schreef op donderdag 03 december 2009 @ 14:15:

. Dat de uitvoer 128 bits is is ook niet interessant, want er is sowieso kans op een collision.
Dat is het wel want met een beperkte dataset is het moeilijker om collissions te krijgen zeker voor een 'gebroken' hash functie als md5 (voor de complete problematiek betreffende md5 moet je eens zoeken naar 'Benne de Weger' of gewoon md5 collissions TUe)


[...]
Woy schreef op donderdag 03 december 2009 @ 14:15:

Dan zijn we het toch niet helemaal eens, want mijn mening is juist dat je het op een andere laag moet doen. Als je het gelijk doet dan ben je verkeerd bezig. Als je alle input, bij binnenkomst, gaat escapen tegen bijvoorbeeld xss is dat nogal stom, want die input gebruik je misschien wel helemaal niet alleen voor output naar HTML. Als je het in een andere context output zul je dan eerst die escaping weer moeten verwijderen.

Escaping moet je altijd doen op het punt waar het nodig is, en niet eerder of later.
Over het algemeen weet ik waarvoor een variabele gaat dienen alvorens ik deze declareer. Als ik een functie voor opeens een 2e doel ga gebruiken is het ook logisch om opnieuw je filter regels te beredeneren. Kortom ik doe escape niet tegen xss ik modeleer de data naar de vorm welke ik wil dat het heeft. Als je dat zeker weet kan je veilig verder redeneren in je programma.

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 14:52:
[...]
Voorbeeld van wanneer dit fout ging, een blacklist bevatte ' echter ` stond er niet op waardoor de app nog steeds kwetsbaar was voor sql-injectie. Dit had met een whitelist nooit voor kunnen komen. Impliciet autoriseer je met het blacklist idee alle ideeen uit de toekomst qua datasets etc plus alles wat je over het hoofd ziet.
Door een whitelist sluit je echter veel te veel uit, zo zou jij bijvoorbeeld geen chinese browser toestaan. Hier begin je weer over SQL injection, maar het doel van die black-list zou niet moeten zijn om te beschermen tegen SQL injection, want dat is de verantwoordelijkheid van de data-laag. Het enige doel van die blacklist is het valideren of het een geldige user-agent is. En in een geldige user-agent mag best een ' of ` voorkomen. Ik zie geen enkele reden om die te gaan escapen voor bijvoorbeeld MySQL als ik hem in een hash functie gebruik.

Voor het escapen van een string in de data-laag ( als je het al zelf zou doen, en niet de daarvoor geleverde functies gebruikt ) zou je inderdaad een lijst met te escapen characters, die je uit de documentatie van het RDBMS kunt halen, gebruiken en escapen.

Ik wil mijn input in dit geval helemaal niet beperken omwille van het RDBMS, die heeft niet als taak om te bepalen wat er wel en niet in een string mag zitten. Die krijgt een string aangeleverd, en het is zijn taak om die in de database te zetten.
Dat is het wel want met een beperkte dataset is het moeilijker om collissions te krijgen zeker voor een 'gebroken' hash functie als md5 (voor de complete problematiek betreffende md5 moet je eens zoeken naar 'Benne de Weger' of gewoon md5 collissions TUe)
Maar een collision is helemaal geen belangrijk issue bij het genereren van een session-id. Er moet alleen even gecontroleerd worden of dat session-id al is uitgegeven. Als dat het geval is moet je gewoon een ander session-id genereren. Een session-id heeft naast het identificeren van een sessie immers totaal geen betekenis.

Een attacker heeft ook geen invloed op het genereren van een collission, want de hash is niet alleen afhankelijk van de user-input. Het idee is juist dat het afhankelijk is van een random waarde, alleen omdat die random waarde te voorspellen is omdat hij afhankelijk is van de tijd doe je daar nog een Secret bij.

Maar zelfs als iemand het voor elkaar krijgt om via zijn user-agent een collission te triggeren is dat geen probleem, immers word er gewoon gedecteerd dat dat session-id al uitgegeven is, en word er gewoon een nieuwe gegenereerd.

Je wil alleen niet dat een attacker het session-id kan voorspellen, en dat lukt niet, aangezien er een Secret component in de hash zit verwerkt.
Over het algemeen weet ik waarvoor een variabele gaat dienen alvorens ik deze declareer. Als ik een functie voor opeens een 2e doel ga gebruiken is het ook logisch om opnieuw je filter regels te beredeneren. Kortom ik doe escape niet tegen xss ik modeleer de data naar de vorm welke ik wil dat het heeft. Als je dat zeker weet kan je veilig verder redeneren in je programma.
Dan zit je de verantwoordelijkheid op de verkeerde plek te stoppen. Het is immers niet aan de front-end om te bepalen op welke manier de data opgeslagen word. Escaping voor SQL is RDBMS afhankelijk, dus je moet in je front-end al rekening gaan houden met welk RDBMS je hebt. Verder is de kans groot dat escaping tussen verschillende outputs niet gelijk hoeft te zijn.

Stel ik krijg een parameter x ( string ) binnen, en die wil ik zowel naar een PDF schrijven, als naar een database. Voor de database moet je bijvoorbeeld de quotes escapen, maar voor naar de PDF heb je weer andere keywords die je moet escapen. Dat kun je nooit in een variabele verenigen. Dus de enige plek waar je het juist kunt doen is op het moment dat je het naar het medium output.

In het geval van PDF is dat in je PDF writer class, in het geval van de database is dat in je data-laag.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Woy schreef op donderdag 03 december 2009 @ 15:15:
[...]

Door een whitelist sluit je echter veel te veel uit, zo zou jij bijvoorbeeld geen chinese browser toestaan.
Als het niet in de RFC staat niet nee.


Voor het escapen van een string in de data-laag ( als je het al zelf zou doen, en niet de daarvoor geleverde functies gebruikt ) zou je inderdaad een lijst met te escapen characters, die je uit de documentatie van het RDBMS kunt halen, gebruiken en escapen.

Ik wil mijn input in dit geval helemaal niet beperken omwille van het RDBMS, die heeft niet als taak om te bepalen wat er wel en niet in een string mag zitten. Die krijgt een string aangeleverd, en het is zijn taak om die in de database te zetten.
Woy schreef op donderdag 03 december 2009 @ 15:15:

probleem, immers word er gewoon gedecteerd dat dat session-id al uitgegeven is, en word er gewoon een nieuwe gegenereerd.
Dat zou idealiter wel moeten ja, maar ik zie het niet terug in het bovenstaande stukje code. Op basis van assumption dit soort dingen aanpakken is niet handig. Voor het session inderdaad minder relevant maar het md5 algoritme moet niet meer gebruikt worden.
Woy schreef op donderdag 03 december 2009 @ 15:15:

Dan zit je de verantwoordelijkheid op de verkeerde plek te stoppen. Het is immers niet aan de front-end om te bepalen op welke manier de data opgeslagen word. Escaping voor SQL is RDBMS afhankelijk, dus je moet in je front-end al rekening gaan houden met welk RDBMS je hebt. Verder is de kans groot dat escaping tussen verschillende outputs niet gelijk hoeft te zijn.
Als ik een integer nodig heb ik een integer nodig heb in de front zorg ik dat het echt een int is en niks anders. Als ik een User agent nodig heb in de front end dan zorg ik dat ik een User agent heb, een die volgens het RFC is gespecificeerd. Op het moment dat ik een ander doel heb voor de UA dan zorg ik dat het alleen dat doel kan dienen.
Woy schreef op donderdag 03 december 2009 @ 15:15:

Stel ik krijg een parameter x ( string ) binnen, en die wil ik zowel naar een PDF schrijven, als naar een database. Voor de database moet je bijvoorbeeld de quotes escapen, maar voor naar de PDF heb je weer andere keywords die je moet escapen. Dat kun je nooit in een variabele verenigen. Dus de enige plek waar je het juist kunt doen is op het moment dat je het naar het medium output.

In het geval van PDF is dat in je PDF writer class, in het geval van de database is dat in je data-laag.
Ja dan weet je van te voren dat je 1 variabele voor meerdere opties gaat gebruiken. Dan kan je er voor kiezen deze dubbel te declareren of om je datamodel aan te passen. Op het moment dat je dat laatste doet neem je gepaste maatregelen in je database classe.

Offtopic, lang geleden dat ik voor het laatst een discussie had op tweakers, desondanks interessant!

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 03 december 2009 @ 15:31:
[...]
Als het niet in de RFC staat niet nee.
Volgens de RFC zijn chinese user-agent strings gewoon legaal. Volgens mij staat niet gespecificeerd dat een browser string gelimiteerd is tot ascii.
Dat zou idealiter wel moeten ja, maar ik zie het niet terug in het bovenstaande stukje code. Op basis van assumption dit soort dingen aanpakken is niet handig.
Mijn punt is dat je met of zonder user-agent als hash component net zo veel kans op collisions hebt.
Voor het session inderdaad minder relevant maar het md5 algoritme moet niet meer gebruikt worden.
Dat is ook een beetje overtrokken. Het ligt er aan voor wat voor doeleinden je het wil gebruiken. Door zwakheden in MD5 is het inderdaad mogelijk om redelijk snel een collission te vinden met MD5, maar in dit geval, heb je niks aan een collission. Het is leuk dat je een string vind die dezelfde hash oplevert, maar met die string kun je niks. De Hash heeft immers geen waarde buiten het identificeren van de sessie. Dus als een attacker de hash al heeft, dan heeft het totaal geen meerwaarde om een collission te zoeken, de hash is immers resultaat van een (semi)random waarde.
Als ik een integer nodig heb ik een integer nodig heb in de front zorg ik dat het echt een int is en niks anders.
Dat zeg ik ook. Je moet in je front-end wel controleren of iets is wat je verwacht ( Dus als je een int verwacht controleren of het een int is, of controleren of het volgende de RFC een geldige user-agent is ), maar verdere filtering/escaping ten behoeven van encodering voor een ander systeem ( PDF, HTML, Database) moet je doen op de plek waar het hoort, en dat is op de plek dat je het daarheen schrijft.
Als ik een User agent nodig heb in de front end dan zorg ik dat ik een User agent heb, een die volgens het RFC is gespecificeerd. Op het moment dat ik een ander doel heb voor de UA dan zorg ik dat het alleen dat doel kan dienen.
Maar dat heeft dan nog niks met escaping tegen SQL injection te maken. In de RFC voor de UA staat immers niks beschreven over SQL ;)
Ja dan weet je van te voren dat je 1 variabele voor meerdere opties gaat gebruiken. Dan kan je er voor kiezen deze dubbel te declareren of om je datamodel aan te passen. Op het moment dat je dat laatste doet neem je gepaste maatregelen in je database classe.
Maar dan ga je je dus meerder keer je data dupliceren ten behoeve van andere systemen? Dat vind ik nogal gek.

Als ik een entiteit Boek heb, dan ga je toch niet de volgende class maken?
code:
1
2
3
4
5
6
class Boek{
    string PdfEscapedTitle;
    string MySqlEscapedTitle;
    string PostgreSqlEscapedTitle;
    string HtmlEscapedTitle;
}

Het is gewoon veel logischer om de escaping op de plek te doen die daar iets vanaf weet. Bij SQL Injectie is dat in de data laag, voor PDF is dat in de PDF writer, voor HTML/XSS injectie is dat bij het outputten naar je browser. Die plekken hebben immers de kennis en verantwoordelijkheid om dat te doen. Je front-end hoort helemaal niet te weten wat voor database systeem je hebt, of wat voor implementatie van een PDF writer je hebt.

Je gaat toch ook niet in je data laag escapen tegen XSS?

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 21-09 08:50
Woy schreef op donderdag 03 december 2009 @ 15:54:
Als ik een entiteit Boek heb, dan ga je toch niet de volgende class maken?
code:
1
2
3
4
5
6
class Boek{
    string PdfEscapedTitle;
    string MySqlEscapedTitle;
    string PostgreSqlEscapedTitle;
    string HtmlEscapedTitle;
}
Nee daar heb je een HashTable voor!

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
creator1988 schreef op donderdag 03 december 2009 @ 16:29:
[...]


Nee daar heb je een HashTable voor!
Dat is implementatie, en dus niet belangrijk in het stukje pseudo code. Maar wil je zeggen dat jij serieus meerdere keren dezelfde property ( Ongeacht of je het nou in een field, hashtable of een andere collectie stopt ) in een class gaat stoppen, alleen ten behoeve van encodering naar andere systemen toe?

Ik heb liever gewoon een class die er zo uit ziet
code:
1
2
3
class Boek{
    string Titel;
}

en dan een Insert Functie
code:
1
2
3
4
5
6
class MySqlBoekDao : IBoekDao
{
    void Insert( Boek b ){
        ....   mysql_real_escape_string(b.Titel)  ....
    }
}

Die class is immers verantwoordelijk voor het inserten van de data, en die weet hoe hij moet escapen voor dat RDBMS. De front-end is dan onafhankelijk welk RDBMS, en zelfs of er uberhaupt een RDBMS gebruikt word. Misschien wil je het wel in XML of een CSV file opslaan. Dan moet je immers weer compleet andere escaping toepassen. De storage is nou eenmaal geen verantwoordelijkheid van de front-end, en dus kan je in de front-end niet eens bepalen welke escaping je allemaal toe moet passen.

[ Voor 6% gewijzigd door Woy op 03-12-2009 16:42 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1