diff --git a/pub/api/classes/API.php b/pub/api/classes/API.php index e8e8387..3a10c6f 100644 --- a/pub/api/classes/API.php +++ b/pub/api/classes/API.php @@ -4,6 +4,7 @@ namespace api\classes; class API { public $conn; + public $pdo; # The user uuid that requested the API protected $user_uuid; @@ -42,14 +43,21 @@ class API # Used for the query builder base public $baseQuery = false; + # Used for the general get function, this prevents SQL injecting by only allowing these columns instead of + # Whatever the user inputs straigt into the query. + public $allowedGetColumns = false; + + # Cache the columns of the tables for some small performance improvements. + private static array $columnCache = []; + public function __construct() { - require_once $_SERVER['DOCUMENT_ROOT'] . '/bin/php/db_connect.php'; include_once $_SERVER['DOCUMENT_ROOT'] . '/bin/php/Functions/globalFunctions.php'; # Setup Database connection $this->conn = $GLOBALS['conn']; + $this->pdo = $GLOBALS['pdo']; if (!empty($_SESSION['user']['user_uuid'])) { $this->InitUserTypeFrontend(); @@ -694,6 +702,8 @@ class API protected function buildDynamicQuery(string $tableName): array { + $this->allowedGetColumns = $this->loadTableColumns($tableName); + if (!$this->baseQuery) { $this->baseQuery = "SELECT * FROM " . $tableName; } @@ -714,6 +724,10 @@ class API $column = $builder['where'][0]; $value = $builder['where'][1]; + if (!in_array($column, $this->allowedGetColumns, true)) { + $this->apiOutput(400, ['error' => 'The column ' . $column . ' is not allowed.']); + } + $whereClauses[] = "$column = ?"; $types .= 's'; $values[] = $value; @@ -726,6 +740,20 @@ class API return [$this->baseQuery, $types, $values]; } + protected function loadTableColumns(string $tableName): array + { + if (isset(self::$columnCache[$tableName])) { + return self::$columnCache[$tableName]; + } + + $sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?"; + + $stmt = $this->pdo->prepare($sql); + $stmt->execute([$tableName]); + + return self::$columnCache[$tableName] = $stmt->fetchAll(\PDO::FETCH_COLUMN); + } + protected function generalGetFunction($query, $types, $params, $returnBoolean, $itemName) { $stmt = $this->prepareStatement($query);