Loggen van SQL-injections

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

- Ariën  -
Beheerder

- Ariën -

12/10/2017 16:41:33
Quote Anchor link
Ik vroeg me af op er ook procedures bestaan die mogelijke SQL-injections kunnen loggen?

Natuurlijk is het de bedoeling dat alle input netjes met 'prepared statements' of $conn->real_escape_string() ge-escaped en dus beveiligd wordt, maar zijn er er ook mogelijkheden om verdachte queries te kunnen herkennen, zodat je wat extra informatie in een textfile kan opslaan?
Gewijzigd op 12/10/2017 16:42:17 door - Ariën -
 
PHP hulp

PHP hulp

06/11/2024 00:09:14
 
Rob Doemaarwat

Rob Doemaarwat

12/10/2017 19:45:22
Quote Anchor link
Ik controleer de $_SERVER['QUERY_STRING'] en de array_keys($_POST) op deze karakters ['\'','"','<','>'] (die gebruik ik zelf nooit in een URL query string of veldnaam). Als een gebruiker (IP-adres) hier "op scoort" krijgt ie een vinkje. Bij 5 vinkjes gaat ie een aantal uur in de ban.

In een aparte check, maar van hetzelfde laken het pak match ik deze ook nog met '/\\.\\.[\\\\\\/]/' (poging tot path traversal).
 
Toms Diner

Toms Diner

12/10/2017 22:05:35
Quote Anchor link
Al mijn $_POST en $_GET variabelen worden bij de eerste uitlezing schoongemaakt, en in een variabele geplaatst. Daar heb ik een vaste functie voor: $userinput = GetCleanedPostOrGet('gebruikersnaam');

In die functie is een array met verboden tekens, (" ' < > ^) en verdachte woorden (DROP DELETE WHERE <script> enzovoort). Bij meer dan 1 verboden teken en vanaf 1 verdacht woord wordt de hele userinput opgeslagen in een aparte tabel. (Dit is de ruwe input, wordt opgeslagen met bindings) En ja: het maandelijks bekijken van deze tabel is mensenwerk.

Het gebruik van verdachte woorden leidt niet (direct) tot sancties naar de gebruiker: ik gebruik 'em om te zien of ik de lijst moet bijstellen, en of er hobbyisten aan het werk zijn...
 
- Ariën  -
Beheerder

- Ariën -

12/10/2017 22:08:25
Quote Anchor link
Direct iemand blokkeren gaat mij inderdaad te ver.
Zo heb ik ooit eens een script van iemand gezien die alles met diverse MySQL keywords blokkeerde, zoals SELECT, DROP DATABASE en WHERE...

Het script haalde stations op uit een database. Maar helaas: Purmerend Overwhere mocht niet :+)
Gewijzigd op 12/10/2017 22:08:33 door - Ariën -
 
Rob Doemaarwat

Rob Doemaarwat

12/10/2017 22:13:19
Quote Anchor link
Het staat standaard aan, maar het kan ook uit (per controller, per action). Zoals je zelf al aangeeft ga je d'r vanuit dat het niet nodig is, maar zoals Tom al aangeeft wil je toch een beetje de "hobbyisten" in de gaten houden.
 
Thomas van den Heuvel

Thomas van den Heuvel

13/10/2017 03:03:05
Quote Anchor link
Escape-on-input lijkt mij niet de oplossing. Alles op voorhand helemaal desinfecteren lijkt mij overkill, en is soms ook onwenselijk. Daarnaast is het gewoon niet nodig als je de DATA-delen in je SQL-statements op een fatsoenlijke wijze escaped.

Wat je zou kunnen doen is het format van bepaalde variabelen verplicht stellen, dit valt in feite onder input filtering. En als deze controles niet voldoen zou je een exception kunnen throwen die ook gelogd wordt. Of dit stilzwijgend afhandelen. Hangt af van de ernst van de "overtreding" of de implicaties van het ontbreken van (cruciale) informatie.

