Formulier opnieuw verzonden na verversen van pagina
Het is ook niet nodig om eerst te controleren of een sessie "bestaat" middels isset() - session_start() wordt gebruikt om een sessie te starten en/of voort te zetten.
Het ding is gewoon, op het moment dat je met formulieren aan de slag gaat kom je in een gebied terecht dat een overlap heeft met andere zaken, hier komen een aantal zaken bij elkaar die elk op een juiste wijze behandeld zouden moeten worden.
Ik heb het gevonden op One2XS geloof ik :-)
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Csrf {
public static function makeToken() {
$max_time = 60 * 60 * 24;
$csrf_token = $_SESSION['csrf_token'];
$stored_time = $_SESSION['csrf_token_time'];
if ( $max_time + $stored_time <= time() || empty( $csrf_token ) ) {
$_SESSION['csrf_token'] = md5( uniqid( rand(), true ) );
$_SESSION['csrf_token_time'] = time();
}
return $_SESSION['csrf_token'];
}
public static function isTokenValid( $field ) {
return $field === $_SESSION['csrf_token'];
}
}
?>
class Csrf {
public static function makeToken() {
$max_time = 60 * 60 * 24;
$csrf_token = $_SESSION['csrf_token'];
$stored_time = $_SESSION['csrf_token_time'];
if ( $max_time + $stored_time <= time() || empty( $csrf_token ) ) {
$_SESSION['csrf_token'] = md5( uniqid( rand(), true ) );
$_SESSION['csrf_token_time'] = time();
}
return $_SESSION['csrf_token'];
}
public static function isTokenValid( $field ) {
return $field === $_SESSION['csrf_token'];
}
}
?>
Code (php)
HTML:
Gewijzigd op 24/09/2018 00:55:13 door - Ariën -
door je formulier naar form.php te posten en lekker daar te blijven totdat de validatie van het formulier geslaagd is en de gegevens van het formulier verwerkt zijn.
Toevoeging op 24/09/2018 11:43:11:
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
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
<?php
// functie die de formuliervelden valideert en foutmeldingen aanmaakt
function validate($naam, $email)
{
$errors = array();
// validatieregels voor de naam
if(strlen($naam) < 2)
$errors['naam'] = 'U heeft geen naam ingevuld.';
// validatieregels voor het mailadres
if(!strlen($email))
$errors['email'] = 'U heeft geen email adres ingevuld.';
else if(!filter_var($email, FILTER_VALIDATE_EMAIL))
$errors['email'] = 'U heeft een ongeldig email adres ingevuld.';
// geef de array met foutmeldingen terug
return $errors;
}
// initialisatie
$naam = '';
$email = '';
$errors = array();
// indien het formulier verstuurd is
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
// overschrijf de variabelen met de waarde uit de $_POST array
$naam = $_POST['naam'];
$email = $_POST['email'];
// valideer de ingevulde gegevens
$errors = validate($_POST['naam'], $_POST['email']);
// als geen fouten voortkomen uit de validatie
if(!count($errors))
{
/*
* Verwerk hier je formulier, bijvoorbeeld een email versturen of
* de gegevens opslaan in de database
*/
// redirect de gebruiker
header('Location: confirmation.html');
exit;
}
}
?>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Mijn eerste formulier</title>
</head>
<body>
<?php
if(count($errors)) {
echo '<ul id="errors">';
foreach($errors as $error) {
echo '<li>' . $error . '</li>';
}
echo '</ul>';
}
?>
<form method="post">
<input type="text" name="naam" value="<?php echo $naam ?>" />
<input type="email" name="email" value="<?php echo $email ?>" />
<button type="submit">Verzenden</button>
</form>
</body>
</html>
// functie die de formuliervelden valideert en foutmeldingen aanmaakt
function validate($naam, $email)
{
$errors = array();
// validatieregels voor de naam
if(strlen($naam) < 2)
$errors['naam'] = 'U heeft geen naam ingevuld.';
// validatieregels voor het mailadres
if(!strlen($email))
$errors['email'] = 'U heeft geen email adres ingevuld.';
else if(!filter_var($email, FILTER_VALIDATE_EMAIL))
$errors['email'] = 'U heeft een ongeldig email adres ingevuld.';
// geef de array met foutmeldingen terug
return $errors;
}
// initialisatie
$naam = '';
$email = '';
$errors = array();
// indien het formulier verstuurd is
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
// overschrijf de variabelen met de waarde uit de $_POST array
$naam = $_POST['naam'];
$email = $_POST['email'];
// valideer de ingevulde gegevens
$errors = validate($_POST['naam'], $_POST['email']);
// als geen fouten voortkomen uit de validatie
if(!count($errors))
{
/*
* Verwerk hier je formulier, bijvoorbeeld een email versturen of
* de gegevens opslaan in de database
*/
// redirect de gebruiker
header('Location: confirmation.html');
exit;
}
}
?>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Mijn eerste formulier</title>
</head>
<body>
<?php
if(count($errors)) {
echo '<ul id="errors">';
foreach($errors as $error) {
echo '<li>' . $error . '</li>';
}
echo '</ul>';
}
?>
<form method="post">
<input type="text" name="naam" value="<?php echo $naam ?>" />
<input type="email" name="email" value="<?php echo $email ?>" />
<button type="submit">Verzenden</button>
</form>
</body>
</html>
@Ariën: zal me later es verdiepen in een token... eerst maar de opbouw van mijn formulier goed krijgen ;-)
@Frank: bedankt voor je voorbeeld. Ik kan de gebruiker natuurlijk ook redirecten naar dezelfde pagina nadat formulier verstuurd is (nog niet getest):
Code (php)
1
2
3
4
5
6
2
3
4
5
6
header('location:form.php?m=success');
$check = $_GET['m'];
if ($check == success) {
echo 'Succes bericht';
}
$check = $_GET['m'];
if ($check == success) {
echo 'Succes bericht';
}
Guido
Gewijzigd op 24/09/2018 12:49:00 door Guido -
Nadat het formulier succesvol is verwerkt moet dit token direct ongeldig gemaakt worden. Of sterker nog, na elke submitpoging zou dit token ongeldig moeten zijn.
Gewijzigd op 24/09/2018 14:23:01 door Thomas van den Heuvel
Bij een redirect gaat je form data (je $_POST array) verloren. De gebruiker moet dan vervolgens zijn formulier weer helemaal opnieuw invullen hetgeen niet erg gebruiksvriendelijk is. Zo ook voor de foutmeldingen die je boven of in het formulier wilt tonen. Natuurlijk zijn er lapmiddelen te bedenken met GET variabelen of met behulp van $_SESSION maar dat zou het alleen maar nodeloos ingewikkeld maken.
@Thomas Daar heb je wel een punt. Ik zal me er eens in verdiepen hoe OWASP erover denkt.
Frank Nietbelangrijk op 24/09/2018 16:35:39:
Natuurlijk zijn er lapmiddelen te bedenken met GET variabelen
Eigenlijk zou je GET alleen maar voor (onpersoonlijke) zoekopdrachten moeten gebruiken of bijvoorbeeld zaken als pagina-navigatie. URLs kunnen mogelijk gecached worden door tussenstations (proxy's). Zelfs HTTPS gaat je dan waarschijnlijk niet helpen. Betreft het persoonlijke/gevoelige informatie --> gebruikt POST.
in jouw voorbeeld gebruik je alleen een header location als formulier correct ingevuld is, dus maakt het dan niet meer uit of de POST array verloren gaat. Ik toon immers alleen nog een Dank U bericht. Of zie ik iets over het hoofd?
Of wil je jouw site zo vriendelijk maken dat bij een volgende vraag via het contactformulier de naam standaard ingevuld is?
Ja, dat bedoel ik dus ook.
Dan moet je de $_POST in een sessie opslaan.
We praten langs elkaar heen. Ik vind het juist prima dat de POST array leeg is want het enige wat ik wil tonen als validatie correct is, is een "Dank U" bericht. En een leeg formulier.
En ik denk dat weinig bezoekers van je site het nodig vinden om direct een bericht erachteraan te gooien.
En anders vinden ze de link vast wel ;-)
Op lijn 46 vindt er een redirect plaats naar confirmation.html. Dat is de plek voor het "Dankjewel!" bericht.
Gewijzigd op 24/09/2018 18:10:00 door Frank Nietbelangrijk
Frank Nietbelangrijk op 24/09/2018 18:00:10:
Vergeet niet een exit(); achter de redirect te plaatsen overigens.
Of introduceer hiervoor een functie.
Gewijzigd op 24/09/2018 19:45:28 door Thomas van den Heuvel
Guido
Doe een "algemene pre-check" met javascript om de "normale bezoekers" te faciliteren.
Pas als je door de pre-check heen komt, verstuur je het formulier werkelijk en check het het met PHP.
Scheelt een hoop onnodig gePOST naar je server.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<form action="" method="" onsubmit="javascript: return checkForm(this);">
</form>
<script type="text/javascript">
function checkForm(oFormElement)
{
var bErrorFound = false;
if(????) // Is er een error gevonden
{
bErrorFound = true;
}
return (bErrorFound == false);
}
</script>
</form>
<script type="text/javascript">
function checkForm(oFormElement)
{
var bErrorFound = false;
if(????) // Is er een error gevonden
{
bErrorFound = true;
}
return (bErrorFound == false);
}
</script>