Loggen van SQL-injections
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 -
In een aparte check, maar van hetzelfde laken het pak match ik deze ook nog met '/\\.\\.[\\\\\\/]/' (poging tot path traversal).
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...
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 -
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.
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
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 -
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).
- 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
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).
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.
Soms is er zelfs sprake van oude obsolete code die vergeten is.
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.
In de OWASP 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.
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).