Welkom, Gast. Je bent niet ingelogd.

Echt veilig loginsysteem

Door Syncie op 25 Dec 2006, 01:06

- VEROUDERD, KAN HEEL GOED DIKKE ONZIN IN STAAN!!! -

Hey
Na hier 2 tutorials gelezen te hebben kon ik het niet laten om mijn tutorial hier te posten. Hier gebruik ik cookies maar sessies kunnen ook!

1: Wat heb je nodig
Een server die PHP en een SQL database heeft.
Een SSL optie.
Een databaseclass

2: De code & uitleg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php
$form = \'<form method=\"post\" action=\"\' . htmlentities($_SERVER[\'PHP_SELF\'], ENT_QUOTES) . \'\">
    <table border=\"0\" cellpadding=\"2\">
        <tr><td colspan=\"2\" style=\"font-weight:bold; text-align:center\">Inloggen</td></tr>
        <tr><td style=\"font-weight:bold;\">Gebruikersnaam:</td><td><input type=\"text\" name=\"username\" /></td></tr>
        <tr><td style=\"font-weight:bold;\">Wachtwoord:</td><td><input type=\"password\" name=\"password\" /></td></tr>
        <tr><td colspan=\"2\" style=\"margin:0px auto;><input type=\"submit\" value=\"Login\" /> <input type=\"reset\" value=\"Wis invoer\" />/td></tr>
    </table>
</form>\';
// Het formuliertje

