Gisteren kwam ik een presentatie tegen van Ilia Alshanetsky over beveiliging in PHP. Daar kwamen een aantal punten in voor die ik graag met jullie wil delen en benieuwd ben naar jullie mening/aanpak.

Punt 1: Session Fixation
Session fixation is een manier om een sessie te stelen waarbij de aanvaller vooraf weet welk session id het slachtoffer krijgt. (Dus niet zoals bij session hijacking waarbij het session id achteraf gestolen wordt.) Dit is toe te passen met bijvoorbeeld een link als:
jouw.bank.com/?PHPSESSID=foobar
Als het slachtoffer nu op de link klikt denkt de website dat het sessie id foobar is en gaat hier alle gegevens aan koppelen, de aanvaller kan nu simpelweg dat sessie id ook gebruiken.
De oplossing die hierbij gegeven wordt is door simpelweg na het inloggen een nieuw sessie id toe te wijzen waardoor de aanvaller geen kans meer heeft:

<?php
session_start();
// some login code
if ($login_ok) { // user logging in
session_regenerate_id(); // make new session id
?>


Punt 2: Session Hijacking
Een veel toegepaste techniek om [google]session hijacking[/google] (en ook helpt om session fixation) te voorkomen is een sessie koppelen aan een gebruiker. Maar hoe kan je nu een sessie aan een gebruiker koppelen? Een veelgebruikte manier daarvoor is om de sessie aan het IP adres van de gebruiker te koppelen, maar dit heeft een paar nadelen waaronder:
- Er kunnen meerdere mensen met het zelfde ip adres zijn (denk aan thuis- of sommige bedrijfsnetwerken).
- Een IP adres kan vaak wisselen.
- Een IP adres is te spoofen.
In de presentatie wordt ook een voorbeeld met een alternatief gegeven voor het koppelen van een sessie aan een ip adres, namelijk het koppelen aan de browser signature:

<?php
session_start();
$chk = @md5(
$_SERVER['HTTP_ACCEPT_CHARSET'] .
$_SERVER['HTTP_ACCEPT_ENCODING'] .
$_SERVER['HTTP_ACCEPT_LANGUAGE'] .
$_SERVER['HTTP_USER_AGENT']);
if (empty($_SESSION))
$_SESSION['key'] = $chk;
else if ($_SESSION['key'] != $chk)
session_destroy();
?>

Ook dit is niet helemaal water dicht omdat het vaker voor kan komen en door de gebruiker aan te passen is. Maar misschien is het een idee om ook nog het IP adres in de md5-hash mee te nemen?

Ik hoop dat iemand hier wat aan heeft of misschien zelfs wel andere manieren heeft om deze problemen te voorkomen/beveiligen.
Ik vind het wel interessant ja, dit wist ik nog niet.. Maar hoe ik daar mee om ga:

Er wordt niet Alleen op sessie-id gecontroleerd. Inderdaad gebruik ik de browser signature al in m'n login. Daarnaast wordt in de sessie het userid opgeslagen, samen met een unieke hash (combinatie van een paar dingen met de microtijd)

In de database sla ik die unieke hash op, samen met het userid, de browsergegevens en het ip-adres. Neemt iemand met een ander ip de sessie over, dan wordt dat geblokkeerd, wordt er met een andere browser (de signature hiervan) gekeken, dan wordt dat ook geblokkeerd. Daarnaast, pas je het ID aan dan wordt ook dat geblokkeerd.

In principe is het systeem dus voor beide hacking methoden wel goed beveiligd.


Wel bedankt voor het delen van de informatie
Interessant topic, bedankt voor de info inderdaad! Ik zal het van het weekend nog eens goed doorlezen :-)
Als een gebruiker bij mij inlogd krijg hij/zij te maken met de volgende zaken:
Anti-bruteforce, na 3 foutieve inlogpogingen word de toegang voor 15 minuten geblokkeerd. Hij/zij kan daarna pas weer een inlogpoging doen. Stopt de gebruiker na 2 foutieve inlogpogingen dan blijven deze 15 minuten staan.

Als het inloggen lukt dan wordt er een 50 tekens lange random code gegenereerd. Als de bezoeker gekozen heeft voor een cookie dan wordt deze direct geplaatst. Heeft de bezoeker gekozen voor een sessie dan wordt het sessie-id opnieuw gegenereerd en wordt de sessie geplaatst. De cookie/sessie wordt aan het IP, de host en de useragent gekoppeld om hijacking te voorkomen. Kort gezegd wordt er dus een gelockte cookie/sessie geplaatst welke geen gevoelige gebruikers-info bevat.

Alle wachtwoorden worden gehashed met een instelbaar algoritme, ikzelf heb sha512. Ik gebruik een salt welke minimaal 6 tekens lang is.
Het klinkt alsof SESSION-fixation puur gebaseerd is op PHPSESSID in de REQUEST-array. Als je die kan negeren, ben je er dan niet gewoon vanaf? (m.a.w. alleen PHPSESSID in cookies toelaten, niet GET of POST)

SESSION-hjiacking kan je van buiten het netwerk voorkomen door inderdaad die fingerprint in combinatie met het ip-adres. Die laatste is lastig te vervalsen volgens mij. Vertrouw niet op X_FORWARDED of varianten, want juist die zijn heel gemakkelijk te vervalsen. Als je daarop checkt, controleer dan ook nog op REMOTE_ADDR of die niet geblokkeerd is. Van die get_ip() functies die mensen schrijven om 1 van de opties te selecteren zijn dan ook eigenlijk meer een verslechtering dan een verbetering van de veiligheid.

