Digitalna papazjanija

Koristite MySQLi i Prepared Statements kao zaštitu od SQL Injection napada

Svima nam je poznata činjenica da se tehnologija jako brzo razvija, posebno kada su računari u pitanju. Za hardver postoji čak i dobro poznati Murov zakon koji kaže da se “snaga računara udvostručuje približno svakih 18-24 meseca“, dok je u softverskim vodama siutacija malo drugačija. U teroriji je svaka novina momentalno dostupna svim ljudima širom planete, a sve uz pomoć Interneta, međutim u realnosti i nije baš tako. Ovih dana konvertujem neki stari kod pa sam rešio da ovo podelim sa vama.

MySQLi je tema o kojoj se u najveće pričalo još 2008. i 2009. godine, a evo posle 5 godina i dalje nije prihvaćena u potpunosti. Zato je ovaj tekst namenjem mladim kolegama koji se tek upuštaju u web development vode, čisto da na jednostavnom primeru nauče kako se koriste MySQLi i pripremljene naredbe.

Šta su “MySQLi” i “Prepared Statements” i čemu služe

MySQLi je, jednostavno rečeno, dodatak za PHP (od verzije 5.0.0 je uključen u standardnu instalaciju) kojim se pristupa svim naprednim funkcijama uvedenim u MySQL Server, počevši od verzije 4.1.3 dotičnog servera.

If you are using MySQL versions 4.1.3 or later it is strongly recommended that you use the mysqli extension instead.

Ranije se koristio MySQL dodatak za upite nad bazom, pa se slovo “i” u nazivu odnosti na “improved“, tj “poboljšan“. Razlozi za korišćenje novog dodatka su mnogobrojni:

  • Održavanje koda kod stare verzije je postalo problematično još pre nego što je Oracle preuzeo MySQL, pa je bezbednije koristiti novu;
  • Slična sintaksa će skakako pomoći onima koji su koristili staru verziju da se snađu i na novoj;
  • Novi interfejsi su posebno zgodni jer se MySQLi može koristiti i proceduralno (slično kao stari mysql dodatak) i objektno, čime se iskorišćava pun potencijal PHP5 programskog jezika;
  • Napredne opcije počevši od od samih podešavanja prilikom inicijalizacije;
  • Brzina je ono što korisnici velikih i/ili opterećenih baza podataka znaj da cene;
  • Sigurnost je poboljšana na više načina, od promenjenog binarnog protokola u MySQL-u, do korišćenja pripremljenih naredbi (prepared statements);
  • Transakcije i atomične operacije su konačno implementirane u postpunosti.

Za detaljni pregled mogućnosti pogledajte PHP: Introduction – Manual.

Prepared Statements predstavljaju ‘pripremljene naredve‘ tj mogućnost da unapred definišete upite nad bazom, a da dinamičke argumente prosleđujete kasnije, na sigurniji način nego inače, čime sistem štitite od klasičnih SQL Injection napada.

Prepared statements are the ability to set up a statement once, and then execute it many times with different parameters.

Postoje dva tipa pripremljenih naredbi: “bound parameter” i “bound result“, ali su nam za zaptitu od SQL Injection napada zanimljivi samo prvi pa ću dati primer sa njima.

Dakle, MySQLi koristite zbog svojih mnogobrojnih prednosti (a stari mysql će i onako biti izbačen od verzije PHP 5.5.0) a prepared statements je novi saveznik u borbi protiv SQL Injection napada.

Primer MySQLi Prepared Statements upita na bazu iz PHP-a

Kao što iz priloženog primera možete primetiti, procedura je sledeća: kreirate novi $mysqli objekat kojim se konektujete na bazu, pa zatim pripremite SQL upit bez konkretnih parametara, umesto kojih ostavite znak(e) pitanja. Zatim željene parametre dodate (bind) na pripremljeni upit, prilikom čega definišete i tip podka koji prosleđujete (i – integer, d -double, s -string, b – blob) i tek onda zapravo izvršite upit. Na kraju pokupite rezultat upita i upišete ga u željenu promenljivu (ili više njih).

[php]

<?php
// Example of MySQLi and Prepared Statements
// save this file as example.php
// access it with example.php?userid=13 for example

// Databse constants
define(“DB_SERVER”, “localhost”);
define(“DB_USER”, “root”);
define(“DB_PASS”, “”);
define(“DB_NAME”, “testdb”);

// New DB connection
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
if ($mysqli->connect_errno) {
echo “Failed to connect to MySQL: ” . $mysqli->connect_error;
}

// Prepared query with ? as placeholder for parameters
$query = “SELECT user_tel, user_email FROM users WHERE user_id = ?;”;

// Set $userid variable
if (isset($_GET[‘userid’])) {
$user_id = $_GET[‘userid’];
} else {
$user_id = 1;
}

// Get instance of statement
$statement = $mysqli->stmt_init();

// Prepare Query
if ($statement->prepare($query)) {

// Bind Parameters – i for integer
$statement->bind_param(‘i’, $user_id);

// Execute the query
$statement->execute();

// Bind result variables
$statement->bind_result($tel, $email);

// Fetch Value
while ($statement->fetch()) {
echo “Tel: “.$tel.”\n”;
echo “Email: “.$email.”<br />\n”;
}

// Close statement
$statement->close();
}

// Close connection
$mysqli->close();

?>
[/php]