Als $_GET['id'] een autoincrement id zou moeten bevatten op bepaalde pagina's, stel dat dan op bovenstaande wijze verplicht. Het heeft namelijk geen enkele zin om een query in eerste instantie uit te voeren als je wéét dat je een id nodig hebt, maar iets krijgt wat daar in de verste verte niet op lijkt. Voor alle andere gevallen (invoer valt niet of niet makkelijk in een patroon te vangen): escape de DATA-delen in je query. Dit is eigenlijk altijd wel een goed idee en voorkomt injectie.

Het loggen van queries met SQL-injecties is zoiets als de inbraak opnemen. Je hebt dan misschien een dader in beeld maar je hebt nog steeds schade en je stereo is ook nog steeds weg... Zorg in eerste instantie dat je queries veilig zijn, en bouw dit daarna uit met extra controles en extra afhandeling zoals logging.

Daarnaast, waarom zou je stoppen bij injectie? Eigenlijk zijn alle queries die misgaan interessant. Die kunnen namelijk een indicatie zijn van bugs in code enzo (ongedefinieerde variabelen etc.). Waar rook is is meestal vuur.
Gewijzigd op 13/10/2017 04:10:18 door Thomas van den Heuvel
 
- Ariën  -
Beheerder

- Ariën -

13/10/2017 07:21:03
Quote Anchor link
Het lijkt mij dus het meest zinnig als je de queries dus scant op 'rotzooi' en bepaalde tekens.
Gaat mij gewoon puur om de detectie in dit vraagstuk. Escaping- / parameterised blijven uiteraard van belang.
Gewijzigd op 13/10/2017 07:21:29 door - Ariën -
 
Rob Doemaarwat

Rob Doemaarwat

13/10/2017 07:24:40
Quote Anchor link
Daarom ook die (tijdelijke) blokkade: iemand die aan het slot begint te frunniken heeft sowieso al niet veel goeds in de zin. Het is gewoon een soort brute-force delay. Ik kan wel denken dat alles 100% dicht zit, maar misschien dat ze uiteindelijk toch een "specialistisch" gaatje vinden. Daarvoor heb je echter wel heel wat pogingen nodig, en door dan ze dan steeds even voor een langere periode buiten te sluiten schiet het niet heel erg op, en hoef ik niet 24/7 naar de logs te lopen loeren. De meeste aanvallen beginnen toch met id=5' en dat soort simpele fratsen (meestal een lijst van een paar honderd "standaard fratsen").

O, en alles loggen altijd +1: PDO::ERRMODE_EXCEPTION, set_exception_handler(), set_error_handler() (throwt een Exception), en in de register_shutdown_function() nog even kijken of er een error_get_last() was (bijv time-out). Dan blijf je prima op de hoogte waar je applicatie bij dagelijks gebruikt soms kraakt (+ MySQL slow query log in de gaten houden).
 
Thomas van den Heuvel

Thomas van den Heuvel

13/10/2017 16:14:31
Quote Anchor link
- Ariën - op 13/10/2017 07:21:03:
Het lijkt mij dus het meest zinnig als je de queries dus scant op 'rotzooi' en bepaalde tekens.


Rob Doemaarwat op 13/10/2017 07:24:40:
Daarom ook die (tijdelijke) blokkade: iemand die aan het slot begint te frunniken heeft sowieso al niet veel goeds in de zin. Het is gewoon een soort brute-force delay.


Rob Doemaarwat op 13/10/2017 07:24:40:
De meeste aanvallen beginnen toch met id=5' en dat soort simpele fratsen (meestal een lijst van een paar honderd "standaard fratsen").


Dit alles is programmatische interpretatie van invoer, die eigenlijk overbodig is wanneer je goed escaped.

Indien de invoer aan een bepaald format moet voldoen controleer je hier op middels een whitelist. @Rob en @Tom noemen illegale karakters, maar dat is een blacklist. Het nadeel van een blacklist is dat als deze incompleet is, dat deze niet werkt. Dus als iemand het een "specialistische gaatje" vindt verliest een blacklist meteen zijn waarde.