Ik denk niet dat je session-hjiacking vanuit het netwerk kan tegengaan. De persoon die dan aan het hacken is is ook in de positie om al het verkeer op het netwerk af te luisteren (met bijvoorbeeld WireShark) en kan gemakkelijk achter de cookies, en alle andere headers komen. Daarnaast heeft hij voor de server van de website hetzelfde adres. Misschien dat een https-verbinding het wat moeilijker maakt, maar dan nog is hij de 'man in the middle' en kan hij ook daarvan de key achterhalen. Een verbinding zoals SSH met public/private key is dan misschien nog een veilige oplossing omdat daar de key niet over het netwerk wordt verzonden. Ik denk dat die verbindingen niet zomaar af te luisteren en/of te manipuleren zijn. Maar aangezien dat niet haalbaar is met simpel HTTP en normale gebruikers, denk ik niet dat het mogelijk is om dit soort hacken vanaf de server tegen te gaan.


Wat ikzelf eerder interessant vind is hoe ver wil je gaan? Als iemand iedere dag van ip-adres wisselt, dan is lang ingelogd blijven & controleren op IP niet mogelijk. Kies je dan voor de extra veiligheid van een ip-gebonden sessie, of voor het gebruiksvriendelijke 'ingelogd blijven' van de gebruiker. Voor betaal-sites en privacy-gevoelige sites is dit een makkelijke vraag, maar voor een forum zou ik persoonlijk kiezen voor de meest gebruiksvriendelijke oplossing.

ik bedenk me net: bij iedere request een nieuw 'id', een soort van request-token opslaan is ook een oplossing. Op die manier kunnen er niet 2 personen op 1 account tegelijk bezig zijn. Nadeel is echter - en dit is een groot nadeel - dat je geen 2 browsers meer kan openen. Zou je in browser a op een link klikken, dan is de cookie met de token in browser b niet meer geldig. Voordeel is dat wanneer iemand aan bladeren is, en een hacker neemt de sessie over, de hacker (en de gebruiker) direct uitgelogd zijn zodra de gebruiker weer op een link drukt (ervan uitgaande dat de hacker de laatste pagina heeft aangeroepen en de laatste token dus in z'n bezit heeft) want de token van de gebruiker is dan al ongeldig verklaard. Token ongeldig -> sessie ongeldig -> uitgelogd.
Jelmer
Het klinkt alsof SESSION-fixation puur gebaseerd is op PHPSESSID in de REQUEST-array. Als je die kan negeren, ben je er dan niet gewoon vanaf? (m.a.w. alleen PHPSESSID in cookies toelaten, niet GET of POST)

Hoeft niet natuurlijk, als het mogelijk is om javascript te injecteren in een site kan je ook een cookie plaatsen om SESSION-fixation toe te passen (al is hier dus al een extra lek voor nodig).

Jelmer
Wat ikzelf eerder interessant vind is hoe ver wil je gaan?

Dat is een interessante vraag die ook al vaker in andere toppics voor bij is gekomen zeker als het gaat om een sessie aan een IP te binden.
Met name om deze reden vond ik het dus een aardig idee om naar de browser signature te kijken zoals in mijn eerste toppic het 2e code voorbeeld. Hierdoor hou je toch nog een stukje veiligheid over zonder aan het IP te koppelen.
Bij mijn inlogsysteem kan maximaal 1 iemand per account ingelogd zijn, ook dit zie ik meer als een voor- dan nadeel.

Ik zou toch zo ver gaan om de sessie/cookie aan het IP te koppelen, 1x per dag opnieuw inloggen is immers een kleine moeite en zorgt toch voor een relatief groot beveiligingsverschil.
1* per dag inloggen is niet erg. Maar als je op een school zit met meerdere accespoints die geregeld uitvallen en extern ook meerdere ip adressen hebben is het minder fijn.
Het gaat er dus echt wel om wat wel en niet nodig is.
Ivo van B. schreef op 09.03.2008 21:23
Bij mijn inlogsysteem kan maximaal 1 iemand per account ingelogd zijn


Hoe controleer je of je met 1 of meerdere personen op 1 account te maken hebt? M.a.w. wat scheidt de personen van elkaar?

Boaz schreef op 09.03.2008 21:12

Dat is een interessante vraag die ook al vaker in andere toppics voor bij is gekomen zeker als het gaat om een sessie aan een IP te binden.
Met name om deze reden vond ik het dus een aardig idee om naar de browser signature te kijken zoals in mijn eerste toppic het 2e code voorbeeld. Hierdoor hou je toch nog een stukje veiligheid over zonder aan het IP te koppelen.


Eigenlijk zou iemand eens moeten testen welke headers er allemaal verzonden worden, welke eigenschappen hoe uniek zijn. Volgens mij valt dit toch tegen, al is het wel effectief wanneer iemand het niet verwacht (amerikaanse hacker die nederlander probeert te hacken weet niet waarom het mislukt)
@ Jelmer
Elke keer als er eimand inglogd worden de huidige inloggegevens overschreven.
Maar daar voorkom je SESSION-hjiacking nog niet mee. Je weet nooit zeker hoeveel mensen er van die ene sessie gebruik maken.

Reageren