PHP en MYSQL injection
Ik probeer momenteel mijn invoervelden veilig te maken tegen MYSQL injection. Is dit goed genoeg beveiligd?
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
$link = mysqli_connect($db_hostname, $db_username, $db_password, $db_database) or die("Error " . mysqli_error($link));
$bloopp = $_POST['bloopp'];
$bloopp = htmlspecialchars($bloopp);
$bloopp = mysqli_real_escape_string($link, $bloopp);
$bloopp = strip_tags($bloopp);
$search = array("'", '"', "--");
$replace = array("´", "$acute;", "_");
$bloopp = str_replace($search, $replace, $bloopp);
$bloopp = $_POST['bloopp'];
$bloopp = htmlspecialchars($bloopp);
$bloopp = mysqli_real_escape_string($link, $bloopp);
$bloopp = strip_tags($bloopp);
$search = array("'", '"', "--");
$replace = array("´", "$acute;", "_");
$bloopp = str_replace($search, $replace, $bloopp);
Alvast bedankt om een kijkje te nemen!
Sven
Het beveiligen van een applicatie start altijd met weten wat je doet, niet zo maar iets doen en dan hopen dan het veilig is. Als ik dit soort lijnen code zie vraag ik me altijd af of de kennis er wel is. Dus als eerste de vraag: waartegen wil je beveiligen? Probeer bij elke regel dan ook eens te vermelden waarom je die regel nodig denkt te hebben.
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
// (1) Is $_POST['bloopp'] ingesteld en (2) is $_POST['bloopp'] niet leeg?
if (isset($_POST['bloopp']) && !empty($_POST['bloopp'])) {
// (3) Is $_POST['bloopp'] een string?
if (is_string($_POST['bloopp'])) {
// (4) Gebruikt deze server nog verouderde magic quotes?
if (get_magic_quotes_gpc()) {
$_POST['bloopp'] = strip_slashes($_POST['bloopp']);
}
$_POST['bloopp'] = strip_tags($_POST['bloopp']);
$_POST['bloopp'] = htmlspecialchars($_POST['bloopp']);
$link = mysqli_connect($db_hostname, $db_username, $db_password, $db_database);
// (5) Is er geen fout opgetreden bij het openen van de databaseverbinding?
if (!mysqli_connect_error()) {
// (6) Kan de juiste MySQL-karakterset worden ingesteld?
if (mysqli_set_charset($link, 'utf8')) {
$_POST['bloopp'] = mysqli_real_escape_string($link, $_POST['bloopp']);
// Hier een prepared statement opstellen en uitvoeren.
// <...>
}
}
}
}
?>
// (1) Is $_POST['bloopp'] ingesteld en (2) is $_POST['bloopp'] niet leeg?
if (isset($_POST['bloopp']) && !empty($_POST['bloopp'])) {
// (3) Is $_POST['bloopp'] een string?
if (is_string($_POST['bloopp'])) {
// (4) Gebruikt deze server nog verouderde magic quotes?
if (get_magic_quotes_gpc()) {
$_POST['bloopp'] = strip_slashes($_POST['bloopp']);
}
$_POST['bloopp'] = strip_tags($_POST['bloopp']);
$_POST['bloopp'] = htmlspecialchars($_POST['bloopp']);
$link = mysqli_connect($db_hostname, $db_username, $db_password, $db_database);
// (5) Is er geen fout opgetreden bij het openen van de databaseverbinding?
if (!mysqli_connect_error()) {
// (6) Kan de juiste MySQL-karakterset worden ingesteld?
if (mysqli_set_charset($link, 'utf8')) {
$_POST['bloopp'] = mysqli_real_escape_string($link, $_POST['bloopp']);
// Hier een prepared statement opstellen en uitvoeren.
// <...>
}
}
}
}
?>
Ik heb inderdaad weinig kennis van beveiliging. Nu weet ik hoe ik duidelijk een script moet opstellen!
Beste Ward
Hartelijk dank voor het opstellen van een veilige code! Ik zal deze zo onmiddellijk veranderen!
Op de regel 'hier een prepared statement opstellen en uitvoeren', kan ik mijn eigenlijke code uitvoeren, zoals het controleren of het tijdverschil met de vorige bloopp groot genoeg is en vervolgens $_POST['bloopp'] naar de database verzenden?
Code (php)
1
2
3
2
3
$check="SELECT TIMESTAMPDIFF(MINUTE, send_time, CURRENT_TIMESTAMP) AS 'diff' FROM bloopp WHERE email = '$email' ORDER BY bloopp_id DESC LIMIT 1";
$res = mysqli_query($link, $check) or die("Error " . mysqli_error($res));
$data = mysqli_fetch_array($res, MYSQLI_ASSOC);
$res = mysqli_query($link, $check) or die("Error " . mysqli_error($res));
$data = mysqli_fetch_array($res, MYSQLI_ASSOC);
Nogmaals erg bedankt! Het is altijd fijn om zeker te zijn dat je website veilig is! ;-)
Met vriendelijke groet
Sven
Je gooit er ineens ook een onbekende en ongecontroleerde variabele $email in.
Wat Erwin zegt dus: probeer eerst te begrijpen wat je per regel doet.
Sven Thijssen op 09/11/2013 16:40:02:
Nogmaals erg bedankt! Het is altijd fijn om zeker te zijn dat je website veilig is! ;-)
Dat weet je helemaal niet....
Omdat ik niet wist wat een prepared statement is. Ik dacht dat dit gewoon de verdere code was, wat dus blijkbaar niet zo blijkt te zijn. Dit heb ik nu opgezocht op Wikipedia en ik heb dit gevonden:
Code (php)
1
2
2
$stmt = $dbh->prepare("SELECT * FROM users WHERE USERNAME = ? AND PASSWORD = ?");
$stmt->execute(array($username, $password));
$stmt->execute(array($username, $password));
Is zoiets in het algemeen wat U bedoelt?
Mijn kennis PHP is zeer gebrekkig en vind het meestal nogal moeilijk om ergens een verschil in te zien, zoals die array.
Ik hoop verder dat ik uit deze fouten kan leren. :)
Bedankt!
@Ward maakt het echt uit? Hoe dan ook moet de output van de query buffer nog geleegd worden
@Erwin lekker constructief, geef ook aan waarom dat dan niet zo is
prepared statement. De query wordt strikt gescheiden van de data die je er later insteekt: iets anders uitvoeren dan jouw query wordt onmogelijk.
Dus even praktisch: ja, herschrijf je MySQLi-code naar een prepared statement.
Juist als je niet exact weet wat je wanneer moet controleren, helpt een Dus even praktisch: ja, herschrijf je MySQLi-code naar een prepared statement.
Pieter Jansen op 09/11/2013 23:30:36:
@Erwin lekker constructief, geef ook aan waarom dat dan niet zo is
Lees mijn eerste post en je hebt je antwoord.
Oké, is zal binnenkort opnieuw schrijven als een prepared statement! Erg bedankt allemaal voor de hulp! ;)
Echt, beveiligen van je scripts is niet een kwestie van een paar trucjes uitvoeren en dan ben je veilig. Als dat zo was dan hoefde geen enkele website ooit meer gehackt te worden. Helaas is dat niet zo. Er zijn altijd uitzonderingen en als je die niet weet ben je nog net zo kwetsbaar.
Maar goed, uit je totale gebrek aan serieuze reactie op mijn opmerkingen ga ik ervanuit dat het je blijkbaar geen bal uitmaakt. Prima, dan ga ik verder ook niet aan een dood paard trekken.
Let er overigens ook op dat de prepared statements in MySQLi gewooon twee queries zijn, want die zijn server-side.
Uit de context kan ik afleiden dat ik een prepared statement gebruik als laatste stap om te controleren of een variabele veilig of onveilig is. Wat me nog onduidelijk is, is of de gehele prepared statement de query vervangt of dit nog eens extra moet opgegeven worden.
Ik vind het spijtig dat ik misschien een verkeerde indruk heb opgewekt, maar ik apprecieer zeker uw hulp. Het neemt soms enige tijd voor mij om alles te begrijpen en te combineren met school.
Sven
Het grote voordeel van een prepared statement is dat deze het mogelijk maakt om grote aantallen insert, update of delete acties achter elkaar uit te voeren, met telkens andere data, zonder dat elke keer de query opnieuw hoeft te worden aangemaakt. Heb je dus vele identieke queries achter elkaar dan scheelt dit veel tijd. Voor eenmalige queries is het eigenlijk helemaal niet bedoelt en kost het alleen maar tijd.
Waarom het dan toch wordt aangeraden is omdat een prepared statement een bijkomend voordeel heeft, namelijk dat er door de manier van uitvoeren van de query, geen sql injectie meer mogelijk is. Omdat de query instructies en de data strikt gescheiden zijn, kan een sql injectie poging geen effect hebben op de query instructies. Maar anders dan dat biedt een prepared statement geen enkele beveiliging op andere mogelijke aanvallen. Je gebruikt in je allereerste post bijvoorbeeld htmlspecialchars. Waarom doe je dat? Normaal gesproken doe je dat om jezelf te beschermen tegen XSS of html injectie (en dan niet voor het invoeren in de database, maar na het er weer uithalen). Een prepared statement zal hier niet bij helpen. Hoe ga je dit nu tegengaan, of was je je er uberhaupt wel van bewust dat je dat daarvoor gebruikte?
Daarom: begrijp wat je doet en 'sleur en pleur' niet zomaar code zonder te weten wat het doet en, vooral, wat het niet doet.
U hebt me absoluut duidelijk gemaakt wat prepared statements inhouden. Ik wist ook niet dat htmlspecialchars bij de opgehaalde gegevens toegepast moest worden.
Ik heb in elk geval geleerd minder snel conclusies te nemen ;-).
Ik ben U ook voor deze uitgebreide en duidelijke uitleg zeer dankbaar!
Mvg Sven