Шрифт:
Интервал:
Закладка:
Как спрятать список пользователей/паролей
Если вы переименуете таблицу USERS и заново создадите USERS как просмотр переименованной таблицы, вы можете получить лучший из миров. У пользователей будет возможность изменять свои собственные пароли, а полный список пользователей и паролей будет спрятан для PUBLIC. Каждый пользователь, не являющийся SYSDBA, будет видеть только одну запись из security.fdb (или isc4.gdb, если у вас сервер версии 1.0.x). Новые структуры в security.fdb будут похожи на следующую схему:
/* Copyright Ivan Prenosil 2002-2004 */
CONNECT 'C:Program FilesFirebirdFirebird_1_5security.fdb'
USER 'SYSDBA' PASSWORD 'masterkey';
/** Переименование существующей таблицы USERS в USERS2. **/
CREATE TABLE USERS2 (
USER_NAME USER_NAME,
SYS_USER_NAME USER_NAME,
GROUP_NAME USER_NAME,
UID UID,
GID GID,
PASSWD PASSWD,
PRIVILEGE PRIVILEGE,
COMMENT COMMENT,
FIRST_NAME NAME_PART,
MIDDLE_NAME NAME_PART,
LAST_NAME NAME_PART,
FULL_NAME COMPUTED BY (first_name || _UNICODE_FSS ''II middle_name || _UNICODE_FSS ' ' || last_name ) ) ;
COMMIT;
INSERT INTO USERS2
(USER_NAME, SYS_USER_NAME, GROUP_NAME,
UID, GID, PASSWD, PRIVILEGE, COMMENT,
EIRST_NAME, MIDDLE_NAME, LAST_NAME)
SELECT
USER_NAME, SYS_USER_NAME, GROUP_NAME,
UID, GID, PASSWD, PRIVILEGE, COMMENT,
EIRST_NAME, MI DDLE_NAME, LAST_NAME FROM USERS;
COMMIT;
/* */
DROP TABLE USERS;
/* */
CREATE UNIQUE INDEX USER_NAME_INDEX2 ON USERS2(USER_NAME);
/** Создание просмотра, который будет использован вместо первоначальной таблицы USERS. **/
CREATE VIEW USERS AS
SELECT *
FROM USERS2
WHERE USER = ''
OR USER = 'SYSDBA'
OR USER = USER_NAME;
/** Полномочия **/
GRANT SELECT ON USERS TO PUBLIC;
GRANT UPDATE (PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME)
ON USERS
TO PUBLIC;
Реальная таблица USERS2 видима только для SYSDBA. Следующее условие
USER = USER_NAME
гарантирует, что каждый пользователь видит только свою собственную запись. Условие
USER = 'SYSDBA'
гарантирует, что SYSDBA может видеть все записи. Условие
USER = ' '
является важным, потому что переменные USER и CURRENT_USER содержат пустые строки в процессе проверки пароля.
! ! !
ПРИМЕЧАНИЕ. К сожалению, две следующие техники не могут быть реализованы в сервере Firebird 1.5. Они используют запись в файлы протоколов. Улучшения безопасности, выполненные в версии 1.5, означают, что подпрограмма идентификации пользователя теперь выполняется в транзакции только для чтения, следовательно, невозможно выполнять запись в протокол! Похожая схема может быть реализована путем делегирования функции протоколирования внешним функциям.
. ! .
Как запротоколировать попытки соединения с базой данных
Замена таблицы USERS в базе данных безопасности на просмотр USERS имеет одно большое преимущество: она позволяет нам вызывать хранимую процедуру, когда пользователь пытается соединиться с базой данных. Когда сервер Firebird выполняет оператор
SELECT PASSWD FROM USERS
WHERE USER_NAME = ?;
мы можем выполнить процедуру, которая действует как триггер выбора или триггер соединения. Эта процедура может быть написана таким образом, что она, например, будет отвергать подключения в некоторые часы дня или протоколировать время, когда пользователи пытаются подключиться к базе данных.
Мы можем протоколировать только имена известных пользователей - т. е. только тех пользователей, имена которых уже хранятся в таблице USERS - и не существует возможности сообщить, было ли подключение успешным. Однако даже такая ограниченная информация, которую мы можем внести в протокол, является полезной. Это может проинформировать нас о попытках подключения в необычное время, что позволит обнаружить множество подозрительных подключений за короткий промежуток времени.
Для подобной реализации нам нужна таблица для протокола и хранимая процедура для выполнения работы.
Таблица протоколаТаблица протокола должна быть внешней таблицей, потому что транзакция, используемая сервером для идентификации пользователей, не подтверждается, а откатывается. Для внешних таблиц не выполняется отмена записанных данных при откате транзакции, как это происходит при добавлении данных в обычную таблицу.
CREATE TABLE,log_table
EXTERNAL FILE 'C:Prograin FilesFirebirdFirebird_1_5security.log' ( tstamp TIMESTAMP, uname CHAR(31) );
Если вы хотите, чтобы таблица протокола была читаема как текстовый файл, вы должны использовать CHAR(20) вместо TIMESTAMP, выполняя необходимые преобразования, и добавить еще два столбца: одиночный CHAR для разделения столбцов времени (tstamp) и имени (uname) и CHAR(2) для заполнения кодами возврата каретки и перевода строки.
Процедура подключенияХранимая процедура имеет тип процедуры выбора, которую можно вызывать из просмотра. Если соединение успешное, происходит обращение к SUSPEND, и строка записывается в протокол. Если соединение ошибочное по той причине, что запрашиваемая из просмотра строка запрещена, то процедура просто завершается, не записав ничего в протокол. Выходной параметр является простой формальностью, его значение игнорируется.
CREATE PROCEDURE log_proc
(un VARCHAR(31)) RETURNS
(x CHAR(1) )
AS
BEGIN
IF (USER = '') THEN
INSERT INTO log_table (TSTAMP, UNAME) VALUES ( CURRENT_HMESTAMP, :un);
/* и не забудьте изменить записанные поля, если вы изменили таблицу log_table, чтобы сделать ее текстовым файлом! */ IF (USER = '' OR USER = 'SYSDBA' OR USER = :un) THEN SUSPEND;
END
Мы проверяем (USER = ''), потому что, когда Firebird проверяет пароль, переменная USER пустая. Это помогает отличить, когда сервер проверяет пароль, а когда пользователь напрямую соединяется с базой данных безопасности.
Реализация новой установкиНам нужно удалить просмотр, который использовался в нашей реструктурированной базе данных безопасности, и создать новую версию, которая вызывает хранимую процедуру:
CREATE VIEW USERS (USER_NAME) AS SELECT * FROM users2
WHERE EXISTS (SELECT * FROM logjproc(users2.user_name));
He забудьте восстановить полномочия, которые были потеряны при удалении просмотра:
GRANT SELECT ON USERS TO PUBLIC;
*/
GRANT UPDATE (PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME) ON USERS TO PUBLIC;
Нужно добавить несколько новых полномочий, связанных с хранимой процедурой:
GRANT INSERT ON log_table TO PROCEDURE log_proc; GRANT EXECUTE
ON PROCEDURE log_proc TO PUBLIC;
Поскольку записи протокола посотянно добавляются в log_table, будет нужно удалять или переименовывать внешний файл время от времени. База данных безопасности и, следовательно, внешний файл освобождаются после завершения идентификации пользователя, так что переименование файла не должно вызвать проблем.
Как остановить злоумышленников
Поскольку мы способны протоколировать имена пользователей, которые пытались подключиться к базе данных, и время этих попыток, мы можем использовать эту информацию для дальнейшего ограничения доступа.
Например, можно подсчитать количество попыток подключений конкретного пользователя в течение последней минуты и, если это количество достигает некоторого
предела, блокировать соединение для данного имени пользователя. Это позволит нам установить некоторую защиту против грубых атак, когда кто-то пытается проникнуть в базу данных, многократно сканируя возможные пароли. Мы можем установить временную блокировку для любого имени пользователя, чье поведение похоже на атаку.
Интервал времени и ограничение на количество подключений должны выбираться аккуратно, чтобы остановить злоумышленников, а не наказать добросовестного пользователя, который просто плохо набирает текст. Open VMS использует похожий подход.
Соответствующий фрагмент кода хранимой процедуры выглядит следующим образом:
. . .
DECLARE VARIABLE Cnt INTEGER;
SELECT COUNT(*)
FROM log_table
WHERE uname = :un
AND tstamp > CURRENT_TIMESTAMP - 0.0007
INTO :cnt;
IF (cnt >= 3) THEN EXIT;
Вы можете изменять константы, а именно 3 (допустимое количество ошибок) и 0.0007 (интервал, приблизительно равный одной минуте). Эта процедура действует для всех пользователей.
Одной из возможных модификаций может быть выбор одного пользователя, не являющегося SYSDBA (не SYSDBA, потому что пользователь SYSDBA, скорее всего, и будет выбран для атак), и исключение его из блокирующей процедуры. Сделайте этого пользователя владельцем всех баз данных, наделив его правами на выполнение останова базы данных.
Пора дальшеЯсно, что безопасность на уровне сервера в Firebird имеет недостатки. В следующей главе обсуждается поддержка в Firebird полномочий SQL, которые могут быть реализованы для всех баз данных. Применение полномочий SQL запутанно, однако при аккуратном использовании они предоставляют основной внутренний уровень безопасности данных баз данных в системах, которые адекватно защищены от краж.
ГЛАВА 35. Безопасность на уровне базы данных.
Безопасность на уровне базы данных в Firebird решает две задачи: во-первых, не разрешить доступ пользователей, идентифицированных на сервере, к данным в вашей базе данных, и, во-вторых, предоставить доступ пользователям, которые работают с вашей базой данных. Средствами реализации такой безопасности на уровне базы данных являются привилегии SQL.
Первая цель, блокирование ненужных пользователей, авторизованных на сервере, используется в средах, где базы данных, которыми владеют многие объекты, запущены на одном сервере - обычно, на сайте, где выполняются сервисы для множества заказчиков. В подобных ситуациях заказчики провайдера обычно не имеют доступа SYSDBA.
- C++ - Страустрап Бьярн - Программирование
- Энциклопедия разработчика модулей ядра Linux - Ори Померанц - Программирование
- Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп - Программирование