login + bruteforce protectie PDO

Door Jeroen VD, 9 jaar geleden, 25.036x bekeken

Er zijn hier aardig wat loginscripts te vinden, hier is er nog een. Wat maakt deze speciaal?
- gebruik gemaakt van PDO, dus OO geschikt. er is verder niet gebruik gemaakt van objecten, maar dat kun je zelf evt toevoegen.
- er zit een bruteforce-protectie in. laatste tijd nogal hot hier, maar tijdens het inloggen bekijkt dit script of er de laatste 5 minuten meer dan 3 keer is proberen in te loggen (instelbaar). zo ja, dan wordt die gebruiker geblokkeerd tot vijf minuten na de eerste poging.

de volgende tabellen moeten aanwezig zijn:
tabel 'users' met tenminste:
- 'user_id' (auto increment)
- 'username'
- 'password' (minimaal 64 varchar)

tabel 'loginfail' met tenminste:
- 'username'
- 'IP'
- 'dateAndTime' (datetime)

het wachtwoord is een eevoudige sha256 van de username + password. geen erg sterke beveiliging, maar in een user tabel komt vast meer gegevens voor die je evt hiervoor kunt gebruiken. dat is aan jezelf.
het inloggen levert een sessie op met het user_id en het IP adres

veel plezier ermee, alle commentaar is welkom!

Jeroen

Gesponsorde koppelingen

PHP script bestanden

  1. login.php
  2. neededtables.txt

 

Er zijn 21 reacties op 'Login bruteforce protectie pdo'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Wouter J
Wouter J
9 jaar geleden
 
Even wat puntjes op je HTML code:
- doctype is incompleet
- ik mis de verplichte <meta charset=utf-8> als eerste element in de head
- fieldset + legend horen in het form element

Tevens nog wat andere puntjes:
- ik zou van $message een array maken en die mooi in list items echoën
- SELECT username is nergens voor nodig, die weet je immers al
- ik ben geen SQL expert, maar is het niet zo dat de velden die je grouped je niet mag selecteren? Oftewel, je mag GROUP BY niet gebruiken om unieke dingen te selecteren

Ook zou ik een neededtables.txt bestand maken waarin je de SQL voor de tabellen zet, iets als:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE IF NOT EXISTS users
  (
    user_id int auto_increment PRIMARY KEY,
    username varchar(50) NOT NULL,
    password varchar(75) NOT NULL
  );
CREATE TABLE IF NOT EXISTS loginfail
  (
    username varchar(50) NOT NULL,
    IP int NOT NULL,
    dateAndTime datetime NOT NULL
  );
Victor -
Victor -
9 jaar geleden
 
0 +1 -0 -1
Op regel 84 zul je altijd op een getal van meer dan 0 uitkomen, dit heeft dus geen zin
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
if(count($tries) > 0)
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
@wouter
- doctype is incompleet
klopt, dat was maar even snel gemaakt. niet echt aan gedacht

- ik mis de verplichte <meta charset=utf-8> als eerste element in de head
ik ook. zal m toevoegen

- fieldset + legend horen in het form element
hmm, form is toch een onderdeel van het fieldset element, en toch niet andersom?


- ik zou van $message een array maken en die mooi in list items echoën
zou kunnen. het maakt hier niet uit, en op deze manier krijg je altijd maar 1 foutmelding, in plaats van een hele rij, en ziet dat er netter uit, vind ik.

- SELECT username is nergens voor nodig, die weet je immers al
volgends mij moet juist alles wat je grouped in de SELECt zitten (ook je volgende vraag), dus username en IP zal ik sowieso moeten selecteren, terwijl ik ze alletwee al heb... dat is waar. ik weet alleen niet hoe ik dat anders zou moeten doen.

- Ook zou ik een neededtables.txt bestand maken
zal ik doen.

@victor:
- Op regel 84 zul je altijd op een getal van meer dan 0 uitkomen, dit heeft dus geen zin
jawel. dit test simpelweg of er een resultaat is. als je de laatste vijf minuten minder dan 3 keer hebt geprobeerd in te loggen, of dat was langer dan vijf minuten geleden, zal mysql een lege set resultaten terugsturen, en na het fetchen is het dan een lege array, en zal een count() daarop 0 opleveren. is die wel gevuld, krijg je altijd 1, omdat het maar 1 resultaat is.
Wouter J
Wouter J
9 jaar geleden
 
