Escapen van data in functiebieb (om te leren!!)
Onlangs heb ik op deze site melding gemaakt van het feit dat een van mijn sites bezocht was door ongenode gasten. Achteraf bleek dat er het e.e.a. aan mijn beveiliging schortte.
Zo heb ik nu mijn queries voor DELETE, INSERT en UPDATE via een prepared statement laten lopen. Dit lijkt allemaal goed te gaan. In ieder geval komen de nieuwe waardes van de variabelen terecht in de juiste tabellen.
Nu gaat er de laatste tijd op dit forum een discussie rond over het escapen van input-data.
Nu heb ik voor mijzelf een functie opgenomen in mijn bibliotheek om alle input-data hierdoor te laten "schonen".
Graag hoor ik van jullie of deze schoning nog aanvulling behoeft.
Functie:
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
<?php
function EscapeData($cDataVar) {
$cDataVar = strip_tags($cDataVar);
$cDataVar = htmlspecialchars($cDataVar);
return($cDataVar);
}
?>
function EscapeData($cDataVar) {
$cDataVar = strip_tags($cDataVar);
$cDataVar = htmlspecialchars($cDataVar);
return($cDataVar);
}
?>
Deze functie pas ik op de volgende wijze toe in mijn script:
Script:
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
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
<?php
if($_SERVER['REQUEST_METHOD'] === 'POST') {
// Inlezen invulvelden
$cNaamInzender = $_POST['naam'];
$cEmailInzender = $_POST['email'];
$cCorrectie = $_POST['bericht'];
$cBestandsnaam = basename($_FILES['bestand']['name']);
// Ontdoen van mogelijke verkeerde info
$cNaamInzender = EscapeData(cNaamInzender);
$cEmailInzender = EscapeData($cEmailInzender);
$cBestandsnaam = EscapeData($cBestandsnaam);
$cBestandsnaam = VertaalBestandsnaam($cBestandsnaam);
$cCorrectie = EscapeData($cCorrectie);
$cBestemming = "uploads/" . $cBestandsnaam;
$cIdPersoon = $_SESSION['cx'];
$cVersie = $_SESSION['versie'];
$cPersoon1 = $_SESSION['persoonsnaam'];
//Open de connectie met de database
include "connectie_nw.inc.php";
include "queries/sql_ins_correctie.php";
// Create a prepared statement en bewaar de melding in de database
$stmt=mysqli_stmt_init($verbinding);
if (mysqli_stmt_prepare($stmt,$sql)) {
// Execute query
mysqli_stmt_execute($stmt);
// Fetch value
mysqli_stmt_fetch($stmt);
// Close statement
mysqli_stmt_close($stmt);
}
// Upload bijgesloten file
// Brondoc: http://www.w3schools.com/php/php_file_upload.asp
if ($_FILES["bestand"]["error"] > 0) {
echo "Return Code: " . $_FILES["bestand"]["error"] . "<br>";
} else {
if (file_exists("uploads/" . $_FILES["bestand"]["name"])) {
echo $_FILES["bestand"]["name"] . " already exists. ";
} else {
move_uploaded_file($_FILES["bestand"]["tmp_name"],$cBestemming);
}
}
mysqli_close($verbinding);
}
?>
if($_SERVER['REQUEST_METHOD'] === 'POST') {
// Inlezen invulvelden
$cNaamInzender = $_POST['naam'];
$cEmailInzender = $_POST['email'];
$cCorrectie = $_POST['bericht'];
$cBestandsnaam = basename($_FILES['bestand']['name']);
// Ontdoen van mogelijke verkeerde info
$cNaamInzender = EscapeData(cNaamInzender);
$cEmailInzender = EscapeData($cEmailInzender);
$cBestandsnaam = EscapeData($cBestandsnaam);
$cBestandsnaam = VertaalBestandsnaam($cBestandsnaam);
$cCorrectie = EscapeData($cCorrectie);
$cBestemming = "uploads/" . $cBestandsnaam;
$cIdPersoon = $_SESSION['cx'];
$cVersie = $_SESSION['versie'];
$cPersoon1 = $_SESSION['persoonsnaam'];
//Open de connectie met de database
include "connectie_nw.inc.php";
include "queries/sql_ins_correctie.php";
// Create a prepared statement en bewaar de melding in de database
$stmt=mysqli_stmt_init($verbinding);
if (mysqli_stmt_prepare($stmt,$sql)) {
// Execute query
mysqli_stmt_execute($stmt);
// Fetch value
mysqli_stmt_fetch($stmt);
// Close statement
mysqli_stmt_close($stmt);
}
// Upload bijgesloten file
// Brondoc: http://www.w3schools.com/php/php_file_upload.asp
if ($_FILES["bestand"]["error"] > 0) {
echo "Return Code: " . $_FILES["bestand"]["error"] . "<br>";
} else {
if (file_exists("uploads/" . $_FILES["bestand"]["name"])) {
echo $_FILES["bestand"]["name"] . " already exists. ";
} else {
move_uploaded_file($_FILES["bestand"]["tmp_name"],$cBestemming);
}
}
mysqli_close($verbinding);
}
?>
Mijn vraag is dan ook: Zitten in beide scripts nog onvolkomenheden? Ik wil graag iets leren en geen aapje worden die een kunstje kent.....
George
Bijvoorbeeld strip_tags en htmlspecialchars, waarom doe je die voor je het in de database zet?
Ofwel je doet het na het weer uit de database halen en voor het versturen naar de browser. Je wil in principe namelijk de oorspronkelijke user input in je database hebben en niet een aangepaste versie. Heb je namelijk iets aangepast, dan kan je nooit meer de oorspronkelijke versie terughalen.
Ofwel je wil weten of er iets raars in je data zit, zodat je de hele insert kan voorkomen. Is er namelijk iemand bezig met een hack poging, en je ontdekt het in je code, dan is er geen enkele reden om de data alsnog in de database te zetten. Het is toch allemaal troep, dus stop met de hele actie in dat geval.
In beide gevallen is er dus geen reden om vooraf al die acties uit te voeren.
Een andere opmerking:
Hier doe je eigenlijk twee dingen verkeerd. In de eerste plaats check je niet of de key 'naam' wel bestaat in de $_POST array. Bestaat die niet dan gaat je script plat. Daarnaast kan het natuurlijk direct, in 1 regel (en sommige zullen zeggen dat je het onnodig in een variabele kopieert, daar ben ik het niet noodzakelijkerwijs mee eens)
Code (php)
Gewijzigd op 17/11/2013 11:44:46 door Erwin H
Dank voor je toelichting.
1. Het testen of de betreffende key bestaat ga ik overnemen.
2. Het langs de functie EscapeData laten lopen van de variabele zou volgens jou pas moeten bij het uitlezen van de tabel en niet bij het opslaan in de tabel. Is dit een keuze of is dit echt bittere noodzaak?
Toevoeging op 17/11/2013 12:28:08:
Erwin,
Nog een toevoeging: Ik gebruik in mijn html-deel wel de mogelijkheid om velden verplicht met het juiste format te laten invullen.
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
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
<div id="tabs-6" >
<strong>Inzenden aanvulling</strong>
<div class="regelhoogte25"></div>
<?php if(!empty($errors)){ echo "<p class='err'>".nl2br($errors)."</p>"; } ?>
<div id='contact_form_errorloc' class='err'></div>
<form name="contact_form" action="persoonskaart.php?id=<?php echo $cX ; ?>" method="POST" enctype="multipart/form-data">
<input type="submit" class="aanvulling" value="Insturen aanvulling" />
<label for="naam">Uw naam:</label><br />
<input type="text" name="naam" placeholder="Uw naam" required="" /><br />
<label for="email">Uw e-mailadres:</label><br />
<input type="email" name="email" placeholder="Uw e-mailadres" /><br />
<label for="bestand">Evt. bestand:</label><br />
<input type="file" name="bestand" /><br />
<label for="bericht">Uw aanvulling:</label><br />
<textarea name="bericht" style="margin-bottom: 5px!important; width: 300px!important;" ></textarea><br />
<img src="captcha/captcha_code_file.php?rand=<?php echo rand(); ?>" id='captchaimg' ><br>
<label for='message'>Controlecode. Neem het woord hierboven over</label><br />
<input id="6_letters_code" name="6_letters_code" type="text" placeholder="Controlecode" required="" /><br />
<small>Code onleesbaar? Klik <a href='javascript: refreshCaptcha();'>hier</a> voor een nieuwe code</small><br />
</form>
<script language="JavaScript">
// Code for validating the form
// Visit http://www.javascript-coder.com/html-form/javascript-form-validation.phtml
// for details
var frmvalidator = new Validator("contact_form");
//remove the following two lines if you like error message box popups
frmvalidator.EnableOnPageErrorDisplaySingleBox();
frmvalidator.EnableMsgsTogether();
frmvalidator.addValidation("naam","req","Vul uw naam in");
frmvalidator.addValidation("bericht","req","Vul uw bericht in");
frmvalidator.addValidation("email","req","Vul uw e-mailadres in");
frmvalidator.addValidation("email","email","Geen geldig e-mailadres");
</script>
<script language='JavaScript' type='text/javascript'>
function refreshCaptcha() {
var img = document.images['captchaimg'];
img.src = img.src.substring(0,img.src.lastIndexOf("?"))+"?rand="+Math.random()*1000;
}
</script>
</div>
<strong>Inzenden aanvulling</strong>
<div class="regelhoogte25"></div>
<?php if(!empty($errors)){ echo "<p class='err'>".nl2br($errors)."</p>"; } ?>
<div id='contact_form_errorloc' class='err'></div>
<form name="contact_form" action="persoonskaart.php?id=<?php echo $cX ; ?>" method="POST" enctype="multipart/form-data">
<input type="submit" class="aanvulling" value="Insturen aanvulling" />
<label for="naam">Uw naam:</label><br />
<input type="text" name="naam" placeholder="Uw naam" required="" /><br />
<label for="email">Uw e-mailadres:</label><br />
<input type="email" name="email" placeholder="Uw e-mailadres" /><br />
<label for="bestand">Evt. bestand:</label><br />
<input type="file" name="bestand" /><br />
<label for="bericht">Uw aanvulling:</label><br />
<textarea name="bericht" style="margin-bottom: 5px!important; width: 300px!important;" ></textarea><br />
<img src="captcha/captcha_code_file.php?rand=<?php echo rand(); ?>" id='captchaimg' ><br>
<label for='message'>Controlecode. Neem het woord hierboven over</label><br />
<input id="6_letters_code" name="6_letters_code" type="text" placeholder="Controlecode" required="" /><br />
<small>Code onleesbaar? Klik <a href='javascript: refreshCaptcha();'>hier</a> voor een nieuwe code</small><br />
</form>
<script language="JavaScript">
// Code for validating the form
// Visit http://www.javascript-coder.com/html-form/javascript-form-validation.phtml
// for details
var frmvalidator = new Validator("contact_form");
//remove the following two lines if you like error message box popups
frmvalidator.EnableOnPageErrorDisplaySingleBox();
frmvalidator.EnableMsgsTogether();
frmvalidator.addValidation("naam","req","Vul uw naam in");
frmvalidator.addValidation("bericht","req","Vul uw bericht in");
frmvalidator.addValidation("email","req","Vul uw e-mailadres in");
frmvalidator.addValidation("email","email","Geen geldig e-mailadres");
</script>
<script language='JavaScript' type='text/javascript'>
function refreshCaptcha() {
var img = document.images['captchaimg'];
img.src = img.src.substring(0,img.src.lastIndexOf("?"))+"?rand="+Math.random()*1000;
}
</script>
</div>
George van Baasbank op 17/11/2013 12:17:55:
2. Het langs de functie EscapeData laten lopen van de variabele zou volgens jou pas moeten bij het uitlezen van de tabel en niet bij het opslaan in de tabel. Is dit een keuze of is dit echt bittere noodzaak?
Wat je doet is daar niet escapen (ook al noem je het zo). Escapen is het onschadelijk maken van bepaalde karakters door er (over het algemeen) een andere karakter voor te zetten dat de database weet dat het als een normaal karaketer in de string moet worden gezien. Dat heb je normaal gesproken nodig in een query, maar niet meer op het moment dat je prepared statements gebruikt. Wat jij doet in je 'EscapeData' functie is het veranderen van bepaalde stukken in de string, normaal gesproken gebruikt om HTML injectie of XSS tegen te gaan.
Is het keuze om het op het ene moment of het andere te doen? Ja, uiteraard is dat een keuze. Waarom je het pas later zou moeten doen heb ik eerder uitgelegd.