-----------------------------------------------------------------------
WAARSCHUWING - DIT SCRIPT IS VEROUDERD / NIET 100% VEILIG (MEER)
-----------------------------------------------------------------------
2014-10-29
Dit script (ondertussen meer dan 10 jaar oud!) valt eigenlijk in een aantal onderdelen uiteen, die eigenlijk afzonderlijk behandeld zouden moeten worden:
- communicatie met de database (database-laag)
- gebruikersbeheer (gebruikersbeheer/-backend)
- gebruik (en verwerking) van formulier(-data) (formuliersysteem)
- authenticatie van een gebruiker (authenticatie/beveiliging)
- rechtenbeheer van gebruikers (rechtenbeheer/-backend)
- het combineren van bestanden die samen een "pagina" vormen (templatesysteem of equivalent)
In dit script zijn er veel aannames gedaan over hoe je webpagina's in elkaar zitten, dit maakt het script waarschijnlijk minder geschikt om (naadloos) te integreren in je eigen code. Dit neemt niet weg dat je de principes kunt gebruiken om delen van je website af te schermen.
De crux van dit geheel is het gebruik van sessies. Sessies stellen je, net als cookies maar dan op een "veilige(re)" manier, in staat om informatie te onthouden tussen verschillende pagina's van een website. Een sessie kan dus bijvoorbeeld onthouden dat je op een zeker moment een juiste gebruikersnaam/wachtwoord-combinatie hebt ingevoerd die jou (hopelijk) identificeert als de bijbehorende gebruiker.
Een tweetal dingen uit het onderstaande script zou ik (structureel gezien) nou waarschijnlijk anders aanpakken:
1. de opslag van rechten/privileges in de sessie
Het script werkt zo dat de rechten die iemand heeft (hier $_SESSION['slevel']) opgeslagen worden in de sessie zelf.
Dit heeft zowel voor- als nadelen. Een voordeel is dat je niet elke page-access de rechten hoeft op te halen uit de database (dit scheelt dus een of meer queries). Een nadeel is dat deze rechten van kracht blijven zolang de sessie van
de gebruiker bestaat, ook al pas je ondertussen de rechten aan in de database. De enige manier om iemand zijn "sessie rechten" in te trekken is deze gebruiker geforceerd (via code of anderszins) uit te laten loggen. Een mogelijk beter
alternatief is dat je in je sessie geen rechten opslaat (maar enkel een gebruikers-id) maar dat je deze rechten elke page-access opnieuw berekent en bijvoorbeeld opslaat in een user-object. De user-klasse zou je vervolgens kunnen voorzien van methoden waarmee je bepaalt of een gebruiker een bepaalde handeling mag verrichten. Hiermee bewerkstellig je waarschijnlijk een betere "scheiding van verantwoordelijkheden": je sessie onthoudt (enkel) wie je bent, met het (elke page-access opnieuw geconstrueerde) user object bepaald je verdere authenticatie-vraagstukken (if ($user->hasRights($array_met_te_controleren_verplichte_rechten)) { ... } o.i.d.).
2. het "doorloggen"
Indien in het onderstaande script de sessie is verlopen (door timeout of wat dan ook) en je hebt aangegeven dat je je login wilt onthouden, dan zal worden getracht om de sessie on-the-fly door te starten. Hierbij wordt de pagina wel ververst. Als je op dat moment dus bijvoorbeeld een lange post aan het schrijven was dan gaat deze informatie verloren. Het zou dus beter zijn om dus niet tussendoor te redirecten. Als je er voor zorgt dat de heropbouw van de sessie plaatsvindt voordat je bijvoorbeeld controleert of iemand toegang heeft tot een pagina (dus ook -als we voortborduren op het gebruik van een user class-
voordat we het user object opnieuw bouwen (wat op zijn beurt weer zijn informatie uit de sessie onttrekt)), dan zou deze doorstart geruisloos kunnen plaatsvinden.
Je kunt het onderstaande script wel gebruiken om enigszins vertrouwd te raken met de materie, maar echt veilig is deze niet meer. Wel zou dit script eenvoudig veilig(er) gemaakt kunnen worden, maar het is beter om een iets andere opzet te hanteren wanneer je dit soort functionaliteit wilt. Je zou daarvoor dit script in combinatie met bovenstaande notities als leidraad kunnen gebruiken om zelf iets te bouwen.
EINDE WAARSCHUWING / EXTRA NOTITIES
-----------------------------------------------------------------------
Inleiding:
Met dit script kun je members met een gebruikersnaam en wachtwoord (afhankelijk
van het 'gebruikersniveau' of user level) toegang geven tot bepaalde delen van
je website, en anderen de toegang ontzeggen. Met behulp van een sessie (sessie-
variabelen) bepalen we tot welke delen van de website gebruikers toegang
hebben.
HOE je gebruikers deze rechten geeft en wat deze rechten inhouden is een ander
verhaal. Dit script beschrijft alleen het beveiligingsmechanisme.
Vereisten / aannames:
* De webmaster heeft de beschikking over een MySQL database waarin onder andere
gebruikersnaam, (versleuteld) wachtwoord en gebruikersniveau staan.
LET EROP dat het veld 'pass' tenminste 32 karakters lang dient te zijn, in
verband met gehashde passwords.
* sessies moeten ondersteund worden door de webserver
* Enige kennis van sessies, php functies (trim, md5, strcmp), binair tellen
(bitwise comparator)
Dit script is door mij al enige tijd in gebruik, en tot dusver heb ik nog geen
problemen ondervonden.
Mocht je echter problemen ondervinden (of gaten in de beveiliging ontdekken
die ik over het hoofd heb gezien ;)) mail of reply gerust.
Probeer (als iets niet werkt) eerst zelf uit te vogelen waarom iets niet werkt,
daar leer je echt het meeste van.
Lees ook eerst alles goed door; in de scripts zelf staat voldoende info om
vooruit te komen.
Bestanden:
- connect.php
In dit bestand wordt een connectie gemaakt naar je MySQL-databaseserver,
en selecteer je je eigen database.
- een login-script (login.php)
Hier type je je gebruikersnaam en wachtwoord in. In de database (of een file)
wordt gecontroleerd of je een bekende gebruiker bent. Als dit het geval is en
je wachtwoord klopt, worden enkele sessie-variabelen geïnitialiseerd en
ben je ingelogd. Vervolgens heb je toegang tot bepaalde member-only delen van
de site.
Hier kun je tevens aangeven of je login onthouden moet worden (op de machine
waar je mee inlogt).
Als je dit wilt, zal er een cookie worden aangemaakt en wordt in de database
bijgehouden onder welk IP-nummer je bent ingelogd. Het onthouden van je login
zal dus NIET werken op machines die een dynamisch (internet-)IP-nummer hebben.
Mijn script is zo gemaakt, dat wanneer je een bepaalde tijd niets
uitvoert, je op een gegeven moment weer uitgelogd bent (timeout) - deze "idle
time" kun je naar eigen smaak aanpassen.
- een logout-script (logout.php)
Hier wordt je sessie gedestroyed en wordt het sessie array leeggemaakt;
oftewel alle sessie gegevens worden verwijderd.
Wanneer er een cookie was geset die je login onthield, word deze hier
gecleared.
- een sessie-script (session.php)
Dit script dien je overal te includen waar je je pagina wilt beveiligen
(dus include("session.php"); of require("session.php"); - zie ook
voorbeeld.php) In deze include wordt gekeken of je idle-time is overschreden
en naar aanleiding daarvan worden acties uitgevoerd.
Als je nog niet bent ingelogd, maar bij een eerder bezoek hebt aangegeven dat
je login onthouden moest worden (en wanneer je nog steeds hetzelfde IP-nummer
als toen had) zal je sessie automatisch opnieuw opgestart te worden - je
wordt dan automatisch ingelogd.
- een voorbeeld-pagina (voorbeeld.php)
Hier worden (afhankelijk van het gebruikersniveau van een ingelogd persoon)
bepaalde delen van een pagina al dan niet zichtbaar gemaakt.
MySQL database tabel:
CREATE TABLE users (
id int(4) NOT NULL auto_increment,
name varchar(20) BINARY NOT NULL default '',
pass varchar(32) BINARY NOT NULL default '',
level int(10) NOT NULL default '0',
# v1.2 extra functionaliteit voor ingelogd blijven (volgende regel)
last_ip varchar(15) default NULL,
UNIQUE KEY id (id)
) TYPE=MyISAM;
CREATE TABLE users (
id int(4) NOT NULL auto_increment,
name varchar(20) BINARY NOT NULL default '',
pass varchar(32) BINARY NOT NULL default '',
level int(10) NOT NULL default '0',
# v1.2 extra functionaliteit voor ingelogd blijven (volgende regel)
last_ip varchar(15) default NULL,
) TYPE=MyISAM;
Uitbreiding:
Vanaf versie 1.2 is het mogelijk om je login te 'onthouden' door middel van het
setten van een cookie. Hierin staan de username en het encrypted wachtwoord van
een gebruiker opgeslagen. Om ervoor te zorgen dat mensen niet met een gestolen
cookie in kunnen loggen met de gegevens uit het cookie, wordt in de database
het IP bijgehouden van de machine van de persoon die het laatst succesvol is
ingelogd.
In de verschillende pagina's van het script zal aangegeven worden welke dingen
je moet toevoegen voor de gebruikmaking van deze extra functionaliteit.