Инструментарий системного администратора: Проверка правильности конфигурации системы

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

Мартин Браун (Martin C. Brown) , Внештатный автор и консультант компании MCslp, Свободный писатель

Мартин Браун – бывший руководитель IT подразделения с опытом работы в области межплатформенной интеграции. Обладая большим опытом разработчика, он создал динамические сайты для множества крупных клиентов, включая HP и Oracle, и на данный момент является техническим директором ресурса Foodware.net. В настоящее время Мартин в качестве внештатного автора и консультанта сотрудничает с корпорацией Microsoft, работает редактором (LAMP Technologies Editor) журнала LinuxWorld, является видным членом группы AnswerSquad.com. Его перу принадлежат книги на совершенно разные темы: от сертификации Microsoft, компьютеры iMac до программирования открытого исходного кода. При всем этом он продолжает плодотворно работать в области программирования для разных платформ и сред. Связаться с Мартином можно посредством его персонального Web-сайта по адресу http://www.mcslp.com.



28.05.2010

Об этой серии статей

Обычно администратор UNIX® регулярно применяет ряд утилит, приемов и систем. Для упрощения различных процессов можно использовать стандартные утилиты, интерфейс командной строки и сценарии. Часть этих инструментов поставляется вместе с операционной системой, но большая часть приемов нарабатывается на основе практического опыта и желания администратора упростить свою жизнь. Цель этой серии статей – рассказать о большинстве доступных инструментов для различных UNIX-систем, включая средства упрощения администрирования гетерогенных сред.

Проверка содержимого файлов

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

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

Итак, как проверить содержимое файлов?

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

  • содержимое файла;
  • владелец файла;
  • группа владельца;
  • разрешения файла;
  • время изменения;
  • время создания.

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

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

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

location:/home/mcbrown

И тот же самый файл с измененной строкой:

location:/home/slbrown

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

Как и другие параметры, время изменения, флаг и другая информация могут быть изменены, например, можно подменить время изменения при помощи команды touch. Даже время создания файла можно подделать, изменив системное время и создав файл заново.

Существует параметр, который изменить намного сложнее – это inode. Inode – это уникальный идентификатор, присваиваемый файлу при создании. Inode используется низкоуровневыми драйверами файловой системы для идентификации файла. Inode часто меняется при редактировании файла, потому что большинство редакторов создают новый файл и записывают новое содержимое в этот файл перед удалением старого файла и переименовывают новый файл с именем старого. Это делает сравнение inode хорошим индикатором изменений файла.

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

Контрольная сумма файла

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

Механизм контрольных сумм основан на обработке содержимого файла и генерации почти уникального отпечатка его содержимого. Эту задачу можно выполнить различными способами. Например, можно добавить значение каждого байта наряду с использованием алгоритма, использующегося для сложного расчета отдельных битов или группы битов заданного файла. Окончательный выбор метода расчета контрольной суммы лежит за пределами этой статьи и зависит от используемого средства проверки контрольной суммы.

В UNIX имеется простая команда для работы с контрольными суммами – sum. Эта команда весьма ограничена по своим возможностям, но зато она создает достаточно уникальное число, которое можно использовать для обнаружения различий между большинством файлов. Однако у этого алгоритма есть и ограничения. Многие современные программы поддерживают команду md5, которая создает 128-разрядный отпечаток файла и теоретически может сгенерировать уникальную подпись для любого файла любого размера.

Алгоритм md5 для генерирования информации о контрольной сумме первоначально был разработан для создания уникальных отпечатков файлов до шифрования файлов с тем, чтобы гарантировать проверку целостности расшифрованных файлов. Контрольные суммы, созданные при помощи md5, могут быть представлены в виде двоичной строки, шестнадцатеричной строки или строки, закодированной методом base64. Последний формат используется в MIME-сообщениях электронной почты, чтобы обеспечить уникальный идентификатор для различных вложений.

Создание контрольных сумм файлов

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

Можно создать контрольную сумму двух файлов одной командой, как показано в листинге 1.

Листинг 1. Создание контрольной суммы двух файлов одной командой
$ sum old new
50093 1 old
62381 1 new

Хотя файлы отличаются один от другого только двумя символами, получаются две заметно различающиеся контрольные суммы. В листинге 2 показаны те же файлы, обработанные при помощи md5.

Листинг 2. Обработка файлов при помощи md5
$ md5 old new
MD5 (old) = 602f604720d3b57925e99bcaa7d931a4
MD5 (new) = c3f06c217a0f26c16f8d030837d8718b

