пʼятниця, 6 листопада 2015 р.

«Анатомия Oracle» Дэвида Литчфильда


  1. Это перевод первой статьи из цикла «Анатомия 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-логов.

    [​IMG]

    Тип файла

    Чтоб различать разные типы файлов в 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-лог как символьная строка, или любые другие данные для потребности, могут быть разделены хэдером.

    [​IMG]


    Здесь мы видим пример блок хэдера (желтый цвет), который разделил символьную строку - в этом случаи команду 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; 
    } 
    
    Если 16 бит высшего порядка не равняются 16 битам нижнего значит есть проблема с блоком. Контрол. сумму можно "исправить" используя XOR результата с текущей контрольной суммой.
    Например, припустим, что контрольная сумма в блоке 0x4E50, а результат DWORD после исполнения операций ХОR 0x59B109B1. Это значит 0x59B1 для верхнего ряда 16 бит и 0x09B1 для нижнего. XOR даст всумме 0x5000 (Если бы контр. сумма была правильная - выдал бы 0x0000. Итак, чтоб это исправить, мы просто используем XOR таким образом:

    0x4E50 ^ 0x5000 = 0x1E50

    Если б нам тогда нужно было изменить контр. сумму на эту (0x1E50) - она бы теперь подошла.

    Хэдер redo-лога

    Хэдер redo-лога намного интереснее хэдера файла и вмещает очень много информации: SID БД, версию БД и время, когда начался лог.

    [​IMG]

    На картинке мы видим 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; 
    } 
    
    Бесполезный факт: если установить системное время на день раньше 1/1/1998 то Oracle 10g не будет правильно работать.

    [Содержимое 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 сразу после него - ну мы припустим, что не знаем об этом. Посмотрим, как мы разберемся.

    [​IMG]

    Сначала мы видим запись - размером 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 пользоветелей.
    1. NeMiNeM

      NeMiNeMElder - Старейшина

      Регистрация:
      22.08.2005
      Сообщения:
      483
      Одобрения:
      305
      Репутация:
      118

      Пример на С, который показывает как сдампить запись 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(&timestamp,&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.
      Используя наш любимый хекс-редактор, открываем лог и ищем оффсет.

      [​IMG]


      Видим хэдер блока (0x122) возле оффсета 0x01FD7E00. Мы также можем увидеть текст DDL - в нашем случаи “create user wiggywiggywiggy identified by VALUES ‘2FA1749D698AD874’”, но нам нужно понять бинарный формат. Эта диаграмма поазывает, какие значения относятся к каким битам информации.



      [​IMG]

      Здесь видим, что пользователь SCOTT (105 байт в записи), пока его сессия относится к SYS , успешно исполнил команду DDL “CREATE USER”. Сказать, что сделал он это с помощью например SQL-инъекции или нет, тяжело без доказательств. Это мы рассмотрим позже. Теперь, нам важно, как можно прочесть бинарный формат операторов DDL.

      [​IMG]

      Простой и быстрый способ дампинга операторов 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.

      [​IMG]

      Это особенно важно для исследователя. Только потому, что команда 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]. После этого, производится инъекция курсора в уязвимую процедуру.


      [​IMG]

      Заметив, что 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 между каждого слова. Как это выглядит в логах?

      [​IMG]

      Пока мы не видим признака 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, всё равно новый лог-файл будет иметь записи о попытке стереть файл.

      [​IMG]


      Это диаграмма показывает, что пользователь 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 дампов не могут показать.

    пʼятниця, 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 р.

    Механизмы обеспечения транзакций



    Уровни изоляции, установленные стандартом, во-первых, определены недостаточно четко, во-вторых, не являются обязательными для начального уровня соответствия стандарту. Стандарт также не предусматривает того, как обеспечивается изоляция. Поэтому реальные СУБД достаточно по-разному трактуют изолированность транзакций и используют разные механизмы для обеспечения свойств ACID, в том числе и свойств параллельности.

    5.4.1 Механизмы DB2

    В DB2 для обеспечения атомарности транзакций применяется "упреждающее протоколирование", при котором изменения в данных записываются в журнальный файл прежде, чем транзакция фиксируется. Изменения в данных производятся в журнальных файлах и лишь при фиксации транзакции переносятся в основную область данных СУБД. Журнал используется для повторения или отката транзакций в случае сбоя.
    В основе механизма обеспечения изоляции DB2 лежат блокировки. Суть блокировки состоит в том, что если для выполнения транзакции требуется гарантия того, что определенный объект не будет изменен параллельно выполняющейся транзакцией, объект блокируется, то есть, запрещается доступ к нему из других транзакций.
    В самом простом случае СУБД обеспечивает блокировки двух типов:
    • S-блокировка - разделяемая блокировка или блокировка чтения, допускающая совместный доступ к строке таблицы;
    • X-блокировка - эксклюзивная блокировка или блокировка записи, не допускающая совместного доступа к строке.
    Прежде чем считать (select) какую-либо строку из таблицы транзакция должна установить для строки S-блокировку. Прежде чем обновить (update, delete, insert) строку таблицы транзакция должна установить для строки X-блокировку. Если для строки уже установлена блокировка, несовместимая с той, которую пытается установить наша транзакция, то попытка нашей транзакции отвергается, транзакция переводится в ожидание до того момента, пока ранее установленная блокировка не будет снята. Совместимость блокировок показана в следующей таблице.
      S  X 
     S данет
     X нетнет
    Тот или иной режим изоляции определяется той или иной комбинацией проверки и установки блокировок чтения.
    Для уменьшения объема проверяемых при любом доступе блокировок вводятся дополнительные типы блокировок, называемые блокировками намерения. Блокировки намерения накладываются на всю таблицу перед наложением S- или X-блокировки на строку таблицы. Основной набор блокировок намерения следующий (хотя в действительности DB2 этот набор несколько шире):
    • IS - блокировка намерения чтения. Накладывается на некоторую таблицу T и означает намерение блокировать некоторую входящую в T строку в режиме S-блокировки.
    • IX - блокировка намерения записи. Накладывается на некоторую таблицу T и означает намерение блокировать некоторую входящую в T строку в режиме X-блокировки.
    • SIX - блокировка чтения с намерением записи. Накладывается на некоторую таблицу T и означает разделяемую блокировку всей этой таблицы с намерением впоследствии блокировать какие-либо входящие в нее строки в режиме X-блокировок.
    Совместимость блокировок с учетом блокировок намерения показана в следующей таблице:
     ISSIXSIXX
    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         130
    
    5.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         101
    
    5.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=11 
     2UPDATE example SET dat=112 WHERE id=2
    UPDATE example SET dat=111 WHERE id=23 
     4UPDATE example SET dat=102 WHERE id=1
    Транзакция T1 должна заблокироваться на шаге 3, а транзакция T2 - на шаге 4. Единственным способом "развязки" тупика является принудительное освобождение одной из транзакций удерживаемого ею критического ресурса.
    Обе СУБД обнаруживают и развязывают тупики. Дойдя до зависания обеих транзакций на шагах 3-4, обе СУБД после некоторой временной выдержки развязывают тупик, но делают это несколько по-разному. DB2 принудительно откатывает одну из транзакций с сообщением об ошибке, вторая транзакция при этом разблокируется и завершается. Oracle откатывает только оператор UPDATE одной из транзакций с сообщением об ошибке. Вторая транзакция при этом продолжает оставаться заблокированной. Транзакция, в которой был выполнен откат оператора, теперь должна явным образом завершиться (зафиксироваться или откатиться), только после этого будет разблокирована другая транзакция.

    5.4.5 Эскалация блокировок

    Поскольку каждый доступ к строке таблицы включает в себя проверку наложенных на строку блокировок, большое число блокировок может привести к замедлению доступа. В DB2 при достижении числом блокировок некоторого предустановленного порога (он задается в параметрах базы данных) происходит эскалация блокировок, наложение блокировок на более крупный объект. Так, если блокируется большое число строк в таблице, то эти блокировки переводятся в блокировку всей таблицы. Эскалация блокировок повышает эффективность выполнения приложения, но влечет за собой увеличение числа блокировок в параллельно выполняющихся транзакциях.
    В Oracle нет концепции эскалации блокировок, так как Oracle, исходит из предположения, что большого числа блокировок быть не должно. Но нехватка памяти для размещения списка блокировок приводит к блокировке всего приложения.

    Сценарии возникновения нежелательных эффектов (потерянные изменения, грязное чтение...)



    Проиллюстрируем нежелательные эффекты, возникающие при параллельном выполнении транзакций на примере таблицы EXAMPLE. Мы предполагаем, что в начале выполнения каждого следующего пункта содержимое этой таблицы возвращается к исходному, а именно:
    Таблица EXAMPLE
    id INTEGERdat INTEGER
    1100
    2110
    3120
    4130

    5.3.1 Потерянные изменения

    Транзакция T1ШагТранзакция T2
    UPDATE example SET dat=dat+1 WHERE id=11 
     2UPDATE example SET dat=dat+1 WHERE id=1
    COMMIT3 
     4COMMIT
    SELECT * FROM example5 
    Если потерянные изменения допускаются, то сценарий выполнится без ошибок и блокировок. На шаге 5 будет выбрано:
            id         dat 
    ---------- -----------
             1         101
             2         110
             3         120
             4         130
    

    5.3.2 Грязное чтение

    Транзакция T1ШагТранзакция T2
     1UPDATE example SET dat=101 WHERE id=1
    UPDATE example SET dat= (SELECT dat FROM example WHERE id=1) WHERE id=22 
    SELECT * FROM example3 
     4ROLLBACK
     5SELECT * 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=11 
    [COMMIT]2UPDATE example SET dat=101 WHERE id=1
     3COMMIT
    SELECT * FROM example WHERE id=14 
    COMMIT5 
    Если неповторяющееся чтение допускается, то сценарий выполнится без ошибок и блокировок. Операцию 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>1101 
    [COMMIT]2INSERT INTO example VALUES(5,140)
     3COMMIT
    SELECT * FROM example WHERE dat>1104 
    COMMIT5 
    Если допускаются фантомы, то сценарий выполнится без ошибок и блокировок. Операцию COMMIT в транзакции T1 на шаге 2 выполнять не придется.
    На шаге 1 будет выбрано:
            id         dat 
    ---------- -----------
             3         120
             4         130
    
    На шаге 4 будет выбрано:
            id         dat 
    ---------- -----------
             3         120
             4         130
             5         150
    

    Понятие транзакции и операторы COMMIT и ROLLBACK



    Транзакцией называется единица работы СУБД, то есть, такая последовательность операторов SQL, которая обрабатывается СУБД как единое целое. Транзакция характеризуется четырьмя основными свойствами, часто называемыми свойствами ACID:
    • атомарность (atomity) - транзакция является неделимой, она выполняется полностью или не выполняется вообще; если транзакция прерывается на середине, то база данных должна остаться в том состоянии, которое она имела до начала транзакции;
    • параллельность (concurrency) - эффект от параллельного выполнения нескольких транзакций должен быть таким же, как от их последовательного выполнения; выполняющиеся транзакции не должны накладываться друг на друга;
    • целостность (integrity) - транзакция переводит база данных из одного непротиворечивого (целостного) состояния в другое; в ходе выполнения транзакции база данных может временно пребывать в нецелостном состоянии;
    • долговременность (duration) - после того, как транзакция завершена и зафиксирована, результат ее выполнения гарантированно сохраняется в базе данных.
    Объем транзакции может варьироваться от одного SQL-оператора до всех действий с базой данных, выполняемых приложением. В случае, если транзакции в приложении не определены явным образом, поведение приложения в этом отношении определяется состоянием режима 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 в DB2
    В Oracle откат транзакции к указанной точке сохранения безусловно снимает все блокировки, наложенные после точки сохранения. В DB2 эта возможность является выборочной, задаваемой при создании точки сохранения. Имена точек сохранения могут повторяться в транзакции (в DB2 может быть указано требование уникальности имени) если имена повторяются, то выполнение следующего оператора SAVEPOINT с тем же именем точки отменяет предыдущую точку сохранения.
    Выше мы отметили, что внутри транзакции состояние базы данных в принципе может быть нецелостным. В 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АномалииDB2Oracle
    А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 - Фантом
    Кроме названных, в Oracle имеется еще уровень изоляции READ ONLY - для только-читающих транзакций.
    В Oracle требуемый уровень изоляции может быть установлен для сеанса соединения с базой данных - как одна из возможностей оператора ALTER SESSION или для отдельной транзакции оператором SET TRANSACTION. Синтаксис этих операторов показан на рис. 5.4.

    Рисунок 5.4 - Операторы ALTER SESSION и SET TRANSACTION (Oracle)
    В DB2 уровень изоляции устанавливается для приложения, и способы его установки различны для разных способов разработки приложений. При работе в среде DB2 Command Line Processor или DB2 Command Center уровень изоляции устанавливается перед соединением с базой данных оператором CHANGE ISOLATION:

    Рисунок 5.5 - Операторы CHANGE ISOLATION (DB2)

    пʼятниця, 15 травня 2015 р.

    Alexander Ryndin: Использование GoldenGate Director для управления интеграцией


    Использование GoldenGate Director для управления интеграцией

    АРХИТЕКТУРА GOLDENGATE DIRECTOR

    GoldenGate Director (сейчас это называется GoldenGate Management Pack) — это многозвенное клиент-серверное приложение, обеспечивающее возможность конфигурирования и управления экземплярами(instances) GoldenGate с удаленного рабочего места. GoldenGate Director состоит из следующих компонент:
    image
    Экземпляры 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;
    Инсталляция
    1. Скачиваем дистрибутив с http://edelivery.oracle.com из раздела Fusion Middleware
    2. Запускаем инсталляцию ggdirector-serversetup_<version>
    3. Welcome screen: Нажимаем Next.
    4. Choose Installation Location: Вводим каталог, в который инсталлируем Director
    5. Weblogic Location: Вводим путь к каталогу, который на один уровень выше wlserver_10.3.1 (по-умолчанию это каталог Middleware). Этот каталог используется для поиска пути к каталогу с доменами.
    6. HTTP port: вводим порт, который будет использоваться. По умолчанию используется порт 7001.
    7. Database: Указывается тип базы данных.
    8. Database driver configuration: Прописываем информацию необходимую для подключения к базе данных.
    9. Database User: Указываем имя пользователя и пароль для создания репозитория.
    10. Pre-installation summary: Жмем Next.
    11. Затем жмем Finish.
    Запуск и останов GoldenGate Director.
    ДействиеWindowsUnix и Linux
    Запускdomain\startWebLogic.cmddomain/startWebLogic.sh
    Остановdomain\bin\stopWebLogic.cmddomain/bin/stopWebLogic.sh
    Подключение к GoldenGate Director

    НАСТРОЙКА GOLDENGATE DIRECTOR

    Для того, чтобы управлять инфраструктурой с помощью GoldenGate Director необходимо настроить подключения к каждому установленному GoldenGate Manager. Кроме того, необходимо настроить пользователей, которые будут использоваться при управлении GoldenGate Director.
    Для этих целей используется инструмент GoldenGate Director Administrator. Проинсталлировать его можно перейдя по ссылке :/download»>http://<servername>:<port>/download. После запуска мы получаем окно входа в систему:
    image
    Имя и пароль по умолчанию — admin. После первого запуска рекомендуется сменить этот пароль. Имя сервера необходимо вводить вместе с  номером порта, на котором слушает weblogic (по-умолчанию 7001).
    Учетные записи мы сейчас трогать не будет, поэтому сразу перейдем на вторую закладку, на которой регистрируются источники данных:
    image
    На этой закладке для каждой базы данных, для которой будет производиться  репликация. На этой закладке более менее все понятно
    image
    После того, как все настроено можно перейти на закладку Monitor Agent и попробовать перезапустить агентов.

    НАСТРОЙКА РЕПЛИКАЦИИ

    После настройки источников данных мы запускаем толстый клиент Oracle GoldenGate-Director. Жмем кнопку Login и вводим того же пользователя admin, что и ранее.
    image
    Создаем новую диаграмму, на которую перетаскиваем нужные источники данных:
    image
    Далее в простейшем случае мы можем перетащить с закладки Add new действие Capture and Delivery на источник. Необходимые действия на настройки репликации.
    image

    МОНИТОРИНГ РАБОТЫ ПРОЦЕССОВ GOLDENGATE

    Для мониторинга сервисов можно использовать как толстый клиент, так и веб-клиент, расположенный по адресу :/acon»>http://<servername>:<port>/acon
    image

    ЗАКЛЮЧЕНИЕ

    Инструмент GoldenGate Director — это мощное, но достаточно простое в использовании средство настройки репликации данных, а также готовое средство мониторинга процессов, участвующих в передаче данных.
    Вследствие своей архитектуры GoldenGate Director обеспечивает единый взгляд на процессы репликации для всех пользователей вне зависимости от того, с какого сервера произведен вход в систему.
    Для одних задач удобно применять веб-клиент, а для других — удобнее толстый клиент. Кроме того, GoldenGate обеспечивает инфраструктуру для настройки уведомления администратора при возникновении заданных событий.