Mysql
 sql >> база данни >  >> RDS >> Mysql

Преминаване към подготвени изявления

Аз съм бил в същата ситуация. Използвах и конкатенирани оператори, след което превключих приложението си към подготвени оператори.

лошите новини ще промените всеки SQL израз, изграден чрез конкатениране на клиентски данни към SQL израза, който почти ще бъде всеки SQL израз, който имате във вашите 50 изходни файла.

добрата новина печалбата от преминаването към подготвени изявления е безценна, например:

1 - никога няма да се притеснявате за нещо, наречено "SQL инжекция атака"

php ръководството казва

За мен тази причина - спокойствие - е достатъчна, за да платя разходите за промяна на моя изходен код. , сега вашите клиенти могат да въвеждат в полето за име на формуляр robert; DROP table students; -- ;) и се чувствате сигурни, че нищо няма да се случи

2- вече не е нужно да избягвате параметрите на клиента. можете директно да ги използвате в SQL израза, нещо като :

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

вместо

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

което е нещо, което трябваше да направите, преди да използвате подготвени изявления, което ви излагаше на опасност да забравите да избягате от един параметър като нормално човешко същество. и всичко, което е необходимо на нападателя да повреди системата ви, е само 1 неекраниран параметър.

Промяна на кода

обикновено промяната на изходните файлове винаги е рискована и причинява болка, особено ако дизайнът на вашия софтуер е лош и ако нямате очевиден план за тестване. но ще ви кажа какво направих, за да го направя възможно най-лесно.

Направих функция, която всеки код за взаимодействие с базата данни ще използва, така че можете да промените това, което искате по-късно на едно място - тази функция - можете да направите нещо подобно

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

Сега можете да използвате този интерфейс навсякъде, където искате във вашите изходни файлове, например нека променим текущите си SQL изрази, които сте предоставили във въпроса. Нека променим това

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

В това

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

Да, атаката с инжектиране на SQL се прилага чрез конкатениране на лош низ към вашия SQL израз. където е INSERT , SELECT , DELETE , UPDATE . например

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

нещо подобно може да се използва от

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

което ще доведе до SQL израз

$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

Успех с превключването на вашия софтуер към подготвени изявления и не забравяйте, че спокойствието, което ще получите, знаейки, че каквото и да се случи, вие сте в безопасност от атаки с инжектиране на SQL, си струва цената за промяна на изходните файлове




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как мога да принудя да изляза всички потребители на уебсайт?

  2. Вмъкнете стойност на полето за динамичен избор в базата данни на Mysql и покажете съобщението за изпратените данни

  3. varchar(255) срещу tinytext/tinyblob и varchar(65535) срещу blob/text

  4. mysql PDO как да обвържем LIKE

  5. Laravel Query Builder КЪДЕ НЕ