Эти контрольные суммы значительно различаются, и не возникает сомнений, что эти файлы каким-то образом отличаются друг от друга.

Другим методом является использование Perl для создания информации о контрольных суммах. Для этого используется модуль Perl Digest::MD5, который способен создавать контрольные суммы MD5 из любой строки данных или указанного файла.

В листинге 3 показан простой скрипт, возвращающий контрольную сумму MD5 для загруженного файла в командной строке, в виде шестнадцатеричной строки (идентично формату, показанному в листинге 2).

Листинг 3. Скрипт, возвращающий контрольную сумму MD5
use Digest::MD5;
use IO::File;

my $chk = Digest::MD5->new();

foreach my $file (@ARGV)
{
    $chk->addfile(IO::File->new($file));

    print "$file -> ",$chk->hexdigest,"\n";
}

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

Листинг 4. Обработка тех же файлов при помощи Digest::MD5
$ simpmd5.pl old new
old -> 602f604720d3b57925e99bcaa7d931a4
new -> c3f06c217a0f26c16f8d030837d8718b

Для упрощения процесса необходимо записать полученную информацию в файл, чтобы позднее сравнить полученную информацию. Перед этим добавьте дополнительную информацию для сравнения (время изменения, размер файлов, владелец, inode и так далее).

Добавление в отчет дополнительной информации

Функция Perl stat() может получить из заданного файла множество информации, большинство которой можно использовать. Список информации, которую можно получить, приведен в листинге 5.

Листинг 5. Функция Perl stat()
 0 dev      номер устройства или файловой системы
 1 ino      inode
 2 mode     флаг файла (тип и разрешения)
 3 nlink    количество ссылок (в том числе жестких) на файл
 4 uid      числовой идентификатор владельца файла
 5 gid      числовой идентификатор группы владельца файла
 6 rdev     идентификатор устройства (только для специальных файлов)
 7 size     общий размер файла в байтах
 8 atime    время последнего доступа к файлу в секундах с начала эпохи
 9 mtime    время последнего изменения файла в секундах с начала эпохи
10 ctime    время изменения inode в секундах с начала эпохи (*)
11 blksize  размер блока файловой системы ввода-вывода
12 blocks   текущее количество используемых блоков

Можно записывать почти всю эту информацию, но часть ее бесполезна, поскольку либо слишком часто меняется, либо сбрасывается при перезагрузке. Как правило, следует исключить следующие параметры:

  • rdev—используется только для специальных файлов (устройств или конвейеров), и поэтому, как правило, его можно исключить.
  • atime—время последнего доступа меняется при каждом обращении к файлу. Это означает, что файл будет выглядеть как измененный, даже если в действительности никак не менялся. Отслеживание этого параметра может привести к ложным срабатываниям системы сравнения.
  • blksize—используется в файловой системе ввода-вывода. Маловероятно, что этот параметр изменится, однако другие факторы, не связанные с изменением файла, могут привести к изменению значения этого параметра, поэтому его отслеживание для контроля целостности файлов не имеет смысла.
  • blocks—количество блоков, занятых файлом в файловой системе. Эта информация связана с файлом, но если размер файла уже контролируется, запись этого параметра будет лишней.

Следующие параметры используются для отслеживания в особых случаях:

  • dev—номер устройства в файловой системе должен быть постоянным вне зависимости от перезагрузок, если не происходит постоянного монтирования и отключения файловых систем. Если файловые системы монтируются в одинаковом порядке при каждой перезагрузке, номер устройства должен оставаться постоянным.
  • nlink—количество фиксированных ссылок на файл может выявить создание фиксированной ссылки на файл в месте, куда этот файл можно перезаписать и обойти разрешения исходного файла. Нельзя иметь фиксированную ссылку на файл с владельцем и разрешениями, отличающимися от исходного файла.
  • ctime—время изменения inode может меняться при создании файла или при изменении владельца или флага. Если изменился этот параметр, это может обозначать, что изменились соответствующие параметры файла, даже если затем они вернулись к исходным значениям.

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

Листинг 6. Вывод пути к файлам, контрольной суммы и других данных на стандартное устройство вывода
#!/usr/local/bin/perl

use Digest::MD5;
use IO::File;
use strict;
use File::Find ();

my $chksumfile = 'chksums.dat';

use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

File::Find::find({wanted => \&wanted}, $ARGV[0]);