1 +1 -0 -1
>> hmm, form is toch een onderdeel van het fieldset element, en toch niet andersom?

Volgens mij niet: http://www.w3.org/TR/html5/the-fieldset-element.html#the-fieldset-element

>> volgends mij moet juist alles wat je grouped in de SELECt zitten (ook je volgende vraag),
Zie ook dit: http://phptuts.nl/view/2/1/
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
Ja, form moet dus in de fieldset. Is aangepast.

Je moet alles groupen wat in de select voorkomt. Is een kleine nuance, maar ik zql morgen eens gaan spelen.
Synaps Framework
Synaps Framework
9 jaar geleden
 
0 +1 -0 -1
@Wouter, naar mijn weten is er niks mis met het doctype. Het kan immers gaan om HTML 5.

Daarnaast gaat het hier om de PHP code en niet het kleine formuliertje welke hij er bij plaatst zodat het 1 geheel is. Mensen zullen dit implementeren in hun website en niet de website om dit login form heen bouwen.

Komt bij mij over dat je zoveel mogelijk punten zoekt welke wellicht incorrect zijn.
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
synaps, het doctype heb ik allang aangepast. je ziet nu het goed.

hoemeer puntjes van kritiek, hoe liever. de form is dan misschien maar een bijkomstigheid, ik wil ook dat dat goed is. hoe zeikerig ook.
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
over de query: ik moet iets selecteren, maar alles heb ik al. dus heb ik nu zo min mogelijk.
Ibrahim A
Ibrahim A
9 jaar geleden
 
0 +1 -0 -1
Heel mooi script, mijn complimenten. Ik zal hem gaan gebruiken voor mijn site! Kunt u misschien ook een makkelijke check erbij maken om te zien of iemand al ingelogd is? (Voor speciale pagina's) Alvast bedankt!
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
Maak voor dit soort vragen liever een topic aan, maar bedankt voor het compliment. Die check: gewoon even boven aan de pagina bekjken of de sessie aanwezig is.
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
zoiets als dit boven aan je pagina:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_SESSION['user']) && $_SESSION['user_id'] == $_SERVER['REMOTE_ADDR'])
{

    //user is ingelogd, code die je wilt
}
else
{
    //user is niet ingelogd
}
?>
 - Diov  -
- Diov -
9 jaar geleden
 
0 +1 -0 -1
Hou er wel rekening mee dat je Cookies (Misschien ook sessie kan manipuleren).

Daarom zou je een extra tabel kunnen maken in je databank genaam 'sessions'.

Telkens als iemand inlogt plaats je daar ook de volgende gegevens: een id (auto increment), userid (het id van de gebruiker), eventueel een hash, ip, logintime.

Je plaats ook een sessie op de browser.

Hier de functie om te checken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
function checklogin() {
   if (mysql_num_rows(mysql_query("SELECT userid, `hash`, ip FROM `sessions` WHERE `userid` = '".mysql_real_escape_string($_SESSION['id'])."' AND `hash` = '".mysql_real_escape_string($_COOKIE['hash'])."' AND `ip` = '".mysql_real_escape_string($_SERVER['REMOTE_ADDR'])."'")))
   {
       $return  = TRUE;
   }
   else
   {
       $return = FALSE;
   }
return $return;
}


Op elke pagina kan je dan bovenaan volgende check uitvoeren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (checklogin()) {
    // * Gebruik is ingelogd *
} else {
    // * Gebruik is niet ingelogd *        
}


Dit is nog iets waarop je verder kan bazeren.
Voorbeeld, een admin kan sessies verwijderen uit de database waardoor de gebruiker uitgelogt wordt.

Via de logintime kan je kijken of de gebruiker langer of niet langer dan 15 minuten van pagina gewisseld heeft, zoniet --> uitloggen.

Hopelijk hebben jullie hier iets aan
Dem
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
de sessie is uniek voor elke bezoeker, een hacker kan met een tooltje de sessie overnemen. maar niet de inhoud. in deze sessie staat het ip van de ingelogde, die de hacker dus niet kan veranderen. vindt het veilig genoeg.
 - Diov  -
