sql >> Databáze >  >> RDS >> Mysql

Přechod na připravené výpisy

Byl jsem ve stejné situaci. Také jsem používal zřetězené příkazy, pak jsem přepnul aplikaci na připravené příkazy.

špatné zprávy se chystáte změnit každý příkaz SQL vytvořený zřetězením klientských dat do příkazu SQL, což bude téměř každý příkaz SQL, který máte ve svých 50 zdrojových souborech.

dobré zprávy je zisk z přechodu na připravené výpisy k nezaplacení, například:

1-nikdy se nebudete obávat něčeho, co se nazývá „útok SQL Injection“

příručku php říká

Pro mě je tento důvod - klid v duši - dostatečný na to, abych zaplatil náklady na změnu zdrojového kódu. , nyní mohou vaši klienti zadat do pole pro jméno formuláře robert; DROP table students; -- ;) a máte pocit bezpečí, že se nic nestane

2- již nemusíte unikat parametry klienta. můžete je přímo použít v příkazu SQL, něco jako :

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

místo

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

což je něco, co jste museli udělat před použitím připravených příkazů, což vás vystavovalo nebezpečí, že jako normální lidská bytost zapomenete uniknout jednomu parametru. a vše, co útočník potřebuje k poškození vašeho systému, je pouze 1 neescapovaný parametr.

Změna kódu

obvykle změna zdrojových souborů je vždy riskantní a bolestivá, zvláště pokud je návrh vašeho softwaru špatný a nemáte jasný plán testování. ale řeknu vám, co jsem udělal, aby to bylo co nejjednodušší.

Vytvořil jsem funkci, kterou bude používat každý kód interakce s databází, takže můžete později na jednom místě změnit, co chcete - tuto funkci - můžete vytvořit něco takového

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;
    }
}

Nyní můžete toto rozhraní použít kdekoli ve zdrojových souborech, například změňte vaše aktuální příkazy SQL, které jste uvedli v otázce. Pojďme to změnit

$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;
    }
}

Do tohoto

$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;
}

Ano, útok SQL Injection se aplikuje zřetězením špatného řetězce do vašeho příkazu SQL. kde se jedná o INSERT , SELECT , DELETE , UPDATE . například

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

něco takového by mohl zneužít

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

což bude mít za následek SQL příkaz

$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

Hodně štěstí při přepínání softwaru na připravené příkazy a pamatujte, že klid, který získáte díky vědomí, že ať se stane cokoli, jste v bezpečí před útoky SQL injection, stojí za cenu změny zdrojových souborů




  1. Podpora dBase je zpět v aplikaci Microsoft Access!

  2. Chybějící výsledek v povinných polích

  3. phpMyAdmin na MySQL 8.0

  4. Žádné výsledky po odstranění mysql ft_stopword_file