Ben ik beschermd tegen SQL injection?
Heet het eerste PHP-bestand test.php?
Staat de foutafhandeling voor de database in login.php?
Wat is issset.php?
Staat de foutafhandeling voor de database in login.php?
Wat is issset.php?
Gewijzigd op 17/12/2014 17:02:48 door Ward van der Put
Het eerste bestand heet test.php
in mijn login php file staat gewoon:
$db_host = "localhost";
$db_username = " blablabla";
$db_password = " blablabla";
$db_database = "blablabla";
issset.php is mijn php code die ik gelinkt heb
in mijn login php file staat gewoon:
$db_host = "localhost";
$db_username = " blablabla";
$db_password = " blablabla";
$db_database = "blablabla";
issset.php is mijn php code die ik gelinkt heb
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
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
<?php
require_once 'login.php';
$db_con= new mysqli($db_host, $db_username, $db_password, $db_database);
$db_con->set_charset("utf8");
if($db_con->connect_error) die ("(" . $db_con->connect_error . " Error during connection");
if(isset($_POST['zoeken'])){
$zoeknaam = $_POST['Zoek']; // declare the input here
$stmte = $db_con->prepare("SELECT * FROM customers WHERE Voornaam = ?");
$stmte->bind_param("s", $zoeknaam); // then use inside here
$stmte->execute();
$rows = $stmte->num_rows;
if($stmte->num_rows > 0) {
$results = $stmte->get_result();
while($row = $results->fetch_assoc()) {
echo $row['Achternaam'] . '<br/>';
// and other columns
}
}
}
?>
require_once 'login.php';
$db_con= new mysqli($db_host, $db_username, $db_password, $db_database);
$db_con->set_charset("utf8");
if($db_con->connect_error) die ("(" . $db_con->connect_error . " Error during connection");
if(isset($_POST['zoeken'])){
$zoeknaam = $_POST['Zoek']; // declare the input here
$stmte = $db_con->prepare("SELECT * FROM customers WHERE Voornaam = ?");
$stmte->bind_param("s", $zoeknaam); // then use inside here
$stmte->execute();
$rows = $stmte->num_rows;
if($stmte->num_rows > 0) {
$results = $stmte->get_result();
while($row = $results->fetch_assoc()) {
echo $row['Achternaam'] . '<br/>';
// and other columns
}
}
}
?>
Gewijzigd op 17/12/2014 21:45:28 door Michael Desmadril
Even een vraagje over het SQL-injection probleempje. -->
Buiten dat het moet gebeuren voor je login variabelen , om ze af te vangen met 'mysgl_real_escape_string', moet het ook voor alle andere velden in je systeem. Dus bij registratie van NAW, Bankrekeningnummer (IBAN), etc, ??
Buiten dat het moet gebeuren voor je login variabelen , om ze af te vangen met 'mysgl_real_escape_string', moet het ook voor alle andere velden in je systeem. Dus bij registratie van NAW, Bankrekeningnummer (IBAN), etc, ??
Kort antwoord: Op alle data die een gebruiker maar invoert of aan kan passen moet je controleren of de inhoud schadelijke data bevat.
Ik neem ook dat dat geldt voor je NAW-gegevens en bankrekeningsnummers.
Dus ja, ook hierbij geldt dat je het moet escapen. Verder is gebruik van de mysql_*() extentie afgeraden, en wordt PDO of MySQLi aangeraden.
Ik neem ook dat dat geldt voor je NAW-gegevens en bankrekeningsnummers.
Dus ja, ook hierbij geldt dat je het moet escapen. Verder is gebruik van de mysql_*() extentie afgeraden, en wordt PDO of MySQLi aangeraden.
Gewijzigd op 05/05/2015 16:27:33 door - Ariën -
Maar je kan die velden toch ook wel afvangen met javascript ?
Ja, maar Javascript werkt lokaal, en is uit te zetten/manipuleren.
Dus als je valideert:
- Validatie reeks controle (mailadres, telefoonnummer, website, etc...)
- SQL injection filteren
- Input validatie met JavaScript/HTML5
Dus als je valideert:
- Validatie reeks controle (mailadres, telefoonnummer, website, etc...)
- SQL injection filteren
- Input validatie met JavaScript/HTML5
Gewijzigd op 05/05/2015 16:35:16 door - Ariën -
Duidelijke taal Aar ! Dank je.
Waarom zou je het risico lopen dat ergens $db_username of $db_password wordt weergeven?
Zet die gewoon NIET in variabelen, maar hardcoded in de code.
Nu doe je dat ook, maar wel via een variabele. Geen enkel voordeel, alleen maar mogelijke nadelen.
Dus doe het zo:
Zet die gewoon NIET in variabelen, maar hardcoded in de code.
Nu doe je dat ook, maar wel via een variabele. Geen enkel voordeel, alleen maar mogelijke nadelen.
Dus doe het zo:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
// require_once 'login.php';
$db_con= new mysqli("localhost", "gebruikerX", "kdeN3nen_83", "database");
$db_con->set_charset("utf8");
?>
// require_once 'login.php';
$db_con= new mysqli("localhost", "gebruikerX", "kdeN3nen_83", "database");
$db_con->set_charset("utf8");
?>
Gewijzigd op 05/05/2015 17:28:25 door Eddy E
Waarom zou je die variabelen ook echo'en? Je kan ze ook direct weer unset()-en nadat je ze gebruik hebt in de connectie. Dan kan niemand ze echo'en via een exploit ofzo.
Verder was die reactie waarop je reageert van iemand anders, en inmiddels gedateerd. Dit even ter informatie.
Verder was die reactie waarop je reageert van iemand anders, en inmiddels gedateerd. Dit even ter informatie.
Gewijzigd op 05/05/2015 17:28:35 door - Ariën -
Eddy E op 05/05/2015 17:22:08:
Waarom zou je het risico lopen dat ergens $db_username of $db_password wordt weergeven?
Zet die gewoon NIET in variabelen, maar hardcoded in de code.
Zet die gewoon NIET in variabelen, maar hardcoded in de code.
Als je je daar druk om moet maken, heb je problemen van een hele andere orde. Daarmee geef je in feite toe dat je niet in kunt staan voor de veiligheid van je eigen code.
Het is heel goed denkbaar dat je dit soort parameters wilt vangen in variabelen, bijvoorbeeld in een configuratie-bestand dat verschillende waarden heeft voor een vaste set parameters op grond van bijvoorbeeld een hostname.
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
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
<?php
switch ($_SERVER['HTTP_HOST']) {
// development
case 'mysite.dev':
$config->database = array(
'user' => '...',
'pass' => '...',
'database' => '...',
// etc...
);
// more host specific config...
break;
// production
case 'mysite.com':
$config->database = array(
'user' => '...',
'pass' => '...',
'database' => '...',
// etc...
);
// more host specific config...
break;
default:
die('unknown hostname');
}
?>
switch ($_SERVER['HTTP_HOST']) {
// development
case 'mysite.dev':
$config->database = array(
'user' => '...',
'pass' => '...',
'database' => '...',
// etc...
);
// more host specific config...
break;
// production
case 'mysite.com':
$config->database = array(
'user' => '...',
'pass' => '...',
'database' => '...',
// etc...
);
// more host specific config...
break;
default:
die('unknown hostname');
}
?>
Zoals gezegd, als iemand het op een of andere manier voor elkaar krijgt om de inhoud van $config af te drukken, dan wil dat zeggen dat iemand op een of andere manier PHP-code kan uitvoeren. Dan ben je al nat.
Dit klinkt als een soort mantra wat je je ooit hebt aangeleerd, maar waarvan je niet meer precies weet waarom het ook alweer zo zou zijn.
Ontopic: ik vind het grappig dat er zoveel nadruk wordt gelegd op het escapen van van alles en nog wat op het gebied van MySQL, en vervolgens druk je data die uit je database komt gewoon af, zonder deze te escapen :D. Dan mis je toch een beetje het punt geloof ik.
Vertrouw nooit user input. Ook / vooral niet nadat je deze hebt opgeslagen in je database lol.
SQL Injection is wat het aangeeft: dat iemand zonder het weten of te mogen data kan aanleveren die door de database wordt herkend als SQL. Ofwel dat het niet duidelijk is voor de database welk deel nu de SQL code is, en welk deel de data. Het grootste probleem is dat je als PHP programmeur soms zoveel met queries werkt dat het een klus kan zijn om alle queries adequaat te beschermen.
Meestal wordt aangeraden om mysqli_real_escape_string() te gebruiken. Maar dat werkt niet altijd, bijvoorbeeld als je een ID wilt escapen en iemand gebruikt '1 OR 1=1'. Dan moet je in ieder geval nog alle data checken op type, dat is al een hele klus.
Daarom is de enige aanbevolen manier om met prepared statements te werken. Omdat het aanbieden van de query en de data in gescheiden stappen gaat, is er voor de database geen misverstand wat precies de query is en wat de data is.
Meestal wordt aangeraden om mysqli_real_escape_string() te gebruiken. Maar dat werkt niet altijd, bijvoorbeeld als je een ID wilt escapen en iemand gebruikt '1 OR 1=1'. Dan moet je in ieder geval nog alle data checken op type, dat is al een hele klus.
Daarom is de enige aanbevolen manier om met prepared statements te werken. Omdat het aanbieden van de query en de data in gescheiden stappen gaat, is er voor de database geen misverstand wat precies de query is en wat de data is.
Laatste tijden veel aan mijn PHP-scrips verbeterd.
1) Quote's regeltjes consequent overal toegepast (wanneer enkele quotes en wanneer dubbele quotes)
2) Overgestapt van PHP 5.3.29 naar PHP 5.5.24
3) MySQL-statements omgezet naar MySQLi
4) SQL-injection d.m.v. mysqli_real_escape_string afgevangen
5) Password encryptie toegepast (password_hash, password_verify, password_needs_rehash)
6) Javascripts verbeterd (o.a. IBAN check toegevoegd)
Nu zit ik nog met 2 puntjes:
1) Ik wil 'prepared statements' gaan toepassen om het nog veiliger te maken.
Mijn vraag is: Is het zinvol om gewoon alle SQL-statements om te zetten naar een versie van prepared statements ? Kan ik dus al mijn mysqli_real_escape_string-statements er weer uitgooien ?
2) Ik zit nog met een vraag (waarschijnlijk een domme vraag).
Ik heb middels javascript alle velden gecontroleerd (of het een juist IBAN-nummer is, of het veld niet leeg is, of de datum-va/dataum-tm goed zijn ingevuld, etc...). Moet ik nu alle javascript-controles ook nog eens bij de PHP-validaties doen? Want ik begrijp dat je javascript uit kan zetten en dan worden er geen javascript-validaties gedaan. Maar is dit niet allemaal een beetje dubbel op ??
Toevoeging op 17/05/2015 16:05:18:
3de puntje:
AJAX maakt gebruik van javascript. Wanneer javascript wordt uit gezet in de browser werkt AJAX dan ook niet meer ?
1) Quote's regeltjes consequent overal toegepast (wanneer enkele quotes en wanneer dubbele quotes)
2) Overgestapt van PHP 5.3.29 naar PHP 5.5.24
3) MySQL-statements omgezet naar MySQLi
4) SQL-injection d.m.v. mysqli_real_escape_string afgevangen
5) Password encryptie toegepast (password_hash, password_verify, password_needs_rehash)
6) Javascripts verbeterd (o.a. IBAN check toegevoegd)
Nu zit ik nog met 2 puntjes:
1) Ik wil 'prepared statements' gaan toepassen om het nog veiliger te maken.
Mijn vraag is: Is het zinvol om gewoon alle SQL-statements om te zetten naar een versie van prepared statements ? Kan ik dus al mijn mysqli_real_escape_string-statements er weer uitgooien ?
2) Ik zit nog met een vraag (waarschijnlijk een domme vraag).
Ik heb middels javascript alle velden gecontroleerd (of het een juist IBAN-nummer is, of het veld niet leeg is, of de datum-va/dataum-tm goed zijn ingevuld, etc...). Moet ik nu alle javascript-controles ook nog eens bij de PHP-validaties doen? Want ik begrijp dat je javascript uit kan zetten en dan worden er geen javascript-validaties gedaan. Maar is dit niet allemaal een beetje dubbel op ??
Toevoeging op 17/05/2015 16:05:18:
3de puntje:
AJAX maakt gebruik van javascript. Wanneer javascript wordt uit gezet in de browser werkt AJAX dan ook niet meer ?
Gewijzigd op 17/05/2015 14:13:47 door Paco de Wulp
>> 1) Ik wil 'prepared statements' gaan toepassen om het nog veiliger te maken.
Mijn vraag is: Is het zinvol om gewoon alle SQL-statements om te zetten naar een versie van prepared statements ?
Nee, het gaat alleen om de injectie van buitenaf. SQL-expressies die geen output van buitenaf bevatten, kunnen niet met SQL-injectie worden misbruikt.
>> Ik heb middels javascript alle velden gecontroleerd (of het een juist IBAN-nummer is, of het veld niet leeg is, of de datum-va/dataum-tm goed zijn ingevuld, etc...). Moet ik nu alle javascript-controles ook nog eens bij de PHP-validaties doen?
Ja. Niet alleen kan JavaScript worden uitgezet: een hacker kan elk HTTP-request veranderen. Alle input die van buiten komt is dus bij voorbaat verdacht, totdat je met controles hebt bewezen dat deze ermee door kan.
Mijn vraag is: Is het zinvol om gewoon alle SQL-statements om te zetten naar een versie van prepared statements ?
Nee, het gaat alleen om de injectie van buitenaf. SQL-expressies die geen output van buitenaf bevatten, kunnen niet met SQL-injectie worden misbruikt.
>> Ik heb middels javascript alle velden gecontroleerd (of het een juist IBAN-nummer is, of het veld niet leeg is, of de datum-va/dataum-tm goed zijn ingevuld, etc...). Moet ik nu alle javascript-controles ook nog eens bij de PHP-validaties doen?
Ja. Niet alleen kan JavaScript worden uitgezet: een hacker kan elk HTTP-request veranderen. Alle input die van buiten komt is dus bij voorbaat verdacht, totdat je met controles hebt bewezen dat deze ermee door kan.
Dank je @Ward.
ad.1)Maar wat is erop tegen om alles met prepared-statements doen? Het kan toch geen kwaad. Je hanteert dan wel tenminste overal dezelfde methodiek. Of heeft het andere consequenties voor bijvoorbeeld de performance, of is het niet sjiek om iets-wat overbodige statements in je code te hebben ?
ad.2)Dus eigenlijk kan je alle javascript checks skippen, want alles moet toch in PHP worden gecheckt. Eigenlijk zijn javascripts dus alleen maar voor een iets mooiere schermafhandeling, qua foutmeldingen en ander soort meldingen. Toch ?
ad.3) Maar hoe zit het dan met AJAX die ook gebruik maakt van javascript ?
ad.1)Maar wat is erop tegen om alles met prepared-statements doen? Het kan toch geen kwaad. Je hanteert dan wel tenminste overal dezelfde methodiek. Of heeft het andere consequenties voor bijvoorbeeld de performance, of is het niet sjiek om iets-wat overbodige statements in je code te hebben ?
ad.2)Dus eigenlijk kan je alle javascript checks skippen, want alles moet toch in PHP worden gecheckt. Eigenlijk zijn javascripts dus alleen maar voor een iets mooiere schermafhandeling, qua foutmeldingen en ander soort meldingen. Toch ?
ad.3) Maar hoe zit het dan met AJAX die ook gebruik maakt van javascript ?
1) Er is niets op tegen om alles met prepared statements te doen. Al zou het iets trager zijn dan merk je daar helemaal niets van. Maar Ward heeft gelijk. Vaste queries zonder variabelen van buitenaf zijn voor een buitenstaander ook niet te misbruiken.
2) Alles moet met PHP gevalideerd worden. Het is echter vaak wel gebruiksvriendelijk om ook javascript validatie te gebruiken. Denk bijv. aan een vakje dat direct rood wordt nadat de focus van het veld af is.
De gebruiker kan nu direct het vakje alsnog juist invullen en hoeft later niet nog een keer terug.
Persoonlijk vind ik dat met de komst van HTML5 de javascript validatie grotendeels weggelaten kan worden. Nu heb je immers de mogelijkheid om een input type "email" en "numeric" e.d. te maken.
3)Ook bij AJAX moet je serverside valideren en kun je om het gebruiksvriendelijker te maken ook clientside valideren.
2) Alles moet met PHP gevalideerd worden. Het is echter vaak wel gebruiksvriendelijk om ook javascript validatie te gebruiken. Denk bijv. aan een vakje dat direct rood wordt nadat de focus van het veld af is.
De gebruiker kan nu direct het vakje alsnog juist invullen en hoeft later niet nog een keer terug.
Persoonlijk vind ik dat met de komst van HTML5 de javascript validatie grotendeels weggelaten kan worden. Nu heb je immers de mogelijkheid om een input type "email" en "numeric" e.d. te maken.
3)Ook bij AJAX moet je serverside valideren en kun je om het gebruiksvriendelijker te maken ook clientside valideren.
Gewijzigd op 17/05/2015 19:57:43 door Frank Nietbelangrijk
Paco de Wulp op 17/05/2015 14:04:46:
4) SQL-injection d.m.v. mysqli_real_escape_string afgevangen
Mijn god daar gaan we weer.
mysqli_real_escape_string is geen wondermiddel.
Stel dat jij een query hebt waar je voor een zekere parameter een getal verwacht, zet je daar dan quotes omheen?
Bijvoorbeeld: SELECT * FROM users WHERE user_id = $x.
$x komt bijvoorbeeld uit $_GET['id'].
Als je geen quotes gebruikt doet je real_escape_string niets. Als $_GET['id'] "OR 1 = 1" bevat (zonder dubbele quotes) dan wordt er niets geescaped omdat er niets te escapen valt.
Als je wel quotes gebruikt... ik weet niet, het is wel "veilig" in combinatie met mysqli_real_escape_string() maar het is nogal onzinnig.
Als je prepared statement gebruikt... doe je een hoop werk voor niets als je het mij vraagt. prepare(), bind_param(), etc. Aint nobody got time fo dat.
Bottom line: als je een getal verwacht controleer dan op een getal. Oftewel filter je input. Als je invoer niet voldoet aan een zeker formaat dan hoef je ook geen query uit te voeren die niets oplevert.
Dank je @Frank. Duidelijk.
@Thomas, mij hoor je er niet meer over...ik snap het nu. Be Happy !!
@Thomas, mij hoor je er niet meer over...ik snap het nu. Be Happy !!
Ik zie nergens filter input, escape output staan dus ik behoud mij het recht voor enige reserveringen te hebben (en te houden) ten aanzien van bovenstaande stelling.
Je "regels" zijn ook voornamelijk gericht op het buiten houden van rotzooi, maar over een verdere behandeling van "user data" hoor ik je niet. Tenzij jij bepaalde gebruikers in je systeem/systemen vertrouwt (middels een soort van chain-of-trust waarbij privileges worden doorgegeven) moet je alle user data blijven behandelen als zijnde onbetrouwbaar, zelfs (en wellicht vooral) als deze opgeslagen is in je database.
Je "regels" zijn ook voornamelijk gericht op het buiten houden van rotzooi, maar over een verdere behandeling van "user data" hoor ik je niet. Tenzij jij bepaalde gebruikers in je systeem/systemen vertrouwt (middels een soort van chain-of-trust waarbij privileges worden doorgegeven) moet je alle user data blijven behandelen als zijnde onbetrouwbaar, zelfs (en wellicht vooral) als deze opgeslagen is in je database.
Ik neem alle hints, suggesties, tips mee. Wat een fantastische website is dit toch !
AJAX is ook maar een soort 2e 'headless' browser die op de achtergrond HTTP requests doet, net als de browser. Alleen dan gebeurt het met een XMLHTTPRequest (XHR) object, in plaats van dat de gebruiker een URL typt/klikt/afvuurt. Voor Javascript hoeft er verder niets speciaals gedaan te worden, zolang je de inputvariabelen maar controleert en schoont voordat je ze bij een SQL query in stopt. Hiervoor gelden dus dezelfde regels, en kan ik prepared statements aanbevelen.




