PFZ.nl - PHP Community: Veiligheid van website door filteren POST / GET / REQUEST_URI - Discussie - Forum - PFZ.nl - PHP Community

Je kunt niet antwoorden op dit topic
#1 06-01-2012 11:28
  • Remi R
  • Groep: Forumleden
  • Posts: 18
  • Actief sinds: 09-03-2004
Hey Scripters,

om de veiligheid van mijn websites te verbeteren (voornamelijk tegen SQL injecties) zat ik er aan te denken om een aantal zaken in mijn sites te controleren.

Uiteraard zorg ik dat alle invoer goed wordt gecheckt en gefilterd, maar eigenlijk zou ik dit willen automatiseren over de gehele website. Dit wilde ik doen door een PHP script te laden vóórdat de pagina opent. Dit kan door .HTACCESS aan te passen met een regel:
1
php_value auto_prepend_file veiligheid.php


Hier in wilde ik de array $_GET en $_POST filteren op bekende SQL commando's (select, update, delete, truncate, --, union, etc etc.). Ditzelfde wilde ik doen met de $_SERVER["REQUEST_URI"] doen.


Ik ben alleen niet zó behendig met Arrays dat ik dergelijke zaken er uit kan filteren, maar toch alle array keys in stand kan houden. De bedoeling is dus dat de rest van de info in de array in tact blijft, enkel de "select" / "update" etc woorden er uit worden gefilterd.

Voorbeeld:
Als iemand een form veld invult: "dit is een test select from table test",
dan moet overblijven: "dit is een test from table test" (hij filtert 'select')


Ik hoop veel injecties hiermee te voorkomen.

Ik ben benieuwd wat jullie visie hier op is.

Bedankt!

#2 06-01-2012 12:02
En stel dat iemand nu gewoon in een normale zin het woord 'select' of 'update' wil gebruiken in een form? Dan klopt die hele zin niet meer.

#3 06-01-2012 12:17
  • Remi R
  • Groep: Forumleden
  • Posts: 18
  • Actief sinds: 09-03-2004
Hey Ramon,

Correct. Echter zijn dergelijke woorden op deze site niet van toepassing (webshop).
Dus die zouden sowieso geen resultaten opleveren. Daar is over nagedacht.

#4 06-01-2012 12:21
  • Jason
  • Groep: Forumleden
  • Posts: 445
  • Actief sinds: 12-03-2011

Bekijk Post Op 06-01-2012 11:28 schreef Remi R:

Ik hoop veel injecties hiermee te voorkomen.
Wat is er mis met prepared statements? Dat is bewezen techniek en absoluut niet te hacken.

Daarnaast is het te testen door de querylog aan te zetten van jouw database, alle queries met hardcoded parameters geven een potentieel lek aan. Dit kun je dus ook checken op een productieserver, gewoon de loggings uitlezen. Jouw code is niet goed te testen, wanneer jij een item vergeet op te noemen in jouw validatiescript (en daar lijkt het nu al op!) is jouw code nog steeds lek. Querylogs heb je in jouw geval ook niets aan, jij ziet niet het verschil tussen een veilige en onveilige query.

Je probeert het wiel nogmaals uit te vinden en je hebt nu een gebroken vierkant wiel gemaakt...

#5 06-01-2012 12:33
  • Remi R
  • Groep: Forumleden
  • Posts: 18
  • Actief sinds: 09-03-2004
Hey Jason,

Goed punt, mogelijk een optie voor een volgend project, maar de huidige website is een bestaande site die gebruik maakt van de requliere mysql opdrachten. Het is niet mogelijk om de site nu om te zetten naar de veiligere Prepared statements.

Ik verwacht geen directe aanvallen op de site, maar de geautomatiseerde kan je bijna niet voorkomen. Daarom zou ik standaard opdrachten zoals 'show tables' en dergelijke willen blokkeren in de URL, POST en GET informatie.

Om mijn vraag enigszins te versimpelen;
1
2
3
$arrayx[test1]='aap noot mies';
$arrayx[info2]='de aap valt door de mand';
$arrayx[3]='Test een twee drie';


