СтатьиАдминистрирование

Защита базы данных MySQL от SQL инъекций с помощью GreenSQL
n0xi0uzz
06 сентября 2008 09:25



Теги: mysql, sql, security, greensql

Перевод статьи Ben Martin «Protecting your MySQL database from SQL injection attacks with GreenSQL»

Атаки типа SQL инъекций могут позволить взломщикам выполнить случайные SQL запросы к вашей базе данных через ваш сайт. Чтобы избежать таких атак, любые данные, отправляемые пользователем в форме через HTTP POST или CGI-параметры, или другими способами, должны проверяться, не содержат ли они неожиданной информации. GreenSQL является фаерволом для SQL, — он расположен между вашим сайтом и базой данных MySQL и решает, какие SQL-выражения должны или не должны быть выполнены. Именно в этом выполнении я нашел несколько «открытых дверей».

GreenSQL сделана для использования в качестве прокси для базы данных MySQL. Вместо подключения напрямую к базе данных MySQL, ваш сайт подключается к GreenSQL. GreenSQL направляет допустимый SQL-запрос к базе данных MySQL и возвращает результат. Если GreenSQL обнаружит запрещенный запрос, содержащий недопустимый или подозрительный SQL, он заблокирует этот запрос и вернет пустые данные в качестве результата без обращения к базе данных MySQL. Чтобы ознакомится с атаками SQL инъекций, которые GreenSQL блокирует, посмотрите демонстрационную страницу.

GreenSQL нет в репозиториях дистрибутивов Fedora, OpenSuSe или Ubuntu. Он доступен в качестве 1-Click установки для OpenSuSe 10.3 и для Fedora 8. Страница загрузки включает в себя пакеты для Fedora 7, OpenSuSe 10.2, FreeBSD и Ubuntu Feisty Fawn и выше. В этой статье я произведу установку из исходного кода на 64-битном компьютере с Fedora 9, используя greensql-fw версии 0.8.4.

Установка не использует автоматических утилит и вам придется настроить вещи, вроде конфигурационных файлов, пользователей системы, настроки MySQL, настройки лога и файлов /etc/init.d вручную. Вся процедура хорошо задокументирована в install.txt. Ещё улучшает процесс то, что, выполнив несколько шелл-скриптов в директории скриптов, вы можете завершить большую часть установки. Чтобы скомпилировать приложение, просто выполните make в главной директории, как показано ниже. На Fedora 9 я получил следующую ошибку вскоре после начала компиляции, которая возникла из-за отсутствия libevent-devel:
$ tar xzf /.../greensql-fw-0.8.4.tar.gz
$ cd greensql-fw-0.8.4/
$ make
...
connection.hpp:29: error: field 'proxy_event' has incomplete type
connection.hpp:30: error: field 'client_event' has incomplete type

Как только я установил libevent-devel, я обнаружил, что мне необходимо отредактировать /usr/include/event.h, чтобы включить sys/types.h для компиляции кода.
vi /usr/include/event.h
...
#include <sys/time.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdarg.h>

На этой стадии, make -k завершился с ошибкой на нескольких файлах, вызывающих строковые функции, такие, как strcasecmp без включения заголовочного файла string.h. В зависимости от того, какую версию gcc вы используете, следующие проблемы могут не возникнуть при компиляции GreenSQL.
$ cd src
$ vi mysql/mysql_con.cpp 
...

#include <string.h>
#include "mysql_con.hpp"
...

$ vi config.hpp 
...
#ifndef GREEN_SQL_CONFIG_HPP
#define GREEN_SQL_CONFIG_HPP

#include <string.h>
...

$ vi ../src/parser/expression.hpp
...
#ifndef _SQL_EXPRESSION_HPP_
#define _SQL_EXPRESSION_HPP_

#include <string.h>
...

Если вы собираете GreenSQL на 64-битном дистрибутиве, вам также придется слегка отредактировать Makefile так, чтобы сборка проверяла lib64 вместо простой проверки директории lib, как показано ниже:
$ vi src/Makefile
...
LIBS:=-L/usr/local/lib -L/usr/local/lib/mysql \
-L/usr/lib64/mysql -lmysqlclient -levent -lpcre

