Vraag Moet ik me beschermen tegen SQL-injectie als ik een vervolgkeuzelijst gebruik?


Ik begrijp dat u de gebruikersinvoer van een formulier NOOIT moet vertrouwen, voornamelijk vanwege de kans op SQL-injectie.

Is dit echter ook van toepassing op een formulier waarbij de enige invoer uit een vervolgkeuzelijst (en) bestaat (zie hieronder)?

Ik bewaar het $_POST['size'] naar een sessie die vervolgens door de hele site wordt gebruikt om de verschillende databases te doorzoeken (met een mysqli Selecteer zoekopdracht) en een SQL-injectie zou deze zeker schaden (mogelijk laten vallen).

Er is geen gebied voor getypte gebruikersinvoer om de databases te doorzoeken, alleen dropdown (s).

<form action="welcome.php" method="post">
<select name="size">
  <option value="All">Select Size</option> 
  <option value="Large">Large</option>
  <option value="Medium">Medium</option>
  <option value="Small">Small</option>
</select>
<input type="submit">
</form>

92
2018-03-20 13:16


oorsprong


antwoorden:


U kunt zoiets eenvoudigs doen als in het volgende voorbeeld om ervoor te zorgen dat de geposte grootte is wat u verwacht.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

Gebruik vervolgens mysqli_ * als u een versie van php> = 5.3.0 gebruikt die u zou moeten zijn om uw resultaat op te slaan. Bij correct gebruik zal dit helpen met sql-injectie.


68
2018-03-20 13:25



Ja, je moet je hiertegen beschermen.

Laat me je laten zien waarom, met behulp van Firefox's ontwikkelaarsconsole:

i've edited one of the values in the dropdown to be a drop table statement

Als u deze gegevens niet opschoont, wordt uw database vernietigd. (Dit is misschien geen volledig geldige SQL-instructie, maar ik hoop dat ik mijn punt heb doorgespeeld.)

Alleen omdat je hebt beperkt welke opties beschikbaar zijn in je dropdown betekent niet je hebt de gegevens beperkt die ik je server kan sturen.

Als u dit verder wilt beperken met behulp van het gedrag op uw pagina, zijn mijn opties onder meer het uitschakelen van dat gedrag of het schrijven van een aangepast HTTP-verzoek naar uw server dat deze formulierinzending sowieso imiteert. Er is een tool genaamd Krul gebruikt voor precies dat, en ik denken de opdracht om deze SQL-injectie toch in te dienen, zou er ongeveer zo uitzien:

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(Dit is misschien geen volledig geldig curl-commando, maar nogmaals, ik hoop dat ik mijn punt heb doorgespeeld.)

Dus, ik zal herhalen:

Vertrouw NOOIT gebruikersinvoer. Bescherm jezelf ALTIJD.

Ga er niet van uit dat de invoer van een gebruiker veilig is. Het is mogelijk onveilig, zelfs als het op een andere manier dan een formulier aankomt. Niets van het is ooit betrouwbaar genoeg om af te zien van het beschermen tegen SQL-injectie.


192
2018-03-21 04:18



Omdat deze vraag is getagd , hier is een antwoord met betrekking tot dit specifieke soort aanval:

Zoals je in de opmerkingen is verteld, moet je voorbereide uitspraken gebruiken voor elke afzonderlijke vraag met betrekking tot variabele gegevens, met geen uitzonderingen.

Ongeacht HTML-dingen!
Het is essentieel om te begrijpen dat SQL-query's correct moeten worden opgemaakt achteloos van externe factoren, of het nu gaat om HTML-invoer of iets anders.

Hoewel u witte lijsten kunt gebruiken die in andere antwoorden worden voorgesteld voor het doel van de invoervalidatie, het zou geen invloed moeten hebben op SQL-gerelateerde acties - ze moeten hetzelfde blijven, ongeacht of u HTML-invoer hebt gevalideerd of niet. Dit betekent dat u nog steeds voorbereide instructies moet gebruiken bij het toevoegen van variabelen in de query.

