Базы данных. Основы SQL. Введение в SQL-инъекции

Привет, друг!

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

Что такое база данных

Итак, что такое база данных? Этот термин широко применим в повседневной жизни, что неудивительно, ведь по сути, база данных – это просто хранилище упорядоченной информации. Мы же, применительно к SQL, будем рассматривать базу данных как контейнер для информации в виде одного или нескольких файлов. Также надо знать что программное обеспечение которое управляет базой данных называется СУБД т.е система управления базой данных.

Ещё один момент который нужно понимать это структура базы данных. Здесь тоже ничего сложного. База данных состоит из трех элементов: таблица, строка и столбец. Ну и пару слов о них.

Таблица – это основной структурный элемент базы данных, при чем в одной базе может быть несколько таблиц. С точки зрения безопасности и удобства использования считается правильным хранить в каждой таблице только определенный тип данных. При создании таблицы нужно присвоить ей уникальное имя, в одной базе не может быть таблиц с одинаковыми именами, также нужно указать из каких столбцов она состоит и тоже присвоить им имена.

Столбец (колонка) – это структурный элемент уже таблицы. Для каждого столбца нужно указать какой именно тип данных разрешено в нем хранить: текст, числа, диапазоны чисел, файлы, логические значения и т.д.

Каждой записи в таблице соответствует отдельная строка, т.е. по сути строка – это отдельная запись в таблице. Каждой строке должен быть присвоен так называемый “первичный ключ” – это уникальный идентификатор строки, позволяющий в последствии обращаться именно к этой строке. В принципе любой столбец может выступать первичным ключом, главное соблюдать некоторые правила: он должен быть уникальным для каждой строки и должен обязательно иметь какое-либо присвоенное значение (он не может быть null), и его нельзя менять.

Примечание:
Иногда ты можешь столкнуться с термином – реляционная база данных. Это всего лишь означает что таблицы в этой базе могут ссылаться друг на друга и взаимодействовать между собой. Связи таблиц бывают трех видов: “один ко многим” (самый распространенный вариант), “один к одному” и “многие ко многим” (но это реже).

Что такое SQL

Что такое базы данных, вроде разобрались. Осталось разобраться что с ними делать, но к счастью тут не всё так сложно как могло показаться на первый взгляд. Для того что бы работать с базами данных был придуман язык SQL.

SQL (Structured Query Language) – это язык структурированных запросов и он позволяет выполнять любые действия с данными и базами данных: от простого ввода данных и создания таблиц до администрирования сервера СУБД. При этом он очень удачно совмещает в себе простоту и огромные возможности. Чтобы понять принцип работы SQL представь себе, что ты разговариваешь и даешь команды человеку, который очень исполнительный, но знает всего несколько слов и, вот, если ты дашь ему команду известными ему словами – он выполнит её идеально. Вообщем смысл в том, что создание запросов на SQL очень напоминает разговор, но обо всем по порядку.

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

Установка MySQL

Для начала нам понадобится СУБД. Мы будем использовать MySQL (просто для примера), но точно также всё будет работать и в любой другой СУБД.

Для начала нужно установить MySQL. Скачать её можно с официального сайта https://dev.mysql.com/downloads/mysql/

Или установить командой:

sudo apt install mysql-server

После установки MySQL автоматически запустится, проверить это можно командой:

sudo service mysql status
MySQL

если вдруг, по какой-то непонятной причине у тебя не запустилось, запускай вручную:

sudo service mysql start

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

sudo mysql_secure_installation

Первый шагом нам предложат придумать пароль, выбираем Y и дважды вводим пароль, ну и на все следующие вопросы отвечаем Y.

Теперь подключимся к серверу и продолжим:

sudo mysql -u root -p

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

mysql

Чтобы процесс изучения SQL был более наглядным, мы создадим базу данных, например пользователей какого-то условного сайта и с ней и будем работать. В нашей базе будут какие-нибудь условные таблицы, которые мы придумаем в процессе.

Создание базы данных и таблиц в SQL

Для создания новой базы данных используется команда CREATE DATABASE потом указывается имя новой базы и ещё запомни, что команда в SQL должна заканчиваться ” ; “

CREATE DATABASE all_users;

