SQL Injection Guide

Door Niek s, 14 jaar geleden, 22.659x bekeken

Beschrijving hoe iemand SQL injection gebruikt, en wat je er tegen kan doen.
Dit is een beknopte tutorial, verwacht er niet teveel van zal ik maar zeggen ;-)

Gesponsorde koppelingen

Inhoudsopgave

  1. Inleiding
  2. Is SQL Injection mogelijk?
  3. SQL Injection, Hoe krijg ik datastructuur?
  4. SQL Injection, Data bewerken
  5. Wat kan ik er tegen doen?
  6. Bronnen en extra

 

Er zijn 47 reacties op 'Sql injection guide'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
Misschien nog een aanvulling op de tutorial:

gebruik altijd quotes in een query voor de variabelen, voorbeeldje:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?
$sQuery
= 'SELECT * FROM tabel WHERE id = \'' . $variabele . '\'';

// EN NIET:

$sQuery = 'SELECT * FROM tabel WHERE id = ' . $variabele;
?>


Bij onderstaande query kan ik gewoon $variabele gelijk maken aan:

23;DELETE FROM tabel

En zeg maar dag dag records ;D

edit:

ooo vergeten, mooie tutorial..


14 jaar geleden
 
0 +1 -0 -1
vette tutorial ga ik direct eens gebruiken om mijn login script te testen voor sql injection
Jelmer -
Jelmer -
14 jaar geleden
 
0 +1 -0 -1
Quotes op plekken waar integers gebruikt worden is etisch gezien niet lekker. Daarbij zal mysql_query nooit meer dan 1 opdracht uitvoeren. Limitatie van PHP ;)
Leroy Boerefijn
Leroy Boerefijn
14 jaar geleden
 
0 +1 -0 -1
chille tut!!
volgens mij niets vergeten ;)

@martijn!, ik doe altijd dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$query
= "SELECT * FROM tabel WHERE id = '" . $variabele . "';
?>

dan hoef je namelijk niet met die backslases te werken..
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
Net ff gecontroleerd en mijn producten tabel was leeg.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
SELECT *
FROM p_products
WHERE 1 ;# Rijen: 3439
DELETE FROM p_products# Getroffen rijen: 3439


@leroy:

Kan ook idd...
Jelmer -
Jelmer -
14 jaar geleden
 
0 +1 -0 -1
Nooit vertrouwen wat anderen zeggen over PHP? :S
Ik dacht echt dat het beperkt was door PHP.

Ikzelf gebruik voor integers meestal het o zo gemene intval() of gewoon typecasting (int)

Misschien is het leuk om in de 'wat kan je er tegen doen' magic_quotes_rpc ook even te vermelden, en even aan te geven dat dit niet een oplossing is aangezien dat alleen maar lastig is en toch binnenkort weer uit PHP geslingerd wordt.


14 jaar geleden
 
0 +1 -0 -1
intval() zoals Jelmer zegt moet je gebruiken voor het selecteren van een id, en geen quotjes plaatsen. Want anders is het een string (volgens mij is MySQL ook een van de weinige systemen die dit slikt)
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
Ik heb hier een mooie oracle SQL leerboek en daarin staat:

"Let op het subtiele verschil tussen 123 en '123'! Het verschil tussen numerieke en alfanumerieke constanten komt met name tot uiting in hun bewerkingsmogelijkheden. Numerieke constanten kunnen bijvoorbeeld worden opgeteld, of met elkaar vermenigvuldigd. Met alfanumerieke constanten gaat dat niet; die kun je bijvoorbeeld aan elkaar plakken"

Maar dat is ook al weer een oude boek over Oracle7 en 8i
Klaasjan Boven
Klaasjan Boven
14 jaar geleden
 
0 +1 -0 -1
Quote:
Martijn! schreef op 01.11.2006 22:12
Ik heb hier een mooie oracle SQL leerboek en daarin staat:

"Let op het subtiele verschil tussen 123 en '123'! Het verschil tussen numerieke en alfanumerieke constanten komt met name tot uiting in hun bewerkingsmogelijkheden. Numerieke constanten kunnen bijvoorbeeld worden opgeteld, of met elkaar vermenigvuldigd. Met alfanumerieke constanten gaat dat niet; die kun je bijvoorbeeld aan elkaar plakken"


