From c85f54116c2ff081c86c57e0dd8ef10e908970d5 Mon Sep 17 00:00:00 2001 From: Timothy Allen Date: Fri, 25 Sep 2026 21:29:09 +0200 Subject: [PATCH] Use bound parameters for every query that takes user data. The queue image query took $id without quotes or a check, which allowed SQL injection. --- display.php | 4 +-- get_data.lib.php | 33 +++++++++------------ navigation.lib.php | 6 ++-- publish/addeditor.php | 13 ++++----- publish/login.php | 8 ++--- publish/post.lib.php | 68 +++++++++++++++++++++---------------------- session.lib.php | 27 ++++++----------- 7 files changed, 70 insertions(+), 89 deletions(-) diff --git a/display.php b/display.php index d308088..bc52b1c 100644 --- a/display.php +++ b/display.php @@ -41,8 +41,8 @@ function display_img($id) { $hidden = $is_admin ? "" : " AND hidden IS NOT TRUE"; } - $query = "SELECT img, mime FROM $table WHERE 1 AND ID = ".$db->real_escape_string($id).$hidden." LIMIT 0, 1"; - $result = $db->query($query)or die("Query failed : ".$db->error); + $query = "SELECT img, mime FROM $table WHERE 1 AND ID = ?".$hidden." LIMIT 0, 1"; + $result = $db->execute_query($query, array((int)$id)) or die("Query failed : ".$db->error); $row = $result->fetch_assoc(); if ($row) { diff --git a/get_data.lib.php b/get_data.lib.php index bf224d2..057fe1a 100644 --- a/get_data.lib.php +++ b/get_data.lib.php @@ -105,28 +105,25 @@ function get_count() { $search = get_search_args(); $queue = get_queue(); $table = which_table(); + $params = array(); // if search= is defined, search.... if ($search) { $count_query = "SELECT COUNT(*) FROM $table WHERE". - " ( title LIKE '%".$search."%'". - " OR author LIKE '%".$search."%'". - " OR date LIKE '%".$search."%'". - " OR story LIKE '%".$search."%'". - " )"; + " (title LIKE ? OR author LIKE ? OR date LIKE ? OR story LIKE ?)"; + $params = array_fill(0, 4, "%$search%"); // Otherwise, fall back to default view } else { $count_query = "SELECT COUNT(*) FROM ".$table." WHERE 1"; } if (!$is_admin) $count_query .= " AND hidden IS NOT TRUE"; - $count_query .= " ;"; //echo $count_query."
"; $row_count = NULL; echo $db->info; if ($count_query) { - if ($result = $db->query($count_query)) { + if ($result = $db->execute_query($count_query, $params)) { $row_count = $result->fetch_row(); $result->close(); } else { @@ -149,35 +146,34 @@ function get_query($id = NULL) { $queue = get_queue(); $table = which_table(); $results = array(); + $params = array(); + $limit = " LIMIT ".(int)$start." , ".(int)$show; // If id= is defined, show the corresponding application only if (is_numeric($id)) { if (!$is_admin) - $query = "SELECT * FROM $table WHERE 1 AND hidden IS NOT TRUE AND id = ".$id." LIMIT 0, 1"; + $query = "SELECT * FROM $table WHERE 1 AND hidden IS NOT TRUE AND id = ".(int)$id." LIMIT 0, 1"; else - $query = "SELECT * FROM $table WHERE 1 AND id = ".$id." LIMIT 0, 1"; + $query = "SELECT * FROM $table WHERE 1 AND id = ".(int)$id." LIMIT 0, 1"; // if search= is defined, search.... } else if ($search) { $query = "SELECT * FROM $table WHERE". - " ( title LIKE '%".$search."%'". - " OR author LIKE '%".$search."%'". - " OR date LIKE '%".$search."%'". - " OR story LIKE '%".$search."%'". - " )"; + " (title LIKE ? OR author LIKE ? OR date LIKE ? OR story LIKE ?)"; + $params = array_fill(0, 4, "%$search%"); if (!$is_admin) $query .= " AND hidden IS NOT TRUE"; - $query .= " ORDER BY ".$sort." " .$order." LIMIT " .$start." , ".$show." ;"; + $query .= " ORDER BY ".$sort." ".$order.$limit; // Otherwise, fall back to default view } else { $query = "SELECT * FROM ".$table." WHERE 1"; if (!$is_admin) $query .= " AND hidden IS NOT TRUE"; - $query .= " ORDER BY ".$sort." " .$order." LIMIT " .$start." , ".$show." ;"; + $query .= " ORDER BY ".$sort." ".$order.$limit; } //echo $query; - if ($result = $db->query($query)) { + if ($result = $db->execute_query($query, $params)) { while ($row = $result->fetch_assoc()) { $row['queue_url'] = $queue ? 1 : 0; $results[] = $row; @@ -256,8 +252,7 @@ function get_id() { function get_search_args() { global $db; if (isset($_GET['search']) && is_string($_GET['search'])) { - $search = $db->real_escape_string($_GET['search']); - return $search; + return $_GET['search']; } } diff --git a/navigation.lib.php b/navigation.lib.php index e4e0963..32de564 100644 --- a/navigation.lib.php +++ b/navigation.lib.php @@ -33,7 +33,7 @@ function sort_options($link) { } else { $href = ''.$display.''; @@ -71,7 +71,7 @@ function get_pager() { if ($start > 0) { $string .= "\n".'real_escape_string($_POST['username'] ?? ''); - $password = $db->real_escape_string(password_hash($_POST['password'] ?? '', PASSWORD_DEFAULT)); - $email = $db->real_escape_string($_POST['email'] ?? ''); - $query = "INSERT INTO $table SET". - "`username` = '".$username."', ". - "`password` = '".$password."', ". - "`email` = '".$email."'; "; - if ($result = $db->query($query)) { + $username = (string)($_POST['username'] ?? ''); + $password = password_hash((string)($_POST['password'] ?? ''), PASSWORD_DEFAULT); + $email = (string)($_POST['email'] ?? ''); + $query = "INSERT INTO $table SET `username` = ?, `password` = ?, `email` = ?"; + if ($result = $db->execute_query($query, array($username, $password, $email))) { $added = TRUE; $is_admin = TRUE; } diff --git a/publish/login.php b/publish/login.php index e8fc8de..969e427 100644 --- a/publish/login.php +++ b/publish/login.php @@ -14,11 +14,9 @@ if (isset($_SESSION['editor'])) { $table = "editors"; open_db('open'); - $username = $db->real_escape_string($_POST['username'] ?? ''); - $query = "SELECT * FROM $table WHERE ". - "username LIKE '".$username."' ". - "LIMIT 1;"; - $getid = $db->query($query) or die("Query failed: ".$db->error); + $username = (string)($_POST['username'] ?? ''); + $query = "SELECT * FROM $table WHERE username LIKE ? LIMIT 1"; + $getid = $db->execute_query($query, array($username)) or die("Query failed: ".$db->error); $row = $getid->fetch_assoc(); $stored_password = ''; diff --git a/publish/post.lib.php b/publish/post.lib.php index 844f2be..8e223da 100644 --- a/publish/post.lib.php +++ b/publish/post.lib.php @@ -22,6 +22,7 @@ function save_data($id = NULL) { $comments = NULL; $editor = 'original author'; } + $id = is_numeric($id) ? (int)$id : NULL; $queue = get_queue(); // Are we posting a story from the queue? @@ -37,10 +38,9 @@ function save_data($id = NULL) { if (!$date) $date = gmdate("Y-m-d H:i:s"); // Verify image - if ($move && isset($uploaded) && $uploaded === $id) { + if ($move && isset($id) && isset($uploaded) && $uploaded === (string)$id) { // Special case - transfer image from queue table - $query = "SELECT img, mime FROM queue WHERE id = $id;"; - if ($getimg = $db->query($query)) { + if ($getimg = $db->execute_query("SELECT img, mime FROM queue WHERE id = ?", array($id))) { $row = $getimg->fetch_assoc(); $img = $row['img']; $mime = $row['mime']; @@ -56,43 +56,43 @@ function save_data($id = NULL) { } } - if (is_numeric($id) && !$move) - $query = "UPDATE $table SET"; - else - $query = "INSERT INTO $table SET"; - $query .= " `title` = '".$db->real_escape_string($title)."'" - .", `author` = '".$db->real_escape_string($author)."'" - .", `email` = '".$db->real_escape_string($email)."'" - .", `editor` = '".$db->real_escape_string($editor)."'"; + // Column => value; the values are bound as query parameters + $fields = array( + 'title' => $title, + 'author' => $author, + 'email' => $email, + 'editor' => $editor, + ); if ($is_admin && isset($comments)) { - $query .= ", `comments` = '".$db->real_escape_string($comments)."'"; - } - if ($hidden) { - $query .= ", `hidden` = TRUE"; - } else { - $query .= ", `hidden` = FALSE"; + $fields['comments'] = $comments; } + $fields['hidden'] = $hidden ? 1 : 0; if ($remove_img && $story) { - $query .= ", `story` = '".$db->real_escape_string($story)."'"; - $query .= ", `mime` = NULL"; - $query .= ", `img` = NULL"; + $fields['story'] = $story; + $fields['mime'] = NULL; + $fields['img'] = NULL; } else if (isset($img)) { - $query .= ", `mime` = '".$db->real_escape_string($mime)."'"; - $query .= ", `img` = '".$db->real_escape_string($img)."'"; - $query .= ", `story` = ''"; + $fields['mime'] = $mime; + $fields['img'] = $img; + $fields['story'] = ''; } else { - $query .= ", `story` = '".$db->real_escape_string($story)."'"; + $fields['story'] = $story; } if (!is_numeric($id) || $move) - $query .= ", `date` = '".$db->real_escape_string($date)."'"; - if (is_numeric($id) && !$move) - $query .= " WHERE `id` = '".$id."' LIMIT 1;"; - else - $query .= ";"; - + $fields['date'] = $date; + + $set = implode(', ', array_map(function ($column) { return "`$column` = ?"; }, array_keys($fields))); + $params = array_values($fields); + if (is_numeric($id) && !$move) { + $query = "UPDATE $table SET $set WHERE `id` = ? LIMIT 1"; + $params[] = $id; + } else { + $query = "INSERT INTO $table SET $set"; + } + //echo $query; - $result = $db->query($query) or die("Query failed: ".$db->error); - + $result = $db->execute_query($query, $params) or die("Query failed: ".$db->error); + if (is_numeric($id) && $move) { $queue_id = $id; } @@ -134,9 +134,9 @@ function delete_story($id, $move = FALSE) { $queue = get_queue(); $table = which_table($move, 'delete'); - $query = "DELETE FROM $table WHERE `id` = '".$id."' LIMIT 1;"; + $query = "DELETE FROM $table WHERE `id` = ? LIMIT 1"; //echo $query; - $result = $db->query($query)or die("Query failed : ".$db->error); + $result = $db->execute_query($query, array((int)$id)) or die("Query failed : ".$db->error); $message = ''; if (!$move) diff --git a/session.lib.php b/session.lib.php index a817af2..3d73c87 100644 --- a/session.lib.php +++ b/session.lib.php @@ -32,15 +32,11 @@ function check_persistent_login() { $table = "persistent_sessions"; open_db('open'); - $cookie_data = $db->real_escape_string($_COOKIE['PersistentAuth']); + $cookie_data = (string)$_COOKIE['PersistentAuth']; list($username, $key) = explode("|", $cookie_data, 2) + array('', ''); - $username = $db->real_escape_string($username); - $key = $db->real_escape_string($key); - $query = "SELECT * FROM $table WHERE ". - "username LIKE '".$username."' ". - "LIMIT 1;"; - $getid = $db->query($query) or die("Query failed: ".$db->error); + $query = "SELECT * FROM $table WHERE username LIKE ? LIMIT 1"; + $getid = $db->execute_query($query, array($username)) or die("Query failed: ".$db->error); $row = $getid->fetch_assoc(); open_db('close'); @@ -67,12 +63,11 @@ function create_persistent_login($username) { $table = "persistent_sessions"; open_db('open'); - $username = $db->real_escape_string($username); $key = bin2hex(random_bytes(100)); // Add session key to database - $query = "INSERT INTO $table " . "(username, session) VALUES ('" . $username."', '" . $key . "');"; - $db->query($query) or die("Query failed: ".$db->error); + $query = "INSERT INTO $table (username, session) VALUES (?, ?)"; + $db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error); open_db('close'); // Create cookie with key @@ -86,16 +81,12 @@ function delete_persistent_login() { $table = "persistent_sessions"; open_db('open'); - $cookie_data = $db->real_escape_string($_COOKIE['PersistentAuth'] ?? ''); + $cookie_data = (string)($_COOKIE['PersistentAuth'] ?? ''); list($username, $key) = explode("|", $cookie_data, 2) + array('', ''); - $username = $db->real_escape_string($username); - $key = $db->real_escape_string($key); - // Add session key to database - $query = "DELETE FROM $table " . - " WHERE username LIKE '" . $username . "'" . - " AND session LIKE '" . $key . "';"; - $db->query($query) or die("Query failed: ".$db->error); + // Remove this session key from the database + $query = "DELETE FROM $table WHERE username LIKE ? AND session LIKE ?"; + $db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error); // Reap old sessions $query = "DELETE FROM $table " .