Ik wil dat er in die array geen 'aap' mag voorkomen, maar de keys en de rest van de tekst moet intact blijven. Welke techniek kan ik dan het beste gebruiken (snelste, zuinigste, efficientste)

#6 06-01-2012 12:45
  • Jason
  • Groep: Forumleden
  • Posts: 445
  • Actief sinds: 12-03-2011

Bekijk Post Op 06-01-2012 12:33 schreef Remi R:

Hey Jason,

Goed punt, mogelijk een optie voor een volgend project, maar de huidige website is een bestaande site die gebruik maakt van de requliere mysql opdrachten. Het is niet mogelijk om de site nu om te zetten naar de veiligere Prepared statements.
Niet mogelijk of heeft het geen prioriteit?

En waarom wil je geen mysql_real_escape_string() gebruiken? Dat is niet ideaal, maar nog altijd een heel stuk beter dan datgene wat je nu probeert te maken. Gebruik ctrl-f om te zoeken in jouw code naar SQL en check of de input parameters wel met mysql_real_escape_string én quotes ' worden beveiligd.

Fout:
1
2
3
<?php
$query = "SELECT kolom FROM tabel WHERE id = ".$id;
?>


Goed:
1
2
3
<?php
$query = "SELECT kolom FROM tabel WHERE id = '".mysql_real_escape_string($id)."'"; // let op de enkele QUOTES !
?>


$id mag je even vervangen door 1 or 1=1, dan krijg je een idee hoe simpel SQL injection is en waarom jouw code absoluut niet werkt.

#7 06-01-2012 12:56
  • Remi R
  • Groep: Forumleden
  • Posts: 18
  • Actief sinds: 09-03-2004
Hallo Jason,

Al mijn invoer wordt gefilterd, maar een fout zit in een klein hoekje. Ik probeer enkel de risico's nóg verder te verkleinen. Ik ben op de hoogte van methodes die worden gebruikt bij SQL injectie en hoe die queries worden opgebouwd.

de woorden / combinatie van woorden die ik ga filteren worden niet, en zullen ook niet gebruikt worden, bij gebruik van deze website.

#8 06-01-2012 13:05
Zijn woorden als 'update' niet van toepassing in een webshop? Lijkt me juist van wel! Wat als iemand iets wilt vertellen over een 'update' van bijv. software? Of een 'update' wil geven over het verloop van leveringsproces?

Er zijn maar twee (goede) manieren op SQL injectie te voorkomen: Dat is prepared statements gebruiken, of *escape_string() in combinatie met enkele quotes gebruiken.

Alle andere dingen die je erbij gaat verzinnen in onnodig, onlogisch en vast nog wel een aantal andere 'on'-dingen.

Verder verplaats ik dit topic naar Discussie aangezien je niet op zoek bent naar een script. Het is meer een vraag van wat nu de beste manier is tegen sql injectie.

#9 06-01-2012 13:10
  • Jason
  • Groep: Forumleden
  • Posts: 445
  • Actief sinds: 12-03-2011

Bekijk Post Op 06-01-2012 12:56 schreef Remi R:

Al mijn invoer wordt gefilterd, maar een fout zit in een klein hoekje.
En dat is precies het probleem van jouw filter!

Quote

Ik probeer enkel de risico's nóg verder te verkleinen.
Alleen steek je jouw tijd in de verkeerde code: Nieuwe code met nieuwe problemen en niet het reviewen van bestaande code met minder problemen. Waarom wil je de bestaande code niet gaan verbeteren? Daar zitten de problemen blijkbaar, dan zul je ze daar ook moeten verhelpen. Een code review, waar ook tools voor te vinden zijn, kost niet veel tijd maar je kunt hier wel veel mee winnen.

Code verbeter je niet door méér code te schrijven maar door bestaande code te verbeteren en op te schonen. Soms heb je daar meer code voor nodig, maar vaak is het minder.

Quote

Ik ben op de hoogte van methodes die worden gebruikt bij SQL injectie en hoe die queries worden opgebouwd.
Dan ben je ook op de hoogte van het feit dat er veel meer mogelijk is dan alleen de filters die jij hier benoemt en dat je het daadwerkelijke lek niet verhelpt.

