sql >> Databasteknik >  >> RDS >> Mysql

Växla till förberedda uttalanden

Jag har varit i samma situation. Jag använde också sammanlänkade uttalanden, sedan bytte jag min applikation till förberedda uttalanden.

de dåliga nyheterna kommer du att ändra varje SQL-sats som byggs genom att sammanfoga klientdata till SQL-satsen, vilket nästan kommer att vara varje SQL-sats du har i dina 50 källfiler.

de goda nyheterna är vinsten av att byta till förberedda uttalanden ovärderlig, till exempel:

1-du kommer aldrig att vara orolig för något som kallas "SQL Injection attack"

php manualen säger

För mig räcker den anledningen - sinnesro - för att betala kostnaden för att ändra min källkod. , nu kan dina kunder skriva i ett formulärnamnfält robert; DROP table students; -- ;) och du känner dig säker på att ingenting kommer att hända

2- du behöver inte undkomma klientparametrarna längre. du kan använda dem direkt i SQL-satsen, något som :

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

istället för

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

vilket är något du var tvungen att göra innan du använde förberedda uttalanden, vilket satte dig i fara att glömma bort en parameter som en normal människa. och allt som krävs för att en angripare ska korrumpera ditt system är bara en parameter utan undantag.

Ändra koden

Att ändra källfiler är vanligtvis alltid riskabelt och har smärta, särskilt om din mjukvarudesign är dålig och om du inte har en uppenbar testplan. men jag ska berätta vad jag gjorde för att göra det så enklare som möjligt.

Jag skapade en funktion som varje databasinteraktionskod kommer att använda, så att du kan ändra vad du vill senare på ett ställe -den funktionen- du kan göra något sånt här

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 använda det här gränssnittet var du vill i dina källfiler, låt oss till exempel ändra dina nuvarande SQL-satser som du har angett i frågan. Låt oss ändra detta

$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 i det här

$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 attack tillämpas genom att sammanfoga dålig sträng till din SQL-sats. där det är en INSERT , SELECT , DELETE , UPDATE . till exempel

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

något sådant skulle kunna utnyttjas av

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

vilket kommer att resultera i en SQL-sats

$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

Lycka till med att byta programvara till förberedda uttalanden, och kom ihåg att den sinnesfrid du kommer att få genom att veta att vad som än händer är du säker från SQL-injektionsattacker är värt kostnaden för att ändra källfilerna




  1. Hur man returnerar dagnumret med ett suffix i MariaDB

  2. SQL-serverlogg, leverans och katastrofåterställning, installation och konfiguration -3

  3. Hur extraherar år, månader, dagar, timmar, minuter, sekunder från ett mysql-datum?

  4. GETDATE() Exempel i SQL Server (T-SQL)