sub wanted {
    next unless (-f $name);

    my $fileinfo = genchksuminfo($name);

    printf ("%s\n",$fileinfo);
}

sub genchksuminfo
{
    my ($file) = @_;

    my $chk = Digest::MD5->new();

    my (@statinfo) = stat($file);
    
    $chk->add(@statinfo[0,1,2,3,4,5,7,9,10]);
    $chk->addfile(IO::File->new($file));
    return sprintf("%s:%s:%s",
                   $file,$chk->hexdigest,
                   join(':',@statinfo[0,1,2,3,4,5,9,10]));
}

Скрипт использует модуль Perl File::Find, который обрабатывает каталог и ищет все файлы и каталоги в указанном месте. Для каждого файла вызывается функция wanted(), а в этой функции для всех файлов вызывается функция genchksuminfo(). Она получает информацию при помощи stat() и возвращает строку с информацией о пути к файлу, контрольной суммой и дополнительными данными. В этом скрипте информация просто выводится на стандартное устройство вывода.

Каталог для сканирования указывается в качестве параметра команды. Для получения данных о контрольных суммах файлов в каталоге /etc используйте команду, показанную в листинге 7.

Листинг 7. Сканирование /etc
$ perl savemd5.pl /etc
/private/etc/6to4.conf:e6b1ba3e7683a0df9be21c9e9f5d1f6a:234881026:46788:
               33188:1:0:0:1152674600:1155914028
/private/etc/afpovertcp.cfg:dc7c89b0626d6e603131902d387816f7:234881026:30152:
               33188:1:0:0:1151780398:1166194017
/private/etc/aliases:de483c306c03f35dcbd45d609f8e68ce:234881026:47440:
              33188:1:0:0:1151828538:1155914028
/private/etc/aliases.db:aa95ae673dcb6ba89684a6f4bbe3dba5:234881026:47437:
              33188:1:0:0:1151828588:1155914028
/private/etc/authorization:39f7938ae1df629d422b27ec1a17f3dd:234881026:950752:
              33188:1:0:0:1162503594:1162503594
/private/etc/auto.mnt:3da7579cdc03c529059a42de51c6679e:234881026:1013554:
              33188:1:0:0:1162728759:1162728759
/private/etc/auto.mnt~:54d856aa344d03a6084d63c9dd7e1d9c:234881026:1013530:
              33188:1:0:0:1162728576:1162728576
/private/etc/bashrc:fb23bdcacf23f69f1ce92e3b910c03b9:234881026:42880:
              33188:1:0:0:1151805563:1155914028
/private/etc/compilers:363c62792a79df85cd0c8d71ff274495:234881026:821586:
              33188:1:0:0:1159026690:1162503150
/private/etc/crontab:b9af1eb506bd68a43465789174bfe5e1:234881026:29678:
              33188:1:0:0:1151800085:1166193736
...

Заключительная стадия процесса состоит в сохранении информации и обеспечении способа сравнения текущего состояния с эталонным.

Проверка информации контрольной суммы