Sterkte.

#10 06-01-2012 13:17
  • Remi R
  • Groep: Forumleden
  • Posts: 18
  • Actief sinds: 09-03-2004
Hallo Sjaak,

Bedankt. Gezien de omvang van de huidige site (ik heb het beheer overgenomen) is het te risicovol om alle queries om te gooien naar de 'veiligere' prepared statements. Ook overal de mysql_real_escape_string toevoegen is niet te doen gezien de omvang.

Het is een webshop, geen forum/chatbox. Er worden geen berichten geplaatst door gebruikers. Waar op ik filter zal ook niet direct update zijn, maar bijv. tabelnamen, database naam, list table etc. Het is niet een kwestie van niet willen, maar als ik alle queries moet gaan aanpassen die aanwezig zijn in de diverse scripts, dan is de kans op typfouten te groot.

De verplaatsing naar discussie lijkt me hierdoor onterecht. Ik zoek nu een alternatieve oplossing om de site enigszins te beveiligen tot moment van herschrijven van de totale site. Daarin zal ik zeker de tips gebruiken, maar tot die tijd moet ik iets anders.

Daarom nogmaals:

Om mijn vraag enigszins te versimpelen;
1
2
3
$arrayx[test1]='aap noot mies';
$arrayx[info2]='de aap valt door de mand';
$arrayx[3]='Test een twee drie';

#11 06-01-2012 13:22

Quote

list table etc.
Dan moet je gebruikers aanmaken die daarvoor niet eens de rechten hebben. Dat hoort een gewone gebruiker niet eens te mogen/kunnen doen.

Quote

Het is niet een kwestie van niet willen, maar als ik alle queries moet gaan aanpassen die aanwezig zijn in de diverse scripts, dan is de kans op typfouten te groot.
Wat is er mis met kopiëren plakken? Je moet één functienaam typen...
Alle queries heb je zo gevonden met een find (of find&replace)-commando. Met de tijd die je nu steekt in dit topic en de code die je hierna had willen schrijven om je 'probleem' op te lossen, had je makkelijk al 4/5 deel beveiligd kunnen hebben.

Quote

Ik zoek nu een alternatieve oplossing om de site enigszins te beveiligen tot herschrijven van de totale site.
Dat is het hele punt nu. Er is geen alternatief.

#12 06-01-2012 14:15
  • Jason
  • Groep: Forumleden
  • Posts: 445
  • Actief sinds: 12-03-2011

Bekijk Post Op 06-01-2012 13:22 schreef Sjaak Ringens:

Dat is het hele punt nu. Er is geen alternatief.
Maar wel een wassen neus!

En dat is wat de TS zoekt. Dat het zijn website niet veiliger maakt, dat is niet anders.

#13 06-01-2012 14:45
/offtopic
Er is altijd wel wat bedenken dat het veiliger maakt, met onderstaande functie bijv. zal er geen sql injectie meer mogelijk zijn:

Spoiler

#14 06-01-2012 15:00
  • Martin P
  • Groep: Moderators
  • Posts: 3645
  • Actief sinds: 19-04-2007

Bekijk Post Op 06-01-2012 14:17 schreef Remi R:

Gezien de omvang van de huidige site (ik heb het beheer overgenomen) is het te risicovol om alle queries om te gooien naar de 'veiligere' prepared statements. Ook overal de mysql_real_escape_string toevoegen is niet te doen gezien de omvang.
Toch is dat de enige manier om SQL-injectie 100% te voorkomen. Het is een veelgemaakte beginnersfout om te denken dat je met het eenmalig uitvoeren van een magische functie in één keer SQL-injectie te voorkomen. Je bent helaas niet de eerste die met dit idee rondloopt en je zult ook helaas vast niet de laatste zijn. Het omzetten naar de veiliger (zonder quotes, want het is een vaststaand feit dat het veiliger is) prepared statements of gebruik van mysql_real_escape_string() is nu eenmaal de enige optie. Als het omzetten risicovol is, moet je je eens goed bedenken welk risico je nu loopt (en al helemaal omdat je aangeeft dat het om een webshop gaat...). Blijkbaar is je applicatie op dit moment zo lek als een zeef, dus je kunt er alleen maar op vooruit gaan bij het toepassen van prepared statements of mysql_real_escape_string().