Maar dat is ook al weer een oude boek over Oracle7 en 8i

Gewijzigd op 01.11.2006 22:12 door Martijn!

Maar jij hebt het over _O_ Oracle dat is wel wat anders dan mysql. Mysql is niet zo nauwkeurig als het op wel of geen ' ' aankomt
Robert Deiman
Robert Deiman
14 jaar geleden
 
0 +1 -0 -1
Dat klopt wel Klaasjan, maar dat betekend niet dat je het niet beter op die manier kan doen. De manier van Martijn! waarbij hij zegt dat 123 en '123' anders zijn klopt, MySQL slikt dit, maar als je nu naar een ander type database overstapt?
Precies, dan kan je je beter aan de standaard hebben gehouden, dat scheelt aanpassingen. Daar komt bij dat je je sowiezo beter aan de gestelde standaard kan houden, om fouten te voorkomen.

== Mooie tut hoor ==
Legolas
Legolas
14 jaar geleden
 
0 +1 -0 -1
Eigenlijk zouden PHP en MySQL wat strikter mogen, komt het programmeerniveau ten goede
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
Je zou ook van te voren kunnen checken of een variabele in de querie een getal is. Dan hoef je de query niet meer uit te voeren, als dit niet zo is. Maar ik vind eigelijk niet dat single-quotes om numerieke waardes in queries verkeerd zijn, ik zie het meer als extra zekerheid voor als je waarde check faalt. En schijnbaar kan Oracle ook hiermee omgaan.

@Legolas:
MySQL heeft een strict modes, maar of dat wat help.

PHP mag wat mij betreft een optie in de parser maken die een error geeft als je bagger code hebt gemaakt. Hopen dat PHP6 alle bagger oplossingen aanpakt .
Willem Jan Z
Willem Jan Z
14 jaar geleden
 
0 +1 -0 -1
Quote:
Nooit vertrouwen wat anderen zeggen over PHP? :S
Ik dacht echt dat het beperkt was door PHP.

Waar ben je dan achter gekomen? Ik dacht namelijk ook dat het door PHP kwam dat je maar 1 query er in kan stoppen. Of is het een instelling oid. Want ik kan echt maar 1 query per keer uitvoeren.
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
@Willen-Jan:

SELECT * FROM p_products WHERE 1 ;DELETE FROM p_products

Ga je gang ;D
Bas Kreleger
Bas Kreleger
14 jaar geleden
 
0 +1 -0 -1
Ligt aan je MySQL instellingen of je meerdere queries in ??n keer kunt executen. PHP checked dit niet, tenzij je dit zelf inbouwt :).
Hipska BE
Hipska BE
14 jaar geleden
 
0 +1 -0 -1
php voert met mysql_query() alles na de ; toch niet meer uit?

(heb het gistere toevallig nog geprobeerd)
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
Hipska schreef op 02.11.2006 10:30
php voert met mysql_query() alles na de ; toch niet meer uit?

(heb het gistere toevallig nog geprobeerd)

nee klopt, maar in een string wel... want anders zou je geen ; in een bericht kunnen zetten bijvoorbeeld.

mysql_query("SELECT * FROM poep; TRUNCATE TABLE henk"); werkt gewoon hoor...


(edit: typos onder voorbehoud :p)
Jelmer -
Jelmer -
14 jaar geleden
 
0 +1 -0 -1
Bedoel je met dat hij werkt dat hij de tabel 'henk' op de koop houdt, of dat hij gewoon die 2e opdracht negeert?
Marien xD
Marien xD
14 jaar geleden
 
0 +1 -0 -1
Vergeet de dubbele steepjes niet achter de query als je een injection doet. Dit zorgt ervoor dat de rest van de achterliggende query als commentaar gezien word:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?
mysql_query("SELECT * FROM poep; TRUNCATE TABLE henk-- WHERE blaat");
?>
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
@Marien:

Staat ook in mijn tutorial ;-)
Leroy Boerefijn
Leroy Boerefijn
14 jaar geleden
 