Как видишь мы сказали: СОЗДАЙ БАЗУ ДАННЫХ all_users. Теперь нужно сказать о том что мы хотим поработать с этой базой, для этого существует команда USE

USE all_users;
sql create daybase

Если базу данных нужно удалить используется команда DROP DATABASE имя_базы; Командой DROP, кстати, можно удалять все что угодно, не только базы. Например, чтобы удалить таблицу используется команда DROP TABLE имя_таблицы; а если нужно удалить все данные из таблицы, но саму таблицу при этом оставить, то есть команда: TRUNCATE TABLE имя_таблицы;

Так как база данных состоит из таблиц, то теперь переходим непосредственно к созданию таблиц. Для этого используется команда CREATE TABLE, после которой нужно указать название новой таблицы, а потом в скобках, через запятую перечислить какие в таблице будут колонки и типы данных в этих колонках. Давай для примера создадим таблицу с именами пользователей и их статусом на сайте:

CREATE TABLE users_nick (id INT AUTO_INCREMENT PRIMARY KEY, nick NVARCHAR(64) NOT NULL, status NVARCHAR(32));

Теперь давай посмотрим, что мы там насоздавали:

SHOW COLUMNS FROM users_nick;
sql create table

Ну и давай более детально разберем саму команду которую мы вводили:

  • CREATE TABLE users_nick – создай таблицу с именем users_nick;
  • id INT AUTO_INCREMENT PRIMARY KEY – первый столбец таблицы мы назвали id, присвоили ему тип данных INT т.е. целочисленные значения (это означает что там не может быть дробей, букв, символов – ничего кроме целых чисел), командой AUTO_INCREMENT мы попросили MySQL самостоятельно заполнять строки этой колонки при внесении новых записей в таблицу, при этом добавляя +1 к каждой новой записи, другими словами мы создали счётчик, чтобы добиться уникальности значений именно в этой колонке, а уникальные значения нам нужны чтобы применить параметр PRIMARY KEY т.е. назначить значения из этой колонки первичными ключами – уникальными идентификаторами строк таблицы, используя значения именно из этой колонки мы в последствии будем обращаться к строкам в этой таблице;
  • nick NVARCHAR(64) NOT NULL – второй столбец мы назвали nick и присвоили ему тип NVARCHAR это строковые данные переменного размера, при этом ограничив размер значения 64 байтами. Кстати некоторые “авторитетные” интернет-школы в своих курсах утверждают что значение в скобках – это количество символов, это не совсем так, вернее это так для однобайтовых кодировок, таких как LATIN потому что там 1 символ = 1 байт, но мы используем UTF-8 и это многобайтовая кодировка, а значит один символ может занимать больше одного байта. Потому просто запомни – значение в скобках это размер строки в байтах. Командой NOT NULL мы обозначили что значение в этом столбце не может быть равно NULL т.е. не может быть пустым.
  • status NVARCHAR(32) – третий столбец мы назвали status, тип – строковые данные переменного размера, размер – 32 байта, и раз мы не указывали NOT NULL – этот столбец может быть пустым.

Также создадим таблицу в которой будут перечислены возможные статусы пользователей:

CREATE TABLE users_status (id INT AUTO_INCREMENT PRIMARY KEY, status NVARCHAR(32));

Чтобы посмотреть все созданные нами таблицы используется команда:

SHOW TABLES;
sql show tables

Если нужно удалить отдельную запись из таблицы, то используется команда DELETE:

DELETE FROM users_nick WHERE id = 1;

Здесь мы сказали: УДАЛИ ИЗ ТАБЛИЦЫ users_nick ТАМ ГДЕ id РАВЕН 1.

Теперь нужно заполнить данными созданные нами таблицы т.е. добавить строки, для этого используется команда INSERT. Она может добавлять строки тремя способами:
– добавить полную строку
– добавить часть строки
– добавить результат запроса

Начнем с таблицы статусов:

INSERT INTO users_status (status) VALUES ('admin');

