sql >> Database teknologi >  >> RDS >> Mysql

Skift til udarbejdede erklæringer

Jeg har stået i samme situation. Jeg brugte også sammenkædede udsagn, så skiftede jeg min applikation til forberedte udsagn.

de dårlige nyheder vil du ændre hver SQL-sætning, der er bygget ved at sammenkæde klientdata til SQL-sætningen, som næsten vil være hver SQL-sætning, du har i dine 50 kildefiler.

den gode nyhed er gevinsten ved at skifte til udarbejdede opgørelser uvurderlig, for eksempel:

1-du vil aldrig være bekymret for noget, der hedder "SQL Injection attack"

php manualen siger

For mig er den grund -ro i sindet- nok til at betale omkostningerne ved at ændre min kildekode. , nu kan dine klienter indtaste et formularnavnfelt robert; DROP table students; -- ;) og du føler dig sikker på, at der ikke vil ske noget

2- du behøver ikke længere at undslippe klientparametrene. du kan bruge dem direkte i SQL-sætningen, sådan som :

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

i stedet for

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

hvilket er noget, du skulle gøre, før du brugte forberedte udsagn, hvilket bragte dig i fare for at glemme at undslippe én parameter som et normalt menneske. og det eneste, der skal til, for at en angriber kan beskadige dit system, er kun 1 uundgået parameter.

Ændring af koden

Ændring af kildefiler er typisk altid risikabelt og har smerte, især hvis dit softwaredesign er dårligt, og hvis du ikke har en åbenlys testplan. men jeg vil fortælle dig, hvad jeg gjorde for at gøre det så nemmere som muligt.

Jeg lavede en funktion, som enhver databaseinteraktionskode kommer til at bruge, så du kan ændre, hvad du vil have senere ét sted -den funktion- du kan lave sådan noget her

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 kan du bruge denne grænseflade hvor som helst du vil i dine kildefiler, lad os for eksempel ændre dine nuværende SQL-sætninger, du har angivet i spørgsmålet. Lad os ændre dette

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

Ind i dette

$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, SQL Injection-angreb anvendes ved at sammenkæde dårlig streng til din SQL-sætning. hvor det er en INSERT , SELECT , DELETE , UPDATE . for eksempel

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

sådan noget kunne udnyttes af

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

hvilket vil resultere i en SQL-sætning

$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

Held og lykke med at skifte din software til forberedte erklæringer, og husk, at den ro i sindet, du får ved at vide, at uanset hvad der sker, er du sikker mod SQL-injektionsangreb, det er prisen værd at ændre kildefilerne




  1. SQL Server:SUM() af flere rækker inklusive where-sætninger

  2. Kommaseparerede værdier til IN-funktion i oracle

  3. Er der en måde at se en forberedt forespørgsel, da den vil blive udført på databasen?

  4. Hvordan MID() virker i MariaDB