0 +1 -0 -1
maar wat moet je nou gebruiken??
123 of '123' ??
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
voor integers moet je geen quotes gebruiken volgens mij, maar ik ben geen super expert op dat gebied.
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
@leroy

Als je het heel strikt bekijkt moet je 123 gebruiken en geen '123' alleen maakt het volgens mij niets uit. Wil je iets bij dat getal optellen bijvoorbeeld dan kun je niet '123' gebruiken.
Maar de discussie gaat erover dat die 123 dus een variabele is. Als je dan geen
single-quotes (') gebruikt dan kun je makkelijk twee queries van die enkele query maken wat dus niet de bedoeling is.
Arend a
Arend a
14 jaar geleden
 
0 +1 -0 -1
Ik vond vooral je PDFje interessant, misschien is het aardig om die ook integraal op te nemen in je tutorial?
 
0 +1 -0 -1
Voor id's moet je sowieso gewoon ctype_digit gebruiken.

Mooie tutorial!
The Hosh
The Hosh
14 jaar geleden
 
0 +1 -0 -1
een klein vraagje, is het makkelijk als niemand de tabellen weet? zullen ze makkelijk injecties gebruiken?
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
als niemand de tabellen weet is natuurlijk perfect, maar iemand kan na een paar pogingen atlijd je tabel goed hebben gegokt.. veiliger is om het gewoon niet mogelijk te maken ;-)

Arend schreef op 02.11.2006 20:18
Ik vond vooral je PDFje interessant, misschien is het aardig om die ook integraal op te nemen in je tutorial?

Ik weet niet wat je hier mee precies bedoelt (kan aan mijn dyslexie liggen) maar kan je je zlef nog verklaren of niet?
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
@Niek:

http://www.gkvwijnjewoude.nl/schoolhack3.pdf

@Andries Louw W.:

Bij id,s doe ik dat inderdaad ook altijd in combinatie met empty.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?
$id
= 3432423;

if( !empty($id) && ctype_digit((string)$id) )
{

  # $id is een getal van 1 t/m heel veel.
}
?>
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
Ja dat is mijn pdf, maar wat moet ik daar mee doen? ook in de tutorial zetten ofzo? ik snap het niet helemaal
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Wanneer je in PostgreSQL met PL/pgSQL aan de slag gaat, daarmee gaat programeren en vervolgens iedereen de toegang tot de tabelen ontzegt, kun je SQL-injection helemaal voorkomen. Er is geen mens die de database in kan, men kan alleen van de API's gebruik maken die jij hebt geprogrameerd. En voor alle API's geldt dat jij bepaalt hoe de input en output er uit zal zien. Alles wat daar van afwijkt, laat je door de API afkeuren. Dit is vele malen veiliger dan dat met MySQL-mogelijk is, die kent dit soort oplossingen helemaal niet. Oracle heeft soortgelijke oplossingen als PostgreSQL, PL/SQL.
Martijn B
Martijn B
14 jaar geleden
 
0 +1 -0 -1
Over wat voor oplossingen heb je het nu Frank...

stored-procedures?
Peter Wessels
Peter Wessels
14 jaar geleden
 
0 +1 -0 -1
ik krijg steeds je hebt een verkeert username ingevult bij alle systemen
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
@Martijn: Ik heb het over server programming en dan met name over PL/pgSQL. Zie http://www.postgresql.org/docs/8.1/interactive/server-programming.html en http://www.postgresql.org/docs/8.1/interactive/plpgsql.html

Ik ben niet goed bekend met de stored procedures van MySQL (vanaf versie 5), maar wellicht kun je daar soortgelijke resultaten mee bereiken. Alleen jammer dat MySQL al wel met de volgende waarschuwing komt: "Use of stored routines can cause replication problems.". Dat zijn problemen die je koste wat het kost probeert te vermijden!
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
Quote:
Peter schreef op 03.11.2006 18:22
ik krijg steeds je hebt een verkeert username ingevult bij alle systemen


Dat betekent dat er geen SQL Injection mogelijk is.
Arian Stolwijk
Arian Stolwijk
14 jaar geleden
 