Bij het opzetten van beveiligingsmechanismen lijkt het mij belangrijk dat de spelregels eenvoudig en transparant zijn. Ik stel, wat mij betreft, de simpelste vorm voor om dit te doen, die gewoon altijd veilig is:
- controleer waar nodig, de vorm van de invoer
- escape alle DATA altijd

In een algemenere zin hebben we het hier eigenlijk over hoe we (veilig) om zouden moeten gaan met User Data. Het antwoord hierop is ook simpel: Never Trust User Data. Zelfs niet als deze de database in gaat. Er bestaan aanvallen die pas in werking treden wanneer gegevens weer uitgelezen worden uit de database en dan hun werk doen. Dit betekent echter niet dat alles op voorhand geescaped (opgeslagen)zou moeten worden! Het gaat erom dat wanneer User Data in een bepaalde context wordt gebruikt (SQL, HTML) dat potentieel gevaarlijke karakters hun speciale betekenis verliezen binnen die context. Hiervoor bestaan escaping-functies. Het enige wat je hoeft te doen is deze consequent toepassen.

Dit alles valt (wederom) onder de vuistregel filter input, escape output. Als je dit in je achterhoofd houdt wanneer je met User Data werkt en dit overal consequent toepast dan heb je een aardige garantie op veilige applicaties... mits je netjes omgaat met character encoderingen omdat (hoe) escaping-functionaliteit (werkt) hier sterk van afhangt.

Het is dus meer een knop omgooien over hoe je naar User Data kijkt, en hoe je hiermee omgaat (of om zou moeten gaan).
 
Rob Doemaarwat

Rob Doemaarwat

13/10/2017 16:41:25
Quote Anchor link
Alles leuk en aardig (en idd een groot aandachtspunt), maar niemand schrijft foutloze code (en vandaag "bets practices" blijken morgen opeens achterhaald: Magic Quotes -> addslashes -> mysql_escape_string -> mysql_real_escape_string). Daarom wil ik gewoon weten wie d'r waar & hoe zit te klooien.
 
- Ariën  -
Beheerder

- Ariën -

13/10/2017 16:59:51
Quote Anchor link
Dat klopt.
Soms is er zelfs sprake van oude obsolete code die vergeten is.
 
Ward van der Put
Moderator

Ward van der Put

13/10/2017 17:07:37
Quote Anchor link
In de OWASP SQL Injection Prevention Cheat Sheet zijn "White List Input Validation" en "Escaping All User-Supplied Input" nog steeds twee belangrijke verdedigingslinies. Dat de wapenuitrusting van die linies in de loop der jaren verandert, maakt de verdedigingsstrategieën zelf niet ineens nutteloos.

Meer on topic: je moet alles loggen. De kwaadaardigste SQL-injectie is immers degene die is geslaagd omdat je die onopgemerkt liet passeren, niet de query die mislukte of de query waarvoor de input werd afgekeurd.
 
Thomas van den Heuvel

Thomas van den Heuvel

13/10/2017 19:19:59
Quote Anchor link
white list input validation = filter input
escaping all user-supplied input = escape output

Rob Doemaarwat op 13/10/2017 16:41:25:
Magic Quotes -> addslashes -> mysql_escape_string -> mysql_real_escape_string).

Daar stip je ook iets aan. Magic Quotes en addslashes() waren immers nooit bedoeld noch geschikt voor escaping van DATA binnen SQL. Dit was, en is (helaas nog steeds), een ingeburgerd verkeerd gebruik.

Dit soort (gevestigde) misvattingen de wereld uit helpen is eigenlijk het moeilijkste wat er is. Hier moet je namelijk een berg tekst tegenaan gooien om fundamentele zaken uit te leggen en te verduidelijken, en de enige reactie die je dan vaak krijgt is "whatevs".

En ja, log alles, of in ieder geval fouten. Probeer ook niet invoer die niet voldoet te repareren met typecasts of wat dan ook. Laat dingen gewoon fout gaan die fout zijn. Tis heel simpel: invoer voldoet (YES) of voldoet niet (NO).
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.