if($_SERVER[\'REQUEST_METHOD\'] == \'POST\'){
// Hiermee kijken we of het formulier gepost is.

    sleep(1);
    // Vertraag het inloggen altijd    .

    $query_getLogintries     =    $db->query(\"SELECT logintries, tillTimestamp FROM logintries WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
    $num_getLogintries        =    $db->numRows($query_getLogintries);
    // Kijk of er foutieve inlogpogingen zijn geweest en tel ze.
    
    if($num_getLogintries > 0){
        // Is er foutief ingelogd?
        
        $logintries = $db->fetchAssoc($query_getLogintries);
        // Haal het aantal loginpogingen op.
        
        if($logintries[\'logintries\'] == 3){
            // Als er 3 mislukte inlogpogingen izjn
            
            if($logintries[\'tillTimestamp\'] < time()){
                // Als de 15 minuten voorbij zijn
                
                $db->query(\"DELETE FROM logintries WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
                // Verwijder de 3 mislukte inlogpogingen omdat de 15 minuten voorbij zijn.
                
            }else{
                
                die(\'Je hebt het maximaal aantal loginpogingen overscheren, je mag voor 15 minuten niet meer inloggen.\');
                // Sterf met het bericht.
                
            }
            
        }
        
    }
    
    if(empty($_POST[\'username\']) || empty($_POST[\'password\'])){
        // Even kijken of alles netjes is ingevuld.
        
        $error = \'<b style=\"color:#FF0000\">De volgende fouten zijn opgetreden:</b>
        <br />\';
        
        if(empty($_POST[\'username\'])){
            
            $error .= \'Het veld gebruikersnaam.
            <br />\';
            
        }
        
        if(empty($_POST[\'password\'])){
            
            $error .= \'Het veld wachtwoord
            <br />\';
            
        }
        
        $error . = \'<br />
        Probeer het opnieuw:
        <br />
        \' . $form;
        // Het formulier is niet netjes ingevuld dus we laten de fout(en) zien.
        
    }else{
        
        $username    =    $secure->safeDB($_POST[\'username\']);
        $password    =    $secure->hash($_POST[\'password\']);
        // De maken de gebruikersnaam veilig en het wachtwoord hashen we.
        
        $query    =    $db->query(\"SELECT password FROM members WHERE username = \'\" . $username . \"\'\");
        $num    =    $db->numRows($query);
        // Haal de rij op met die gebruikersnaam en tel het aantal resultaten.
        
        if($num == 0){
            // Er zijn 0 rijen dus de gebruikersnaam bestaat niet.
            
            $result = \'FAIL:username\';
            
        }else{
            
            $fetch = $db->fetchAssoc($query);
            // Haal het wachtwoord op om het te vergelijken met de input van de gebruiker.
            
            if($fetch[\'password\'] == $password){
                // Vergelijk de wachtwoorden met elkaar.
                
                $hash = sha1($username.$password.time().rand(1000000, 999999));
                /*
                Hier maken we de hash:
                    1. Gebruikersnaam
                    2. Gehashde vorm van het wachtwoord.
                    3. De timestamp
                    4. Een random getal van 6 cijfers.
                */
                
                $db->query(\"INSERT INTO hashes(username, hash, userip) VALUES (\'\" . $username . \"\', \'\" . $hash . \"\', \'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\')\");
                // Sla de gebruikersnaam, hash en het IP op in de databaase.
                
                setcookie(\'hash\', $hash, time()+3600*24*365);
                // Plaats een cookie met de naam hash die de inhoud van $hash heeft en een jaar moet bestaan.
                
                $result = \'OK:loggedin\';
                
            }else{
                
                $result = \'FAIL:password\';
                
            }
            
        }
        
        $status = explode(\':\', $result);
        // Explode het resultaat.
        
        if($status[0] == \'FAIL\'){
            // Als het inloggen mislukt is
            
            if($num_getLogintries > 0){
                // Als er al eens foutief is ingelogd.
                
                if($logintries[\'logintries\'] == 2){
                    // Als er al 2 keer iets fout is gegaan bij het inloggen
                    
                    $db->query(\"UPDATE logintries SET logintries = \'3\', tillTimestap=\'\" . time()+60*15 . \"\' WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
                    // Maak  het aantla loginpogingen 3 en maak een timestamp van een kwartier later
                    
                }else{
                    
                    $db->query(\"UPDATE logintries SET logintries = logintries+1 WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
                    // Tel 1 op bij het aantal foutieve inlogpogingen
                    
                }
                
            }else{
                
                $db->query(\"INSERT INTO logintries(logintries, tillTimestamp) VALUES (\'1\', \'\')\");
                // Sla 1 foutieve loginpoging op.
                
            }
            
            echo \'Het inloggen is mislukt.\'
                        
        }else{
            
            $db->query(\"DELETE FROM logintries WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
            // Er is succesvol ingelogd dus alle foutive pogingen kunnen weg.
            
            echo \'Ingelogd\';
            
        }
        
    }
    
}else{
    
    echo $form;
    // Het formulier is niet gepost dus laat het zien.
    
}
?>

Het bestand om te kijken of iemand ingelogd is:
Hier schrijven we gewoon een functie voor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
function isLoggedin(){
    
    if(isset($_COOKIE[\'hash\'])){ // Bestaat de cookie?
        
        $query    =    $db->query(\"SELECT hash FROM hashes WHERE userip=\'\" . $_SERVER[\'REMOTE_ADDR\'] . \"\'\");
        $num    =    $db->numRows($query);
        // We halen de hash op waar het ip gelijk is aan het ip van de bezoeker en tellen de resultaten.
                
        if($num == 0){
            // We vinden niks maar er bestaat wel een cookie dus die verwijderen we ook gelijk.
            
            setcookie(\'hash\', \'\', time()-3600*24*365);
            // We pakken de cookie hash en verwijderen hem.
            
            return false;
            // De cookie bestaat maar de hash is nergens te vinden dus deze persoon is niet ingelogd.
            
        }else{
            
            $fetch = $db->fetchAssoc($query);
            // We halen de hash op om die te vergelijken met die in de cookie.
            
            if($_COOKIE[\'hash\'] == $fetch[\'hash\']){
                // We vergelijken de hashes
                
                return true;
                // De hash klopt. en het ip klopt, dus deze persoon is ingelogd.
                
            }else{
                
                setcookie(\'hash\', \'\', time()-3600*24*365);
                // We pakken de cookie hash en verwijderen hem.
                
                return false;
                // De hash klopt niet maar het IP wel dus we verwijderen de cookie.
                
            }
            
        }
        
    }else{
        
        return false;
        // De cookie bestaat niet dus deze persoon is niet ingelogd.
        
    }
    
}
?>

3: Als laatste moet je doen:
Op pagina\'s kijk je of de gebruiker is ingelogd en als dit zo is dat maak je een nieuwe hash dus de timestamp verandert en het random getal verandert.

4: Wat is hier zo veilig aan:
1. We gebruiken SSL dus er kan niet zomaar informatie van het verzonden formulier onderschept worden.
2. We vertragen het inloggen altijd met 1 seconde waardoor het dus altijd langer dan 1 seconde duurt om in te loggen.
3. De zorgen dat je maximaal 3x per kwartier kan proberen in te loggen.
4. We maken een hash die bijna niet na te maken is waardoor de cookie bijna niet na te maken is.
5. We kijken ook wie de echte \"eigenaar\" van de cookie is via het IP dus kan die cookie ook niet gestolen worden.

De opbouw:
We maken een hash en die slaan we op in de DB samen met het ip waarop de hash gemaakt is, updaten deze bij elk bezoek zodat het nog moeilijker is om te jatten.
--------------------------------------------

De SQL kan je zelf wel verzinnen hoop ik.

Commentaar is altijd welkom.

PS: Niet getest dus bugjes kunnen voorkomen, deze code is niet om te kopieren en te plakken maar om er wat van te leren!

Maarten
Geplaatst op: 07 Feb 2007, 13:57

good tut

[Laatst bewerkt door Gabber4life op woensdag 7 februari 2007, om 13:58]
Syncie
Geplaatst op: 26 Dec 2006, 15:46

Wouser schreef:

waarom gebruik je trouwens $status = FAILassword
waarna je vervolgens de explode functie gebruikt @ : waarna je vervolgens weer $status[0] gebruikt maar niet $status[1] wat de inhoud password heeft?

In men class doe ik dat ook maar hier vond ik dat niet nodig... Tis om van te leren en niet te kopieren en plakken....

Wouser
Cadeau'tjes :r
Geplaatst op: 26 Dec 2006, 14:41

waarom gebruik je trouwens $status = FAILassword
waarna je vervolgens de explode functie gebruikt @ : waarna je vervolgens weer $status[0] gebruikt maar niet $status[1] wat de inhoud password heeft?

Xikeon
Geplaatst op: 26 Dec 2006, 09:44

Hij had eerst een commentaar gegeven van:
\" Saven is pwnt\"
ofzo. Die is verwijderd en weet verder niet of die er waarschuwing voor heeft gehad ofzo...

Syncie
Geplaatst op: 25 Dec 2006, 21:22

Remy schreef:

omfg saven lijer... jij kan ook nergens tegen hé, noep... ik ben hier weg idioot... :\')

Waar slaat dit dan op :s ....
Moet jij niet lekker buiten gaan spelen?

[Laatst bewerkt door Syncie op maandag 25 december 2006, om 21:25]
Syncie
Geplaatst op: 25 Dec 2006, 14:46

iisys schreef:

[...]
Mm ben niet zo bekend met SSL, zal me er is wat in verdiepen

Nhee, ik heb het over --> . \'\' <-- achter echo $form. Dat is zinloos, dus vraag ik je: waarom staat dat daar?


Die .\'\' is idd nutteloos kan gewoon $form; zijn waarschijnlijk niet opgelet en automatisch getypt ofso Edit ik wel ff

SSL = Secure Sockets Layer

Als je dit doorleest weet je er een stuk meer van: Klik

[Laatst bewerkt door Syncie op maandag 25 december 2006, om 14:49]
iisys
Hmhm, indeed. whtvr.
moderator
Geplaatst op: 25 Dec 2006, 14:25

Syncie schreef:

[...]
SSL zit in je server https://www.jesite.nl/inloggen/ zoiets bijvoorbeeld.

Line 71: Tjek de vorige regels. Die maken het laatste deel van de foutmelding en laten hem zien, zo kan de gebruiker direct weer een inlogpoging doen ipv terug te gaan of op vorige te klikken.


Mm ben niet zo bekend met SSL, zal me er is wat in verdiepen

Nhee, ik heb het over -->Â Â Â Â . \'\'Â Â Â Â Â <-- achter echo $form. Dat is zinloos, dus vraag ik je: waarom staat dat daar?

[Laatst bewerkt door iisys op maandag 25 december 2006, om 14:25]
Syncie
Geplaatst op: 25 Dec 2006, 14:21

iisys schreef:

Mm misschien dat ik het over t hoofd zie, maar waar zit het SSL gedeelte?

Line 71: \' . $form . \'\';
Wat heeft dat . \'\' voor nut?

Veel beter dan dat vorige baggerscript dat alleen maar $ingelogd=true; heeft weggelaten van Saven\'s script


SSL zit in je server https://www.jesite.nl/inloggen/ zoiets bijvoorbeeld.

Line 71: Tjek de vorige regels. Die maken het laatste deel van de foutmelding en laten hem zien, zo kan de gebruiker direct weer een inlogpoging doen ipv terug te gaan of op vorige te klikken.

iisys
Hmhm, indeed. whtvr.
moderator
Geplaatst op: 25 Dec 2006, 14:18

Mm misschien dat ik het over t hoofd zie, maar waar zit het SSL gedeelte?

Line 71: \' . $form . \'\';
Wat heeft dat . \'\' voor nut?

Veel beter dan dat vorige baggerscript dat alleen maar $ingelogd=true; heeft weggelaten van Saven\'s script

Died
Geplaatst op: 25 Dec 2006, 14:15

Nice idd
En handig natuurlijk

[Laatst bewerkt door Spunk op maandag 25 december 2006, om 14:15]
HyperTesia
Webdeveloper
Geplaatst op: 25 Dec 2006, 13:37

dees is wel nice

FastFox
Geplaatst op: 25 Dec 2006, 11:49

Persoonlijk vindt ik bij stap 4 punt 2 overbodig omdat je punt 3 als beveiliging hebt. Dus als er een botje je wachtwoord probeert te bruteforcen, is het maar 3 seconden extra op de kwartier. Dat is dus bijna niets. En voor de gebruiker is een seconde wel veel als je het vergelijk met de tijd van het hele inlog gebeure.
Maar verder netjes.

Saven
admin
Geplaatst op: 25 Dec 2006, 11:23

Andries Louw W. schreef:

Keurig script!

Variabelen mooi buiten quotes, goede error afhandeling.
Voor de beginner misschien een beetje moeilijk i.v.m. de ontbrekende tabellen, maar een beetje PHP-er kan deze er zo bij \'verzinnen\'.


Idd

Een mooie toevoeging op de laatst geposte tutorials

Gast
Geplaatst op: 25 Dec 2006, 10:18

Keurig script!

Variabelen mooi buiten quotes, goede error afhandeling.
Voor de beginner misschien een beetje moeilijk i.v.m. de ontbrekende tabellen, maar een beetje PHP-er kan deze er zo bij \'verzinnen\'.

📫

Nieuw privébericht

🔥

Registreren


Login