Итоговый скрипт (листинг 8) основан на коде из листинга 6. Этот скрипт значительно дополнен по сравнению с оригиналом, и включает в себя несколько новых функций:

  • Обработка параметров командной строки при помощи модуля Getopt::Long. С их помощью можно указать файл контрольной суммы (хранилище контрольной суммы и другой полученной информации), сравнивать или нет новую информацию с предыдущей (при помощи считывания содержимого chksumfile) и возможность назначить основной каталог для поиска. При сравнении файлов данные обновляются и отображаются только различия.
  • Функция loadchksumdata() для загрузки и обработки существующего файла данных позволяет без труда сравнить старую и новую информацию.
  • Функция gendiff report(), которая непосредственно сравнивает отдельные поля текущего и сохраненного состояний, чтобы сообщить об изменениях. Эта функция вызывается только в том случае, если известно, что имел место определенный тип изменений.
    Листинг 8. Итоговый скрипт
    #!/usr/local/bin/perl 
    
    use Digest::MD5;
    use IO::File;
    use strict;
    use File::Find ();
    use Getopt::Long;
    
    my $chksumfile = 'chksums.dat';
    my $compare = 0;
    my $basedir = '/etc';
    
    use vars qw/*name *dir *prune/;
    *name   = *File::Find::name;
    *dir    = *File::Find::dir;
    *prune  = *File::Find::prune;
    
    GetOptions("chksumfile=s" => \$chksumfile,
               "compare" => \$compare,
               "basedir=s" => \$basedir);
    
    my $chksumdata = {};
    
    if ($compare)
    {
        loadchksumdata($chksumfile);
    }
    
    my $outfile = '';
    
    if (!$compare)
    {
        $outfile = IO::File->new($chksumfile,"w");
    }
    
    File::Find::find({wanted => \&wanted}, $basedir);
    
    if ($compare)
    {
        foreach my $file (keys %{$chksumdata})
        {
            print STDERR "Couldn't find $file, but have the info on record\n";
        }
    }
    
    sub loadchksumdata
    {
        my ($file) = @_;
    
        open(DATA,$file) or die "Cannot open check sum file $file: $!\n";
        while(<DATA>)
        {
            chomp;
            my ($filename,$rest) = split(/:/,$_,2);
            $chksumdata->{$filename} = $_;
        }
        close(DATA);
    }
    
    sub wanted {
        next unless (-f $name);
    
        my $fileinfo = genchksuminfo($name);
    
        if ($compare)
        {
            if (exists($chksumdata->{$name}))
            {
                if ($chksumdata->{$name} ne $fileinfo)
                {
                    print STDERR "Warning: $name differs from that on record\n";
                    gendiffreport($chksumdata->{$name}, $fileinfo);
                }
                delete($chksumdata->{$name});
            }
            else
            {
                print STDERR "Warning: Couldn't find $name in existing records\n";
            }
        }
        else
        {
            printf $outfile ("%s\n",$fileinfo);
        }
    }
    
    sub gendiffreport
    {
        my ($orig,$curr) = @_;
    
        my @fields = qw/filename chksum device inode mode nlink uid gid size 
    		mtime ctime/;
    
        my @origfields = split(/:/,$orig);
        my @currfields = split(/:/,$curr);
    
        for(my $i=0;$i<scalar @origfields;$i++)
        {
            if ($origfields[$i] ne $currfields[$i])
            {
                print STDERR "\t$fields[$i] differ; was $origfields[$i], 
    			     now $currfields[$i]\n";
            }
        }
    
    }
    
    sub genchksuminfo
    {
        my ($file) = @_;
    
        my $chk = Digest::MD5->new();
    
        my (@statinfo) = stat($file);
    
        $chk->add(@statinfo[0,1,2,3,4,5,7,9,10]);
        $chk->addfile(IO::File->new($file));
        return sprintf("%s:%s:%s",
                       $file,$chk->hexdigest,
                       join(':',@statinfo[0,1,2,3,4,5,9,10]));
    }

Для использования этого скрипта вначале необходимо создать файл с эталонной контрольной суммой и другими данными, которые будут служить в качестве основы для сравнения. Например, для получения данных о контрольных суммах файлов в каталоге /etc можно использовать следующую команду:

$ genmd5.pl --basedir=/etc --chksumfile=etc-chksum.dat

Теперь, когда есть эта информация, если вы внесете изменения в файлы и запустите скрипт повторно, будет создан отчет об изменениях. В листинге 9 можно увидеть отчет об изменении файла /etc/hosts.

Листинг 9. Отчет об изменении файла /etc/hosts
$ genmd5.pl --basedir /private/etc --compare
Warning: /private/etc/hosts differs from that on record
        chksum differ; was d4a23fcdaa835d98ede1875503273ce6, 
		                now beb50782b3fd998f35786b1e6f503d1b
        inode differ; was 4879566, now 4879581
        size differ; was 1186929905, now 1186930065
        mtime differ; was 1186929905, now 1186930065
Couldn't find /private/etc/hosts~, but have the info on record

Обратите внимание, что в отчете выведена информация об изменении файла и об удалении файла. При создании новых файлов в отчет также добавляется информация.

Использование информации контрольной суммы

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

Нет четких и простых правил относительно этой информации, но должно быть ясно, что не стоит хранить полученный файл на той же машине, где он создан, иначе он может быть найден и изменен. То же самое относится к хранению файла на другой машине в той же сети. Как только файл будет обнаружен, он может быть модифицирован или подменен. Вероятно, лучшим решением будет записать файл на CD или DVD и хранить его отдельно от компьютера.

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

Хотя это немного усложняет процесс, преимущества защиты информации в этих файлах – бесценны.

Заключение

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

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

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=493091
ArticleTitle=Инструментарий системного администратора: Проверка правильности конфигурации системы
publish-date=05282010