- Diov -
9 jaar geleden
 
0 +1 -0 -1
Het is maar een ideetje voor de andere mensen.
Wat ik aantoon dat het veiliger is zo.
David Bontenbal
David Bontenbal
9 jaar geleden
 
0 +1 -0 -1
Als ik het script met onderstaande code gebruik gebeurt er niks als ik inlog.

Krijg alleen inlogformulier te zien.

index.php



Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include 'config/db.php';
include 'functions/opendb.php';
include 'functions/checklogin.php';


if (isset($_SESSION['user']) && $_SESSION['user_id'] == $_SERVER['REMOTE_ADDR'])
{

    //user is ingelogd, code die je wilt
}
else
{

    // * Gebruik is niet ingelogd *  
?>
<form method="post" action="inloggen.php">
<fieldset>
<legend>log in</legend>

<label for="username">username</label><br>
<input type="text" name="username"><br>

<label for="password">password</label><br>
<input type="password" name="password"><br>

<input type="submit" name="login" value="login">
</fieldset>
</form>
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php    
}
include 'functions/closedb.php';
?>
Donny Wie weet
Donny Wie weet
9 jaar geleden
 
0 +1 -0 -1
2 vragen: waarom doet ie het bij niet? Ik heb al het standaard dat aangepast moet worden gedaan (database gegevens), de tabel aangemaakt, en een SHA256 generator gebruikt...

Daarnaast: ik kan onbeperkt login klikken, ik wordt niet geblokt...
Jeroen VD
Jeroen VD
9 jaar geleden
 
0 +1 -0 -1
nou dat is ook lekker vaag. ik weet het niet. als de tabellen kloppen (zie neededtables.txt), en je draait het script zonder aanpassingen moet hij het doen.

je kunt altijd op login klikken.... die vijf minuten wordt gekoppeld aan een gebruikersnaam en je IP. en van de twee weg, en je kunt onbeperkt brute forcen. maar ik hoop dat je doorhebt dat je zowiezo een gebruikersnaam nodig hebt. en onder een IP kom je niet uit. (oftewel als jij niets invuld en als een retard op login blijft drukken kun je dus 'onbeperkt inloggen')
Mees kluivers
mees kluivers
6 jaar geleden
 
0 +1 -0 -1
Bij
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
                $checkTries =
                    "SELECT
                        username
                    FROM
                        loginfail
                    WHERE
                        DateAndTime >= NOW() - INTERVAL :attemptsTime MINUTE
                    AND
                        username = :username    
                    GROUP BY
                        username, IP
                    HAVING
                        (COUNT(username) = :maxAttempts)";


Moet het dan niet dit zijn?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
               $checkTries =
                    "SELECT
                        username
                    FROM
                        loginfail
                    WHERE
                        DateAndTime >= NOW() - INTERVAL :attemptsTime MINUTE
                    AND
                        username = :username    
                    GROUP BY
                        username, IP
                    HAVING
                        (COUNT(username) >= :maxAttempts)";


dus
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
              HAVING
                        (COUNT(username) >= :maxAttempts)";


i.p.v.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
                    HAVING
                        (COUNT(username) = :maxAttempts)";
Koen Hollander
Koen Hollander
6 jaar geleden
 
Ik zie dat de hash niet enorm veilig is voor een productie applicatie. Ikzelf gebruik daarvoor blowfish
Tijn p
tijn p
6 jaar geleden
 
0 +1 -0 -1
hij blijft maar zeggen username password invalid. wat niet uitgelegd staat is: hoe krijg je nou een user in de database van mysql ik ga naar deze pagina:
http://www.xorbin.com/tools/sha256-hash-calculator

er staat ook niet of zowel de user als het password 256 moet zijn of alleen het password.

onder de keuzes van mysql staat sha1 maar nergens sha256....

is er zoals het aanmaken van de needtables.txt ook niet zoals als een makeuser.txt

dat zou geweldig zijn.
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Johan de wit
johan de wit
6 jaar geleden
 
0 +1 -0 -1
Dank je wel

Om te reageren heb je een account nodig en je moet ingelogd zijn.

Inhoudsopgave

  1. login.php
  2. neededtables.txt

Labels

Navigatie

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.