Samengevat:
Er bestaat geen superfunctie om SQL-injectie in één keer te voorkomen. Hoe eerder je dat uit je hoofd zet, des te eerder kun je je gaan richten op echte beveiliging (dus prepared statements of mysql_real_escape_string()).

Bekijk Post Op 06-01-2012 15:45 schreef Sjaak Ringens:

Er is altijd wel wat bedenken dat het veiliger maakt, met onderstaande functie bijv. zal er geen sql injectie meer mogelijk zijn
Dat en nog veel meer niet :D
Handleidingen zijn er niet voor niets, gebruik ze dus :)
HTML5 ~ CSS ~ PHP ~ MySQL ~ SQL-injectie bestaat meer dan 13 jaar

#15 13-01-2012 13:40

Quote

Er bestaat geen superfunctie om SQL-injectie in één keer te voorkomen.
Onderstaande functie roep ik aan op elke pagina.
Als er $_POST data is, dan wordt die met mysql_real_escape_string() gefilterd.
(zonodig kun je dit ook voor $_GET toepassen).

Daarmee ben ik toch in één klap van SQL-injectie af?
Of zie ik iets over het hoofd?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$_POST[ww] = "sql 'injectie";

function beveiligPost($_POST) { 
    
    foreach($_POST as $key => $value) {
        $_POST[$key] = mysql_real_escape_string($value);
    }
    return $_POST;
}

if ($_POST) {

    $_POST = beveiligPost($_POST);   
}

print $_POST[ww];

#16 13-01-2012 13:51
  • Gary vd H
  • Groep: Forumleden
  • Posts: 957
  • Actief sinds: 26-01-2005

Bekijk Post Op 13-01-2012 14:40 schreef peter muller:

Onderstaande functie roep ik aan op elke pagina.
Als er $_POST data is, dan wordt die met mysql_real_escape_string() gefilterd.
(zonodig kun je dit ook voor $_GET toepassen).

Daarmee ben ik toch in één klap van SQL-injectie af?
Of zie ik iets over het hoofd?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$_POST[ww] = "sql 'injectie";

function beveiligPost($_POST) { 
    
    foreach($_POST as $key => $value) {
        $_POST[$key] = mysql_real_escape_string($value);
    }
    return $_POST;
}

if ($_POST) {

    $_POST = beveiligPost($_POST);   
}

print $_POST[ww];
En ook dat is onjuist, mysql_real_escape_string gebruik je op 1 plek, in je mysql query.

Nu pak je alle POST variabelen die niet naar de server hoeven aan welke misschien nooit naar mysql
worden gestuurd. Daarnaast zit dan een typfout in een enorm klein hoekje, met 1 letter maak je je hele website,
elke query, gevoelig voor SQL injectie.

Gebruik prepared statements.. of doe een find replace met mysql_real_escape_string

#17 13-01-2012 14:58

Quote

Nu pak je alle POST variabelen die niet naar de server hoeven aan welke misschien nooit naar mysql worden gestuurd.
Klopt. Maar wat is daar mis mee?
Processor belasting verwaarloosbaar klein.
Daarnaast.... nagenoeg alle POST variabelen gebruik ik voor de database.
(maar ook al zou dat anders zijn.... belasting is verwaarloosbaar klein)

Quote

Daarnaast zit dan een typfout in een enorm klein hoekje, met 1 letter maak je je hele website,
elke query, gevoelig voor SQL injectie.
Dus ook andersom?
Zonder typefout in die functie maak je de hele website, elke query ongevoelig voor SQL injectie?

Een typefout zit altijd in een klein hoekje. Voordeel is dat ik nu in één klein hoekje moet zoeken om te kijken of of het goed werkt. Anders moet ik in 1000 kleine hoekjes zoeken of ik ergens mysql_real_escape_string() vergeet....

