sql >> Database >  >> RDS >> Mysql

Overschakelen naar voorbereide afschriften

Ik heb in dezelfde situatie gezeten. Ik gebruikte ook aaneengeschakelde verklaringen, daarna schakelde ik mijn applicatie over naar voorbereide verklaringen.

het slechte nieuws ga je elke SQL-instructie wijzigen die is gebouwd door clientgegevens samen te voegen met de SQL-instructie, wat bijna elke SQL-instructie zal zijn die je in je 50 bronbestanden hebt.

het goede nieuws is de winst van het overschakelen naar voorbereide afschriften van onschatbare waarde, bijvoorbeeld:

1-je zult je nooit zorgen maken over iets dat "SQL-injectie-aanval" wordt genoemd

de php handleiding zegt

Voor mij is die reden -gemoedsrust- genoeg om de kosten van het wijzigen van mijn broncode te betalen. , nu kunnen uw klanten in een formuliernaamveld robert; DROP table students; -- ;) en je voelt je veilig dat er niets gaat gebeuren

2- u hoeft niet meer te ontsnappen aan de clientparameters. je kunt ze direct gebruiken in de SQL-instructie, zoiets als:

$query = "SELECT FROM user WHERE id = ?";
$vars[] = $_POST['id'];

in plaats van

$id = $mysqli->real_escape_string($_POST['id']);
$query = "SELECT FROM user WHERE id = $id";

wat je moest doen voordat je voorbereide uitspraken gebruikte, waardoor je als normaal mens het gevaar liep te vergeten om aan één parameter te ontsnappen. en alles wat een aanvaller nodig heeft om uw systeem te beschadigen, is slechts 1 parameter die niet is ontsnapt.

De code wijzigen

meestal is het veranderen van de bronbestanden altijd riskant en pijnlijk, vooral als je softwareontwerp slecht is en als je geen duidelijk testplan hebt. maar ik zal je vertellen wat ik heb gedaan om het zo gemakkelijk mogelijk te maken.

Ik heb een functie gemaakt die elke database-interactiecode gaat gebruiken, dus je kunt later op één plek veranderen wat je wilt - die functie - je kunt zoiets als dit maken

class SystemModel
{
    /**
     * @param string $query
     * @param string $types
     * @param array $vars
     * @param \mysqli $conn
     * @return boolean|$stmt
     */
    public function preparedQuery($query,$types, array $vars, $conn)
    {
        if (count($vars) > 0) {
            $hasVars = true;
        }
        array_unshift($vars, $types);
        $stmt = $conn->prepare($query);
        if (! $stmt) {
            return false;
        }
        if (isset($hasVars)) {
            if (! call_user_func_array(array( $stmt, 'bind_param'), $this->refValues($vars))) {
                return false;
            }
        }
        $stmt->execute();
        return $stmt;
    }

    /* used only inside preparedQuery */
    /* code taken from: https://stackoverflow.com/a/13572647/5407848 */
    protected function refValues($arr)
    {
        if (strnatcmp(phpversion(), '5.3') >= 0) {
            $refs = array();
            foreach ($arr as $key => $value)
                $refs[$key] = &$arr[$key];
                return $refs;
        }
        return $arr;
    }
}

Nu kunt u deze interface overal in uw bronbestanden gebruiken, laten we bijvoorbeeld uw huidige SQL-instructies wijzigen die u in de vraag hebt verstrekt. Laten we dit veranderen

$mysqli = new mysqli('localhost', "root", "", "testdb");
$addresult = "
                SELECT a.firstnames, a.surname, a.schoolrole, a.datejoined 
                FROM teachers a LEFT JOIN schools b ON a.schoolid = b.id 
                WHERE b.id = '".$inputvalues['schoolid']."'";

if( $result = $mysqli->query($addresult) ) {
    while($row = $result->fetch_all())
    {
        $returnResult = $row;
    }
}

In deze

$mysqli = new mysqli('localhost', "root", "", "testdb");
$sysModel = new SystemModel();
$addresult = "
                SELECT a.firstnames, a.surname, a.schoolrole, a.datejoined
                FROM teachers a LEFT JOIN schools b ON a.schoolid = b.id
                WHERE b.id = ?";
$types = "i"; // for more information on paramters types, please check :
//https://php.net/manual/en/mysqli-stmt.bind-param.php
$vars = [];
$vars[] = $inputvalues['schoolid'];

$stmt = $sysModel->preparedQuery($addresult, $types, $vars, $mysqli);
if (!$stmt || $stmt->errno) {
   die('error'); // TODO: change later for a better illustrative output
}
$result = $stmt->get_result();
$returnResult = [];
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
    $returnResult[] = $row;
}

Ja, een SQL-injectieaanval wordt toegepast door een slechte tekenreeks aan uw SQL-instructie te koppelen. waar het een INSERT is , SELECT , DELETE , UPDATE . bijvoorbeeld

$query = "SELECT * FROM user WHERE name = '{$_GET['name']}' AND password = '{$_GET['pass']}'"

zoiets zou kunnen worden misbruikt door

// exmaple.com?name=me&pass=1' OR 1=1; -- 

wat resulteert in een SQL-statement

$query = "SELECT * FROM user WHERE name = 'me' AND password = '1' OR 1=1; -- '"
//executing the SQL statement and getting the result
if($result->num_rows){
    //user is authentic
}else{
    //wrong password
}
// that SQL will always get results from the table which will be considered a correct password

Veel succes met het overschakelen van uw software naar voorbereide verklaringen, en onthoud dat de gemoedsrust die u zult krijgen door te weten dat wat er ook gebeurt, u veilig bent voor SQL-injectie-aanvallen, de kosten van het wijzigen van de bronbestanden waard zijn




  1. JPA EclipseLink DatabaseException:'tabel foo.SEQUENCE bestaat niet'

  2. HABTM opslaan met extra velden?

  3. Hoe omgevingsvariabele Pad in te stellen met C#

  4. Krijg alle tabelnamen van een bepaalde database door SQL-query?