переводя на человеческий мы сказали: Добавь в таблицу users_status в столбец status значение admin. В приведенном мной примере название столбца и значение которое мы добавляем в скобки можно не брать, потому что мы добавляем одно значение в один столбец, но как правило нужно добавлять в несколько столбцов – разные значения, для этого в скобках, через запятую перечисляем вначале столбцы, а значения которые мы хотим вписать в соответствующий столбец после команды VALUES. Значения всегда должны быть в одинарных кавычках и не забывай, что значения надо указывать в том же порядке в котором мы перечисляли столбцы, но при этом этот порядок не обязательно должен соответвовать порядку столбцов в таблице:

INSERT INTO users_nick (id, nick) VALUES ('1', 'Pulse');

Как видишь, мы добавили только часть строки, пропустив столбец status, в такой ситуации туда будет записано значение NULL т.е . пусто, но только если мы не указывали параметр NOT NULL для этого столбца. Ну и, кстати столбец id по правильному тоже надо было бы пропускать, потому что он всё равно автоматически заполниться.

Если вдруг ты решил изменить какое-то значение в таблице для этого применяется команда UPDATE:

UPDATE users_status SET status = 'administrator' WHERE id = 1;

По сути мы сказали: ОБНОВИ значение в таблице users_status В СТОЛБЦЕ status на administrator ТАМ ГДЕ id=1. Используя WHERE мы задали условия для поиска нужной нам записи, тут нам как раз и понадобились наши идентификаторы, благодаря которым мы выбираем именно нужную строку. Кстати если не указать условие, используя WHERE мы обновим все значение в таблице, так делать не нужно.

Извлечение данных из таблицы

Получение данных из таблицы – это, наверное, одна из основных функций которую мы будем использовать чаще других. Для того чтобы извлечь данные из одной или нескольких таблиц используется команда SELECT. Для того чтобы эта команда была выполнена корректно нужно указать два параметра: что получить и откуда.
Так, например, что бы получить все имена пользователей из нашей таблицы, нам нужно написать:

SELECT nick FROM users_nick;
sql select

Таким образом мы увидели список пользователей из столбца nick таблицы users_nick. По такому же принципу мы можем вывести данные нескольких столбцов указав их через запятую, либо если мы хотим увидеть всю нашу таблицу, то вместо перечисления столбцов нужно поставить символ *

SELECT * FROM users_nick;
sql select

На человеческом это бы звучало так: ВЫБЕРИ всё ИЗ users_nick.

Как видишь всё очень просто, а сложности начнутся если в таблице будет несколько тысяч записей. И помимо очевидной сложности связанной с размером, записи будут выводится в непредсказуемом порядке. Это связанно с тем как СУБД использует память, как и когда записи добавлялись или редактировались, но почему это происходит нам не очень важно, а важно то что с этим делать. А потому нужно научится сортировке выводимых данных.

Для того чтобы разобраться с сортировкой я добавил в нашу таблицу users_nick несколько записей. Самым простым способом сортировки является использование условий, например:

SELECT * FROM users_nick WHERE status = 'user';
sql select

В этом запросе мы попросили железяку показать нам записи в таблице users_nick в которых, в столбце status присвоено значение user. При этом не забывай что в условии WHERE можно использовать логические операторы (AND/OR) и математические операторы сравнения (=, <, >, <=, >=, <>). Ну и не менее полезная штука, это поиск по шаблону, потому что мы не всегда знаем какая точно запись нам нужна, для этого используется команда LIKE:

SELECT * FROM users_nick WHERE status LIKE '%adm%';
sql select

Таким способом мы нашли пользователя, в столбце “статус” которого есть буквы adm, символ % означает любые символы в любом количестве (если нужно указать “один любой символ” используется нижнее подчеркивание _, кстати, это называется метасимволы и их конечно больше чем два). В SQL есть ещё такая штука, которую программисты (а может ещё кто-то) называют инверсией – это, типа наоборот, а если по правильному то это логический оператор означающий отрицание т.е. если в предыдущем примере перед LIKE написать NOT то в результате мы получим все записи в которых нет букв adm.

Также иногда нужно выбрать только уникальные значения в таблице, для этого используется команда SELECT DISTINCT, так например введя:

SELECT DISTINCT status FROM users_nick;

мы получим все уникальные значения из столбца status таблицы users_nick.

Также очень часто для сортировки данных используется команда ORDER BY. После которой мы должны указать имя одного или нескольких столбцов по которым и будут отсортированы выведенные данные. Самый простой пример её использования:

SELECT * FROM users_nick ORDER BY nick;
sql select

Здесь мы попросили отсортировать данные таблицы по столбцу nick, и в результате получили список пользователей в алфавитном порядке. Но это не единственны способ. Можно например, отсортировать данные не в алфавитном порядке (по возрастанию – если цифровые), но и в обратном порядке (по убыванию – если цифровые) для этого к названию столбца по которому фильтруем нужно дописать DESC.

Так как таблиц в базе данных несколько, то может возникнуть необходимость показать данные сразу из нескольких таблиц отфильтровав их по каким-нибудь общим значениям, Так например в нашей таблице с пользователями, пользователю Pulse не присвоен статус, но есть отдельная таблица со статусами, при этом общим параметром у нас будет id (хотя конечно логичнее было бы общим параметром использовать например ник, но да ладно, смысл от этого не меняется), для получения данных используем команду INNER JOIN:

SELECT users_nick.nick, users_status.status FROM users_status INNER JOIN users_nick ON users_status.id = users_nick.id;
sql select

По сути мы объединили записи из двух разных таблиц users_nick и users_status в одну, но взяв только тот результат в котором совпадают id. Я в этом примере показал именно INNER JOIN потому что это, вроде как считается “правильным” синтаксисом и красивым кодом, но по сути это тоже самое, что если бы мы написали:

SELECT nick, users_status.status FROM users_nick, users_status WHERE users_nick.id = users_status.id;

Оба варианта правильные и ты можешь использовать тот который тебе удобней.

Кстати обрати внимание, что когда мы используем команду SELECT и выбираем какие-то столбцы из разных таблиц, и при этом эти столбцы имеют одинаковые названия (как у нас столбец status есть в обеих таблицах) то нужно вначале написать какую таблицу мы имеем ввиду, потом поставить точку и написать столбец, иначе на выходе получим ошибку.

Также полезно помнить про существование итоговых функций, они нужны для получения, например характеристик таблицы:

  • COUNT (столбец) — возвращает количество строк;
  • SUM (столбец) — возвращает сумму значений в данном столбце;
  • AVG (столбец) — возвращает среднее значение данного столбца;
  • MIN (столбец) — возвращает наименьшее значение данного столбца;
  • MAX (столбец) — возвращает наибольшее значение данного столбца.

Например:

SELECT MAX(id) FROM users_nick;
sql select

покажет нам максимальное значение в столбце id таблицы users_nick.

При использовании команды SELECT стоит помнить про команду UNION которая позволяет объединить два запроса SELECT в один.

SELECT nick FROM users_nick WHERE nick='Pulse' UNION SELECT status FROM users_status;
sql union

В этом запросе мы сначала нашли пользователя с ником Pulse в одной таблице, а потом вывели все записи из из столбца status второй таблицы.

Некоторые нюансы языка SQL

Регистр символов.
Как ты мог заметить мы писали команды в верхнем регистре – на самом деле это не обязательно, язык SQL не чувствителен к регистру символов, а потому команды можно вводит как угодно: SELECT select Select – это всегда одна и та же команда, потому верхний регистр в командах и нижний в названиях столбцов и таблиц используется просто для удобства, но не забывай, что названия таблиц и столбцов к регистру чувствительны т.е. users_nick и USERS_NICK – это две разных таблицы.

Пробелы
Все лишние пробелы в SQL отбрасываются, потому, например, одна инструкция может быть записана на нескольких строках. Можешь использовать пробелы там где тебе удобней, это принципиально не на что не влияет.

Комментарии
Конечно в SQL есть комментарии. Символ решетки # поставленный в начале строки превратит её в комментарий. Если нужно создать многострочный комментарий то он должен начинаться с символов /* и заканчиваться */

На этом наше знакомство с базами данных и SQL можно считать оконченным. Конечно же в этой статье я дал только самые базовые знания, но их более-менее достаточно для понимания процессов происходящих с базами данных и самостоятельного более углубленного изучения SQL и всего что с ним связанно, в том числе изучения sql-инъекция, чем кстати мы займемся в следующих статьях на эту тему, а потому не забывай возвращаться к нам.

Твой Pul$e.