Ik begrijp de voordeleen van prepared statements.
Mysql_real_escape_string() werkt ook afdoende tegen sql injectie.
Wat is er vervolgens mis met deze functie?
Als ik zaken over het hoofd zie, dan hoor ik het graag....

#18 13-01-2012 16:01
  • Ivo P.
  • Groep: Verenigingsleden
  • Posts: 2802
  • Actief sinds: 17-01-2002
De functie die Peter aanlevert, werkt bijvoorbeeld al niet voor array's


<input name="keuzeopties[]" value="1">

Sterker: hij maakt de gekozen opties waarschijnlijk gewoon kapot, ipv iets te beveiligen.

Het is ook fijn als alle data die anders gebruikt wordt dan voor inserten in een daabase, bijvoorbeeld voor het versturen van een emailtje, nu ineens voorzien is van allerlei \\\\ in de teksten.
Ivo Peters
Developer en systeembeheerder @ PeHa ICT Services. blog.peha-ict.nl

#19 13-01-2012 16:02
  • Martin P
  • Groep: Moderators
  • Posts: 3645
  • Actief sinds: 19-04-2007

Bekijk Post Op 13-01-2012 14:40 schreef peter muller:

Onderstaande functie roep ik aan op elke pagina.
Als er $_POST data is, dan wordt die met mysql_real_escape_string() gefilterd.
(zonodig kun je dit ook voor $_GET toepassen).

Daarmee ben ik toch in één klap van SQL-injectie af?
Of zie ik iets over het hoofd?
Je ziet meerdere dingen over het hoofd :)
  • $_GET en $_POST kunnen arrays bevatten, dus je kunt nooit op deze manier met een foreach door die variabelen heenlopen, want mysql_real_escape_string() verwacht altijd(!) een string en niet een array
  • Waar dwing je af dat er een databaseverbinding is (die je nodig hebt voor mysql_real_escape_string())?
  • Hoe ga je $_POST- en $_GET-variabelen valideren als je weet dat mysql_real_escape_string() bepaalde tekens toevoegt aan een string?
  • Hoe weet je 100% zeker dat je alleen de "values" van de $_POST en $_GET in een query gebruikt en niet toevallig ook de keys?
  • Is een ' in een string per definitie iets dat je uit wilt sluiten?
  • Hoe kun je aan een query (zonder dat je zicht hebt op deze routine) 100% zeker weten dat SQL-injectie onmogelijk is? Het kan zomaar zijn dat iemand (om wat voor reden dan ook) even commentaar heeft gemaakt van dat regeltje en paf... lek is je website.
  • Wat doe je als je $_POST-data voor andere doeleinden wilt gebruiken dan voor een database? Dan zit je met die extra rommel in bijvoorbeeld e-mails, XML, CSV, enz.

Er zijn vast nog veel meer zaken aan te halen, maar dit zijn in ieder geval wat dingetjes die zo snel bij me opkomen.

EDIT:
  • We vergeten $_SESSION en $_COOKIE? Ook daarlangs kan SQL-injectie worden uitgevoerd

Bekijk Post Op 13-01-2012 15:58 schreef peter muller:

Een typefout zit altijd in een klein hoekje. Voordeel is dat ik nu in één klein hoekje moet zoeken om te kijken of of het goed werkt. Anders moet ik in 1000 kleine hoekjes zoeken of ik ergens mysql_real_escape_string() vergeet....
Een typefout zit altijd in een klein hoekje. Escapen van data om weer te geven in je HTML-code moet je ook altijd op de plaats zelf doen of haal je dan ook direct alle data door htmlspecialchars() heen? Op die manier hoef je niet meer bang te zijn voor XSS (Cross Site Scripting), maar vermink je ook gegarandeerd je data.
Handleidingen zijn er niet voor niets, gebruik ze dus :)
HTML5 ~ CSS ~ PHP ~ MySQL ~ SQL-injectie bestaat meer dan 13 jaar

#20 13-01-2012 17:44
dank!


Inloggen wachtwoord vergeten? Aanmelden