0 +1 -0 -1
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function quote_smart($value){
   // Stripslashes
   if (get_magic_quotes_gpc()){
       $value = stripslashes($value);
   }

   // Quote if not a number or a numeric string
   if (!is_numeric($value)){
       $value = mysql_real_escape_string($value);
   }

   return $value;
}

?>


Dit is ook een handige functie voordat je strings in de sql query zet, om ze te beveiligen tegen SQL injection.

Zo komen ze altijd goed in de database, en hoef je ook geen stripslahes te gebruiken.

Stripslashes hoef je namelijk alleen te gebruiken als magic_quotes_gpc aan staat. Als magic_quotes_gpc aan staat en je doet dan nog eens mysql_real_escape_string() of addslashes() eroverheen wordt hij 2 keer ge slashed. (\\')
Niek s
niek s
14 jaar geleden
 
0 +1 -0 -1
die laatste check hoeft er tog niet in? want als het een getal is wort ie tog automatisch niet geslashed.. dus gewoon zo tog?:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
function dinges($value) {
    if(get_magic_quotes_gpc()) {
        $value = strip_slashes($value);
    }

    return mysql_real_escape_string($value);
}

?>
Jelle -
Jelle -
14 jaar geleden
 
0 +1 -0 -1
jah maar waarom zou je die functie uitvoeren als het nodig is. daarom heeft hij daarop gecheckt.
Legolas
Legolas
14 jaar geleden
 
0 +1 -0 -1
Te veel complexiteit waar het niet nodig is is vaak een grote veroorzaker van allerlei bugs. Dit is dan in dit geval een beetje overdreven, maar toch, denk er over na :P
Katjan
katjan
14 jaar geleden
 
0 +1 -0 -1
ach mensen, sql injection is oud.. de tijd dat dat nog kon is eigenlijk allang voorbij.. (jammer genoeg..;))
er zijn nog een paar systemen waar het wel kan.. (lerarensysteem van ict opleiding in zwolle, niet windesheim maar die andere)
maar bij de meeste systemen lukt het echt niet meer:(
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
@Huib: Wat probeer je hier mee te zeggen? Dat men er dus geen aandacht meer aan hoeft te besteden? Het is juist voor beginners, minstens 80% van de bezoekers van www.phphulp.nl , belangrijk dat hier tijd aan wordt besteed zodat zij ook veilige websites kunnen bouwen.
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Nog een kleine aanvulling:
Gebruik PDO in PHP versie 5, SQL-injection wordt dan onmogelijk.
ToySoldier ZegIkNiet
ToySoldier ZegIkNiet
11 jaar geleden
 
0 +1 -0 -1
@ pagina "SQL Injection, Hoe krijg ik datastructuur?",

Ik ben het daar niet mee eens. Als ik als PHP'er de mysql_num_rows verberg en ik geef de PHP error, of de tabel bestaat of niet, dan kom je helemaal nergens achter..
Thomas van den Heuvel
Thomas van den Heuvel
4 jaar geleden
 
0 +1 -0 -1
Bij de definitie van SQL injection omschrijf je het gevolg (het effect), en niet de oorzaak. Een betere omschrijving van SQL injection is misschien de volgende:

Een query is vaak opgebouwd uit een statisch deel SQL en een of meer variabele delen DATA. Deze DATA komt uit een externe bron: de querystring, een formulier et cetera. Er is sprake van SQL injectie als een stuk DATA als SQL geïnterpreteerd wordt (dat is de injectie van SQL!). Hiermee kun je de betekenis en de werking van een query manipuleren.

SQL injectie is mogelijk wanneer de DATA delen niet ontdaan zijn van een mogelijke speciale betekenis binnen (het) SQL (statement).

Er zijn twee handelingen die je kunt verrichten om SQL injectie tegen te gaan:
- je controleert je invoer (filter input)
- je escaped je uitvoer (escape output)

Het escapen van uitvoer alleen is niet altijd genoeg.
In de string " OR 1=1" zitten geen karakters die een _real_escape_string() escaped. Als je een nummer verwacht ($_GET['id']) controleer hier dan op en voer anders de query niet uit!

Aanroepen van _real_escape_string() functies worden gebruikt als een soort van magische bezwering die uitgevoerd wordt in de veronderstelling dat een systeem vervolgens niet meer gedeerd kan worden...

Constructies met (int) of sprintf (typecasts) of is_int() (verwacht een integer) zijn allemaal nogal brak omdat die in bepaalde gevallen onvoorspelbaar/ongewenst gedrag vertonen. Gebruik filter_var() of een regexp.

addslashes() zijn niet bestemd voor queries, ze escapen andere karakters dan _real_escape_string() functies. Deze twee functies dienen een verschillend doel en zijn dus niet uitwisselbaar.

Gebruik in je hele applicatie (inclusief database) bij voorkeur één character encoding. Dat scheelt je een heleboel gezever.

Dit alles en meer staat in mijn artikel over MySQLi waarin uitgebreid aandacht besteed wordt aan dit soort security issues en de op handen zijnde veranderingen in PHP-land.
Ivo P
Ivo P
4 jaar geleden
 
@thomas
Ben je archeoloog?
Of reageer je alleen op jarenoude tutorials om links naar je eigen site te kunnen spammen?
Thomas van den Heuvel
Thomas van den Heuvel
4 jaar geleden
 
0 +1 -0 -1
Zie het als een update / kanttekeningen. Deze zijn bedoeld om de informatie die hier staat aan te vullen. Ik link naar een artikel omdat daar dingen uitgebreider staan uitgelegd en het nogal loos is om dat hele verhaal hier te herhalen. Ook zie ik niet hoe ik aan het "spammen" ben, aangezien dit de eerste en enige link is naar mijn eigen site.

Ik had ook naar de concurrent kunnen linken waar dat artikel ook geplaatst staat, maar dat was waarschijnlijk ook niet goed geweest.

Dit lijkt mij het hele punt van reacties en ook relevant voor dit artikel wat ondertussen enigszins gedateerd is. Tenzij er een actueler artikel is en/of je op deze site (ver)oude(rde) informatie niet mag becommentarieren zie ik niet waarom ik hier niet zou mogen reageren.

De topics die ik voorbij zie komen op het forum bewijzen wat mij betreft dat er nog heel wat opgestoken kan worden over (SQL) security. Een up-to-date tutorial helpt je daarmee meer dan een verouderd artikel.

Ik zou nog verder kunnen gaan: deze tutorial zou eigenlijk continu bijgewerkt moeten worden. Als niemand in de tussentijd tot meer (/andere) inzicht(en) is gekomen dan zit er waarschijnlijk een behoorlijk hiaat in je kennis.
Ivo P
Ivo P
4 jaar geleden
 
0 +1 -0 -1
Het klopt dat het jammer is dat er nog 10 jaar oude tutorials online staan, zonder dat het daarbij duidelijk is dat een tutorial verouderd is.

Mijn ervaring met reacties op oude topics en tutorials is, dat dat vaak een diepere reden heeft (spam of seo links).
Dat ik meerdere reacties in oude tuts zag en dan ook nog een link, was de reden voor mijn reactie.

Als ik fout zit: mijn excuses.

Blijft over, dat phphulp eigenlijk geen 10 jaar oude tuts ongewijzigd online zou moeten houden :-)
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Wouter J
Wouter J
4 jaar geleden
 
0 +1 -0 -1
>> Blijft over, dat phphulp eigenlijk geen 10 jaar oude tuts ongewijzigd online zou moeten houden :-)

Zolang er geen beter alternatief is, is het verwijderen van oude tutorials alleen maar het verwijdering van kennis overdracht. Een tutorial die het concept wel uitlegt, maar ietwat verouderde preventie technieken gebruikt is alsnog beter dan geen artikel.

Ik nodig Thomas dan ook van harte uit om zijn reactie om te toveren tot een tutorial (ik denk niet dat er heel veel tekst bij hoeft). Wanneer dat gebeurd zullen wij duidelijk maken dat deze tutorial verouderd is en linken naar de vervanger.
Het verwijderen van een tutorial doen we niet vaak, omdat URLs die langer mee gaan vaak hoger in de ranking staan en vaak worden gebruikt door oudere resources. Ze zijn een goede ingang voor de nieuwe tutorial.

Om te reageren heb je een account nodig en je moet ingelogd zijn.

 
 

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.