greensql-fw: $(OBJS)
...
$ make
Показанное ниже — команды для завершения установки, когда демон уже скомпилирован. Файл install.txt из пакета описывает ручную установку, которая использует те же команды, что и скрипты. Использование скриптов выглядит лучшим вариантом, так как процесс установки может быть улучшен (содержанием скриптов), в то время, как процедура остается прежней. Инструкции по установке рекомендуют настроить базу данных MySQL до директории /etc/greensql, но если вы это сделаете, вызов скрипта MySQL завершится с ошибкой при поиске файла настроек и вам придется изменить /etc/greensql/greensql.conf вручную. Это похоже на проблему курицы и яйца, но только одно изменение вы должны сделать в greensql.conf — получить параметры базы данных MySQL.
greensql-fw-0.8.4]# cd ./scripts/
# ./setup_user.sh
done...
# ./greensql-create-db.sh

---------------------------------------------
The following settings will be used:

MySQL admin user: [root]
MySQL admin password: []
MySQL server address: [127.0.0.1]

GreenSQL configuration DB name: [greendb]
DB user to create: [green]
Password to set: [pwd]

Do you want to change anything? [y/N] y

MySQL admin user [root]: 
MySQL admin password []: XXxxXXxxXXxx-FIXME
MySQL server address (you can use ip:port string) [127.0.0.1]: 
GreenSQL config db name [greendb]: 
GreenSQL DB user name [green]: greendb
GreenSQL DB user password [pwd]: greendbpass
---------------------------------------------
The following settings will be used:
Do you want to change anything? [y/N] 


Creating MySQL database...
Adding MySQL user...
Creating MySQL tables...

GreenSQL configuration file is not writable!!!
Check that [database] section contains the following settings in
/etc/greensql/greensql.conf

[database]
dbhost=127.0.0.1
dbname=greendb
dbuser=greendb
dbpass=greendbpass
# dbport=3306
...
# ./setup_conf.sh
done...
# ./setup_log.sh 
done...
# ./setup_binary.sh
done...
# vi /etc/greensql/greensql.conf 
...
[database]
dbhost=127.0.0.1
dbname=greendb
dbuser=greendb
dbpass=greendbpass
...
# chkconfig  --add greensql 
service greensql does not support chkconfig

# /etc/init.d/greensql start

Для тестирования, я создал базу данных test и дал пользователю ben свободный доступ к ней, с помощью следующих команд:
# mysql -p
Enter password: 
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> GRANT ALL ON test.* TO ben@"%";
mysql> FLUSH PRIVILEGES;

По умолчанию, GreenSQL работает на 3305 порту, номер которого меньше на единицу стандартного порта MySQL — 3306. Если вы используете консольный клиенты mysql и подключитесь к GreenSQL на 3305 порт, вы не сможете создать новую таблицу, в то время, как показано в командах ниже, когда вы подключитесь напрямую к MySQL на порт 3306, вы сможете создать новую таблицу.
$ mysql --verbose  -h  127.0.0.1 -P 3305 test
mysql> create table foo ( id int );
--------------
create table foo ( id int )
--------------

Query OK, 0 rows affected (0.01 sec)

mysql> insert into foo values ( 55 );
--------------
insert into foo values ( 55 )
--------------

ERROR 1146 (42S02): Table 'test.foo' doesn't exist


$ mysql --verbose  -h  127.0.0.1   -P 3306 test
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> create table foo ( id int );
--------------
create table foo ( id int )
--------------

Query OK, 0 rows affected (0.01 sec)

mysql> insert into foo values ( 55 );
--------------
insert into foo values ( 55 )
--------------

Query OK, 1 row affected (0.00 sec)

mysql> insert into foo values ( 131 );
--------------
insert into foo values ( 131 )
--------------

Query OK, 1 row affected (0.00 sec)

mysql>  select * from foo;
--------------
select * from foo
--------------

+------+
| id   |
+------+
|   55 | 
|  131 | 
+------+
2 rows in set (0.00 sec)

