inloggen2024.php
Code (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
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
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
<?php
declare (strict_types=1);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
error_reporting(E_STRICT | E_ALL);
// https://www.php.net/manual/en/session.configuration.php
ini_set("session.auto_start", "0"); // Handmatig starten in ieder script
// Status van bestanden ontvangen bijhouden in $_SESSION
ini_set("upload_progress.enabled", "1"); // Houd ontvangen van uploads bij
ini_set("upload_progress.cleanup", "1"); // wis status na uploaden
ini_set("upload_progress.prefix", "upload_progress_"); // key prefix voor status
ini_set("upload_progress.name", "PHP_SESSION_UPLOAD_PROGRESS"); // key naam
ini_set("upload_progress.freq", "1%"); // Status 100x bijwerken per bestand ..
ini_set("upload_progress.min_freq", "1"); // .. maar niet vaker dan 1x per seconde.
// Sessie starten:
// 1. geen sessie ID ontvangen? Dan aanmaken en versturen als HTTP cookie
// 2. sessie ID ontvangen en aanwezig op server? Gegevens laden in $_SESSION
// 3. af en toe sessiegegevens opruimen op server.
// N.B.: deze functie verstuurt meteen HTTP-headers, als eerste aanroepen
session_start([
// Sessie ID verzinnen
"sid_length" => "48", // Aantal karakters van sessie ID
"sid_bits_per_character" => "6", // Aantal bits per karakter (4-6)
// Sessie ID versturen naar browser
"use_cookies" => "1", // SID versturen als HTTP cookie naar browser,
"use_only_cookies" => "1", // .. en alleen via HTTP, niet via URLs,
"cookie_secure" => "1", // .. en alleen via een versleutelde verbinding,
"cookie_samesite" => "strict", // .. en niet naar andere domeinen,
"cookie_httponly" => "1", // .. en verberg het SID voor JavaScript
"name" => "sid", // Verberg "PHP" in cookienaam (standaard "PHPSESSID")
"cookie_domain" => $_SERVER['HTTP_HOST'], // Gebruik huidige domein
"cookie_path" => "/", // cookie is voor alle paden op de domein
"cookie_lifetime" => "0", // bewaar in browser totdat de browser sluit
"cache_expire" => 180, // Cookie cache in browser vervalt na 3 uur
// Niet vanzelf URLs van HTML elementen vertalen via output buffer!
"use_trans_sid" => "0", // Niet vanzelf URLs vertalen voor $_GET
"trans_sid_tags" => "", // Geen URLs van HTML elementen herschrijven met SID
"trans_sid_hosts" => "", // Voorgeen enkele hostname vanzelf URLs vertalen
// Sessie ID ontvangen
"referer_check" => "", // HTTP Referer ($_SERVER['HTTP_REFERER']) niet nodig
// Handler voor bewaren van data ($_SESSION)
"save_handler" => "files", // Data opslaan in bestanden op server
"save_path" => "", // Voor sessie handler, standaard "/tmp" (!)
"serialize_handler" => "php", // standaard serializer
"lazy_write" => "1", // Alleen bewaren als er wijzigingen zijn
"gc_probability" => 1, // Teller van kans voor wissen op server
"gc_divisor" => 100, // Noemer van kans voor wissen op server
"gc_maxlifetime" => 1440, // data ouder dan 24 minuten wissen op server
]);
// Accounts kunnen in een bestand of in een database bewaard
// Altijd alleen de hash van een wachtwoord opslaan, nooit het wachtwoord zelf!
$hash_opties = [
"memory_cost" => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
"time_cost" => PASSWORD_ARGON2_DEFAULT_TIME_COST,
"threads" => PASSWORD_ARGON2_DEFAULT_THREADS];
$accounts = [
"beheerder" => // password_hash("beheerder", PASSWORD_ARGON2ID, $hash_opties);
'$argon2id$v=19$m=65536,t=4,p=1$zYcsM0OuufIy5/rD5Wrctw$dTXqVi0kpnn2tJUymAr4FQYopn63x72Ux1tXK7/axDM',
];
$auth_status = "";
// Aanmeldpoging
if (strlen($_POST["account"] ?? "") && strlen($_POST["password"] ?? "")) {
if (! array_key_exists($_POST["account"], $accounts)) {
// Aanmelden mislukt, account bestaat niet
$_SESSION = [];
$auth_status = "Inloggen mislukt";
// log poging.
password_verify("", // anti-timing attack
'$argon2id$v=19$m=65536,t=4,p=1$SDBY9tz9BDxUwoNtNL9NBg$Q6hY/njk4/unRJpeCO51fwvTKRWOD21ouixWJAHQ7og');
sleep(1); // verplicht wachten
} else {
// deblokkeer account als deze is geblokkeerd en de wachttijd verstreken
$account = $_POST["account"];
$hash = $accounts[$account];
$password = $_POST["password"] ?? "";
if (! password_verify($password, $hash)
// || $account_geblokkeerd
// || $account_password_verlopen
) {
$_SESSION = [];
// - tel het aantal keer dat het aanmelden niet is gelukt
// en blokkeer het account na X aanmeldingen.
// - wis het wachtwoord als wachtwoord is verlopen.
sleep(1); // verplicht wachten
// log poging.
$auth_status = "Inloggen mislukt";
} else { // Aanmelden gelukt
if (password_needs_rehash($hash, PASSWORD_ARGON2ID, $hash_opties)) {
// update hash van account.
}
// deblokkeer account als het is geblokkeerd
// zet het aantal mislukte pogingen op 0.
$_SESSION["ACCOUNT"] = $account;
// stel CSRF token in, en stuur deze mee in alle forms en URL's:
$_SESSION["CSRF"] = bin2hex(random_bytes(32));
// stuur CSRF mee na inloggen:
$_REQUEST["csrf"] = $_SESSION["CSRF"];
// log poging.
}
}
}
// CSRF-bescherming
if (isset($_SESSION["ACCOUNT"])
&& (! isset($_REQUEST['csrf'])
|| $_REQUEST["csrf"] !== $_SESSION["CSRF"]))
{
$auth_status = "Bron van verzoek onbekend, probeer opnieuw.";
// log poging.
}
// Afmeldpoging
else if (isset($_SESSION["ACCOUNT"]) && isset($_GET["_afmelden"])) {
$_SESSION = [];
$auth_status = "U bent uitgelogd";
// log poging.
}
// Aangemeld!
//
// [...]
//
session_write_close();
declare (strict_types=1);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
error_reporting(E_STRICT | E_ALL);
// https://www.php.net/manual/en/session.configuration.php
ini_set("session.auto_start", "0"); // Handmatig starten in ieder script
// Status van bestanden ontvangen bijhouden in $_SESSION
ini_set("upload_progress.enabled", "1"); // Houd ontvangen van uploads bij
ini_set("upload_progress.cleanup", "1"); // wis status na uploaden
ini_set("upload_progress.prefix", "upload_progress_"); // key prefix voor status
ini_set("upload_progress.name", "PHP_SESSION_UPLOAD_PROGRESS"); // key naam
ini_set("upload_progress.freq", "1%"); // Status 100x bijwerken per bestand ..
ini_set("upload_progress.min_freq", "1"); // .. maar niet vaker dan 1x per seconde.
// Sessie starten:
// 1. geen sessie ID ontvangen? Dan aanmaken en versturen als HTTP cookie
// 2. sessie ID ontvangen en aanwezig op server? Gegevens laden in $_SESSION
// 3. af en toe sessiegegevens opruimen op server.
// N.B.: deze functie verstuurt meteen HTTP-headers, als eerste aanroepen
session_start([
// Sessie ID verzinnen
"sid_length" => "48", // Aantal karakters van sessie ID
"sid_bits_per_character" => "6", // Aantal bits per karakter (4-6)
// Sessie ID versturen naar browser
"use_cookies" => "1", // SID versturen als HTTP cookie naar browser,
"use_only_cookies" => "1", // .. en alleen via HTTP, niet via URLs,
"cookie_secure" => "1", // .. en alleen via een versleutelde verbinding,
"cookie_samesite" => "strict", // .. en niet naar andere domeinen,
"cookie_httponly" => "1", // .. en verberg het SID voor JavaScript
"name" => "sid", // Verberg "PHP" in cookienaam (standaard "PHPSESSID")
"cookie_domain" => $_SERVER['HTTP_HOST'], // Gebruik huidige domein
"cookie_path" => "/", // cookie is voor alle paden op de domein
"cookie_lifetime" => "0", // bewaar in browser totdat de browser sluit
"cache_expire" => 180, // Cookie cache in browser vervalt na 3 uur
// Niet vanzelf URLs van HTML elementen vertalen via output buffer!
"use_trans_sid" => "0", // Niet vanzelf URLs vertalen voor $_GET
"trans_sid_tags" => "", // Geen URLs van HTML elementen herschrijven met SID
"trans_sid_hosts" => "", // Voorgeen enkele hostname vanzelf URLs vertalen
// Sessie ID ontvangen
"referer_check" => "", // HTTP Referer ($_SERVER['HTTP_REFERER']) niet nodig
// Handler voor bewaren van data ($_SESSION)
"save_handler" => "files", // Data opslaan in bestanden op server
"save_path" => "", // Voor sessie handler, standaard "/tmp" (!)
"serialize_handler" => "php", // standaard serializer
"lazy_write" => "1", // Alleen bewaren als er wijzigingen zijn
"gc_probability" => 1, // Teller van kans voor wissen op server
"gc_divisor" => 100, // Noemer van kans voor wissen op server
"gc_maxlifetime" => 1440, // data ouder dan 24 minuten wissen op server
]);
// Accounts kunnen in een bestand of in een database bewaard
// Altijd alleen de hash van een wachtwoord opslaan, nooit het wachtwoord zelf!
$hash_opties = [
"memory_cost" => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
"time_cost" => PASSWORD_ARGON2_DEFAULT_TIME_COST,
"threads" => PASSWORD_ARGON2_DEFAULT_THREADS];
$accounts = [
"beheerder" => // password_hash("beheerder", PASSWORD_ARGON2ID, $hash_opties);
'$argon2id$v=19$m=65536,t=4,p=1$zYcsM0OuufIy5/rD5Wrctw$dTXqVi0kpnn2tJUymAr4FQYopn63x72Ux1tXK7/axDM',
];
$auth_status = "";
// Aanmeldpoging
if (strlen($_POST["account"] ?? "") && strlen($_POST["password"] ?? "")) {
if (! array_key_exists($_POST["account"], $accounts)) {
// Aanmelden mislukt, account bestaat niet
$_SESSION = [];
$auth_status = "Inloggen mislukt";
// log poging.
password_verify("", // anti-timing attack
'$argon2id$v=19$m=65536,t=4,p=1$SDBY9tz9BDxUwoNtNL9NBg$Q6hY/njk4/unRJpeCO51fwvTKRWOD21ouixWJAHQ7og');
sleep(1); // verplicht wachten
} else {
// deblokkeer account als deze is geblokkeerd en de wachttijd verstreken
$account = $_POST["account"];
$hash = $accounts[$account];
$password = $_POST["password"] ?? "";
if (! password_verify($password, $hash)
// || $account_geblokkeerd
// || $account_password_verlopen
) {
$_SESSION = [];
// - tel het aantal keer dat het aanmelden niet is gelukt
// en blokkeer het account na X aanmeldingen.
// - wis het wachtwoord als wachtwoord is verlopen.
sleep(1); // verplicht wachten
// log poging.
$auth_status = "Inloggen mislukt";
} else { // Aanmelden gelukt
if (password_needs_rehash($hash, PASSWORD_ARGON2ID, $hash_opties)) {
// update hash van account.
}
// deblokkeer account als het is geblokkeerd
// zet het aantal mislukte pogingen op 0.
$_SESSION["ACCOUNT"] = $account;
// stel CSRF token in, en stuur deze mee in alle forms en URL's:
$_SESSION["CSRF"] = bin2hex(random_bytes(32));
// stuur CSRF mee na inloggen:
$_REQUEST["csrf"] = $_SESSION["CSRF"];
// log poging.
}
}
}
// CSRF-bescherming
if (isset($_SESSION["ACCOUNT"])
&& (! isset($_REQUEST['csrf'])
|| $_REQUEST["csrf"] !== $_SESSION["CSRF"]))
{
$auth_status = "Bron van verzoek onbekend, probeer opnieuw.";
// log poging.
}
// Afmeldpoging
else if (isset($_SESSION["ACCOUNT"]) && isset($_GET["_afmelden"])) {
$_SESSION = [];
$auth_status = "U bent uitgelogd";
// log poging.
}
// Aangemeld!
//
// [...]
//
session_write_close();