Путаница в подготовленном заявлении MySQL


Хорошо, итак, у меня много проблем с подготовленными заявлениями. Я провел несколько часов исследований и, похоже, до сих пор не могу полностью понять все...

Я действительно чувствую, что мне нужно понять подготовленные заявления, потому что я как раз собирался выпустить несколько новых бесплатных API на своем веб-сайте (для выполнения API требуется ключ API), но недавно я понял, насколько все небезопасно.... Я могу просто использовать SQL-инъекцию для обхода проверки ключа API, например 'OR'1'='1

Вот как я проверяю API Ключ:

$apikey = $_GET['key'];
$sql = "SELECT * FROM `table` WHERE `key` = '$apikey'";
$query = mysqli_query($con, $sql);
if($query)
{
    $fetchrow = mysqli_fetch_row($query);
    if(isset($fetchrow[0]))
    {
        echo "API Key is valid!";
    }
    else
    {
        echo "API KEY is invalid";
    }
}

И, как упоминалось выше, это можно легко обойти, выполнив мой API следующим образом

http://website.com/api.php?key='OR'1'='1

Сначала это действительно напугало меня, но потом я провел некоторое исследование и узнал, что хороший способ предотвратить любую форму SQL-инъекции - использовать подготовленный оператор, поэтому я провел много исследований, и это просто кажется мне довольно сложным:/

Поэтому, я думаю, мой вопрос в том, как я могу взять свой приведенный выше код и заставить его функционировать таким же образом, используя подготовленные инструкции?

Author: JeffCoderr, 2016-08-28

2 answers

Вероятно, все, что вам нужно:

class Database {
    private static $mysqli;

Подключение к БД:

public static function connect(){
    if (isset(self::$mysqli)){
        return self::$mysqli;
    }
    self::$mysqli = new mysqli("DB_HOST", "DB_USER", "DB_PASS", "DB_NAME");
    if (mysqli_connect_errno()) {
        /*Log error here, return 500 code (db connection error) or something... Details in $mysqli->error*/
    }
    self::$mysqli->query("SET NAMES utf8");
    return self::$mysqli;
}

Выполните инструкцию и получите результаты:

public static function execute($stmt){
    $stmt->execute();
    if ($mysqli->error) {
        /*Log it or throw 500 code (sql error)*/
    }
    return self::getResults($stmt);
}

Привязать результаты к чистому массиву:

private static function getResults($stmt){
    $stmt->store_result();
    $meta = $stmt->result_metadata();

    if (is_object($meta)){
        $variables = array();
        $data = array();

        while($field = $meta->fetch_field()) {
            $variables[] = &$data[$field->name];
        }

        call_user_func_array(array($stmt, "bind_result"), $variables);

        $i = 0;
        while($stmt->fetch()) {
            $array[$i] = array();
            foreach($data as $k=>$v)
            $array[$i][$k] = $v;
            $i++;
        }
        $stmt->close();
        return $array;
    } else {
        return $meta;
    }
}

Конец класса :)

}

Пример использования:

public function getSomething($something, $somethingOther){
    $mysqli = Database::connect();
    $stmt = $mysqli->prepare("SELECT * FROM table WHERE something = ? AND somethingOther = ?");
    $stmt->bind_param("si", $something, $somethingOther); // s means string, i means number
    $resultsArray = Database::execute($stmt);
    $someData = $resultsArray[0]["someColumn"];
}

Решение вашей проблемы:

public function isKeyValid($key){
    $mysqli = Database::connect();
    $stmt = $mysqli->prepare("SELECT * FROM table WHERE key = ? LIMIT 1");
    $stmt->bind_param("s", $key);
    $results = Database::execute($stmt);
    return count($results > 0);
}

PHP автоматически закрывает соединение с БД, так что не беспокойтесь об этом.

 3
Author: Damiano, 2017-05-04 15:01:45
$sql = "SELECT * FROM `table` WHERE `key` = ?";

if(stmt = $mysqli->prepare($sql)) {
    $stmt->bind_param("i", $apikey);

    $stmt->execute();
    $stmt->bind_result($res);
    $stmt->fetch();

    $stmt->close();
}

Подробнее - http://php.net/manual/en/mysqli.prepare.php

 1
Author: buildok, 2016-08-28 06:00:40