Byłem w takiej samej sytuacji. Ja też korzystałem z połączonych wyciągów, a potem przestawiłem aplikację na gotowe wyciągi.
zła wiadomość czy zamierzasz zmienić każdą instrukcję SQL zbudowaną przez połączenie danych klienta z instrukcją SQL, która będzie prawie każdą instrukcją SQL, którą masz w swoich 50 plikach źródłowych.
dobra wiadomość czy zysk z przejścia na wyciągi gotowe jest bezcenny, na przykład:
1-nigdy nie będziesz się martwić o coś, co nazywa się „atakiem wstrzyknięcia SQL”
php podręcznik mówi
Dla mnie ten powód - spokój ducha - wystarczy, aby pokryć koszty zmiany mojego kodu źródłowego. , teraz Twoi klienci mogą wpisać w polu nazwy formularza robert; DROP table students; -- ;)
i czujesz się bezpiecznie, że nic się nie stanie
2- nie musisz już zmieniać parametrów klienta. możesz ich użyć bezpośrednio w instrukcji SQL, na przykład :
$query = "SELECT FROM user WHERE id = ?";
$vars[] = $_POST['id'];
zamiast
$id = $mysqli->real_escape_string($_POST['id']);
$query = "SELECT FROM user WHERE id = $id";
co musisz zrobić przed użyciem przygotowanych stwierdzeń, co narażało cię na niebezpieczeństwo zapomnienia o ucieczce od jednego parametru jako normalnego człowieka. a wszystko, czego potrzeba, aby atakujący uszkodził Twój system, to tylko 1 nieunikniony parametr.
Zmiana kodu
zazwyczaj zmiana plików źródłowych jest zawsze ryzykowna i bolesna, zwłaszcza jeśli projekt oprogramowania jest zły i jeśli nie masz oczywistego planu testowania. ale powiem ci, co zrobiłem, aby było to jak najłatwiejsze.
Stworzyłem funkcję, z której będzie korzystał każdy kod interakcji z bazą danych, dzięki czemu możesz zmienić to, co chcesz później w jednym miejscu - ta funkcja - możesz zrobić coś takiego
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;
}
}
Teraz możesz używać tego interfejsu w dowolnym miejscu w plikach źródłowych, na przykład zmieńmy bieżące instrukcje SQL, które podałeś w pytaniu. Zmieńmy to
$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;
}
}
W to
$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;
}
Tak, atak Sql Injection jest stosowany przez połączenie złego ciągu z instrukcją SQL. gdzie jest INSERT
, SELECT
, DELETE
, UPDATE
. na przykład
$query = "SELECT * FROM user WHERE name = '{$_GET['name']}' AND password = '{$_GET['pass']}'"
coś takiego mogłoby zostać wykorzystane przez
// exmaple.com?name=me&pass=1' OR 1=1; --
co da w wyniku instrukcję 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
Powodzenia w przełączeniu oprogramowania na gotowe zestawienia i pamiętaj, że spokój ducha, jaki uzyskasz wiedząc, że cokolwiek się stanie, jesteś bezpieczny przed atakami typu SQL injection, jest wart kosztów zmiany plików źródłowych