Hier vindt u wellicht een grondige uitleg, waarom voorbereide verklaringen een must zijn en hoe u ze correct kunt gebruiken en waar ze niet van toepassing zijn en wat u in dergelijke gevallen moet doen: The Hitchhiker's Guide to SQL Injection protection

Ook is deze vraag getagd met . Meestal bij toeval, neem ik aan, maar hoe dan ook, ik moet je waarschuwen voor rauwe mysqli is geen adequate vervanging voor de oude mysq_ * -functies. Gewoon omdat als het in de oude stijl wordt gebruikt, voegt het helemaal geen beveiliging toe. Hoewel de ondersteuning voor de voorbereide uitspraken pijnlijk en lastig is, komt het erop neer dat de gemiddelde PHP-gebruiker deze helemaal niet kan proberen. Dus als er geen ORM of een soort van abstractiebibliotheek is, dan BOB is je enige keuze.


44
2018-03-20 14:19



Ja.

Iedereen kan iets spoofen voor de waarden die daadwerkelijk worden verzonden -

Dus, voor het valideren van vervolgkeuzemenu's, kun je gewoon controleren of de waarde waarmee je werkt in de vervolgkeuzelijst stond - zoiets zou de beste (meest paranoïde) manier zijn:

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}


12
2018-03-20 13:18



Een manier om u te beschermen tegen gebruikers die uw drop-downs wijzigen met behulp van de console, is door alleen integerwaarden te gebruiken. Vervolgens kunt u controleren of de POST-waarde een geheel getal bevat en een array gebruiken om die naar tekst te converteren wanneer dat nodig is. bijv:

<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '<select name="size">';
foreach($sizes as $i => $s) {
    echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';

Dan kun je gebruiken $size in uw vraag met kennis die alleen maar zal bevatten FALSE of een geheel getal.


8
2018-03-20 14:01



De andere antwoorden behandelen al wat u moet weten. Maar misschien helpt het om nog meer te verduidelijken:

Er zijn TWEE DINGEN je moet:

1. Valideer formuliergegevens.

Als Het antwoord van Jonathan Hobbs laat heel duidelijk zien dat de keuze van het html-element voor de invoer van het formulier geen betrouwbare filtering voor u mogelijk maakt.

Validatie wordt meestal gedaan op een manier die de gegevens niet verandert, maar die het formulier opnieuw toont, met de velden gemarkeerd als "Corrigeer dit".

De meeste frameworks en CMS's hebben formulierbouwers die u helpen met deze taak. En niet alleen dat, ze helpen ook tegen CSRF (of "XSRF"), wat een andere vorm van aanval is.

2. Sanitize / Escape-variabelen in SQL-instructies ..

.. of laat voorbereide verklaringen het werk voor je doen.

Als u een (Mijn) SQL-instructie maakt met variabelen, door de gebruiker opgegeven of niet, moet u aan deze variabelen ontsnappen en citeren.

Over het algemeen moet elke variabele die u invoegt in een MySQL-statement een tekenreeks zijn of iets dat PHP op betrouwbare wijze kan veranderen in een tekenreeks die MySQL kan verwerken. Zoals cijfers.

Voor strings moet je dan een van de verschillende methoden kiezen om aan de string te ontsnappen, dat wil zeggen, tekens vervangen die bijwerkingen zouden hebben in MySQL.

  • In old-school MySQL + PHP doet mysql_real_escape_string () het werk. Het probleem is dat het veel te gemakkelijk is om te vergeten, dus je moet absoluut gebruik maken van voorbereide verklaringen of vraagbuilders.
  • In MySQLi kunt u voorbereide instructies gebruiken.
  • De meeste frameworks en CMSes bieden query-builders die u helpen bij deze taak.

Als u met een nummer te maken hebt, kunt u het ontsnappen en de aanhalingstekens weglaten (dit is de reden waarom de voorbereide instructies het mogelijk maken om een ​​type op te geven).

Het is belangrijk om erop te wijzen dat u aan de variabelen ontsnapt voor de SQL-instructie en NIET voor de database zelf. De database slaat de oorspronkelijke tekenreeks op, maar de instructie heeft een escapeversie nodig.

Wat gebeurt er als je een van deze weglaat?

Als u geen formuliervalidatie gebruikt, maar je saneert wel je SQL-invoer, je ziet mogelijk allerlei slechte dingen gebeuren, maar je ziet geen SQL-injectie! (*)

Ten eerste kan het uw toepassing in een staat brengen die u niet van plan was. Bijv. als u de gemiddelde leeftijd van alle gebruikers wilt berekenen, maar één gebruiker 'aljkdfaqer' voor de leeftijd heeft opgegeven, mislukt uw berekening.

Ten tweede kunnen er allerlei andere injectie-aanvallen zijn die u moet overwegen: Bv. de gebruikersinvoer kan javascript of andere dingen bevatten.

Er kunnen nog steeds problemen zijn met de database: Afb. als een veld (databasetabelkolom) is beperkt tot 255 tekens en de tekenreeks langer is dan dat. Of als het veld alleen getallen accepteert en u probeert een niet-numerieke tekenreeks op te slaan. Maar dit is geen "injectie", het is gewoon "crashen van de applicatie".

Maar zelfs als u een vrij tekstveld heeft waar u geen enkele invoer zonder validatie toestaat, kunt u dit alsnog opslaan in de database, als u er op de juiste manier aan ontsnapt als het naar een database-instructie gaat. Het probleem komt wanneer u deze reeks ergens wilt gebruiken.

(*) of dit zou iets heel exotisch zijn.

Als u niet aan variabelen voor SQL-instructies ontsnapt, maar je hebt formulierinvoer gevalideerd, dan kun je nog steeds slechte dingen zien gebeuren.

Ten eerste loopt u het risico dat wanneer u gegevens opslaat in de database en deze opnieuw laadt, het niet dezelfde gegevens meer zijn, "verloren in vertaling".

Ten tweede kan dit resulteren in ongeldige SQL-instructies en daarmee uw applicatie crashen. Bijv. als een variabele een aanhalingsteken of dubbel aanhalingsteken bevat, afhankelijk van het type offerte dat u gebruikt, krijgt u een ongeldige MySQL-verklaring.

Ten derde kan het nog steeds SQL-injectie veroorzaken.

Als uw gebruikersinvoer vanuit formulieren al is gefilterd / gevalideerd, opzettelijk SQl-injectie kan minder waarschijnlijk worden, ALS uw invoer wordt gereduceerd tot een lijst met moeilijk te coderen opties of als deze beperkt is tot aantallen. Maar elke vrije tekstinvoer kan worden gebruikt voor SQL-injectie, als u niet goed aan de variabelen in SQL-instructies ontsnapt.

En zelfs als je helemaal geen invoer van formulieren hebt, zou je nog steeds strings van allerlei bronnen kunnen hebben: lezen van het bestandssysteem, geschrapt van internet, enz. Niemand kan garanderen dat deze snaren veilig zijn.


7
2018-03-22 15:18



Uw webbrowser "weet" niet dat hij een pagina van php ontvangt, alles wat hij ziet is html. En de http-laag weet zelfs minder dan dat. Je moet in staat zijn om bijna elke soort invoer te verwerken die de http-laag kan passeren (gelukkig geeft de meeste invoer-php al een fout). Als u probeert te voorkomen dat kwaadwillende verzoeken uw database verpesten, moet u ervan uitgaan dat de persoon aan de andere kant weet wat hij doet en dat hij niet beperkt is tot wat u in normale omstandigheden in uw browser kunt zien ( om maar te zwijgen over wat je kunt doen met de ontwikkelaarstools van een browser). Dus ja, je moet rekening houden met elke input van je dropdown, maar voor de meeste invoer kun je een foutmelding geven.


6
2018-03-20 15:33