Со стандартной конфигурацией GreenSQL, вы не сможете удалять таблицы через фаервол GreenSQL. Это хорошо, так как структура таблицы не меняется часто и, что более вероятно, не будет меняться из любого места интерфейса сайта.
$ mysql --verbose  -h  127.0.0.1   -P 3305 test
Welcome to the MySQL monitor. Commands end with ; or \g.

mysql>  select * from foo;
--------------
select * from foo
--------------

+------+
| id   |
+------+
|   55 | 
|  131 | 
+------+
2 rows in set (0.00 sec)

mysql> drop table foo;
--------------
drop table foo
--------------

Query OK, 0 rows affected (0.00 sec)

mysql>  select * from foo;
--------------
select * from foo
--------------

+------+
| id   |
+------+
|   55 | 
|  131 | 
+------+
2 rows in set (0.01 sec)

Тестирование инъекций не дало результата, на который я надеялся. Первым тестом было удаление кортежей, базированное на выражении, которое всегда возвращает true. Это вычистило все данные в таблицы и оставило схему таблицы пустой. По умолчанию такой запрос работает через фаервол.
$ mysql --verbose  -h  127.0.0.1   -P 3305 test

mysql> delete from foo where 1=1;
--------------
delete from foo where 1=1
--------------

Query OK, 2 rows affected (0.00 sec)

mysql>  select * from foo;
--------------
select * from foo
--------------

Empty set (0.00 sec)

Для вышеуказанной команды удаления, файл /var/log/greensql.log сохранил следующую информацию:
SQL_DEBUG: QUERY command[]: delete from foo where 1=1
SQL_DEBUG: AFTER NORM   : delete from foo where ?=?
SQL_DEBUG: RISK         : 0

Файл /etc/greensql/greensql.conf позволяет вам устанавливать, насколько рискованными вы считаете определенные вещи. Например, вы можете присвоить вес 10 испольщованию ключевого слова union или запросам с прямыми сравнениями (что-то вроде 1=2). Переменные содержат block_level = 30, так что любой запрос, риск которого выше 30 не будут перенаправлены к серверу MySQL. Пытаясь сделать пометку для GreenSQL для вышеуказанного запроса, я увеличил risk_var_cmp_var и risk_always_true с их стандартных 30 до 150. К несчастью, указанный запрос был указан как запрос с нулевым риском.

Так как вышеуказанный SQL-запрос может быть валидным, я произвел запрос, показанный в приведенных ниже логах со страницы MySQL SQL-инъекции с сайта GreenSQL. Эта SQL-инъекция основывается на вводе с сайта данных, предоставляемых пользователям в строку SQL-запроса и помещения его в базу данных. Он тоже был разрешен.
SQL_DEBUG: QUERY command[]: delete 
from foo where id=181 or 1=1
SQL_DEBUG: AFTER NORM   : delete 
from foo where id=? or ?=?
SQL_DEBUG: RISK         : 0

SQL_DEBUG: QUERY command[]: delete 
from s where comment = 'whatever' or '1'='1'
SQL_DEBUG: AFTER NORM   : delete 
from s where comment = ? or ?=?
SQL_DEBUG: RISK         : 0

После работы с помощью strace(1) и других попыток выяснить, почему GreenSQL помечает приведенные выше запросы как запросы с нулевым риском, я решил попробовать запрос SELECT. Он привел к тому, что GreenSQL сработал, как и ожидалось, заблокировав неправильный запрос, что и показывают следующие логи:
SQL_DEBUG: QUERY command[]: select * from folks 
where name='sam' or '1'='1'
SQL_DEBUG: AFTER NORM   : select * from folks 
where name=? or ?=?
DEBUG:     Query has 'or' token
DEBUG:     Variable comparison only
SQL_DEBUG: RISK         : 35

Исходя из того, что SQL-инъекция в выражении SELECT может позволить авторизироваться на сайте без пароля, использование GreenSQL обезопасит ваши SELECT-запросы. Я надеюсь, что в будущих релизах разработчики расширят защиту GreenSQL до выражений delete, так как такое выражение может полностью очистить таблицу.


Теги: mysql, sql, security, greensql

Статьи с такими же тегами:

Опасный код на C