歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> Unix基礎知識

系統管理工具包: 測試系統的有效性

關於本系列

典型的 UNIX® 管理員擁有一套經常用於輔助管理過程的關鍵實用工具、訣竅 和系統。存在各種用於簡化不同過程的關鍵實用工具、命令行鏈和腳本。其中一些工具來自於操作系統, 而大部分的訣竅則來源於長期的經驗積累和減輕系統管理員工作壓力的要求。本系列文章主要專注於最大 限度地利用各種 UNIX 環境中可用的工具,包括簡化異構環境中的管理任務的方法。

驗證文件內 容

建立組成 UNIX 系統的配置文件(必要時建立應用程序文件)是您希望系統長時間無故障運行 的一種方法。該方法還可以構成安全流程的關鍵部分,這樣不僅可保障系統有效,而且還可以保護系統的 安全配置。

盡管您的系統可能已經非常安全,任何人都無法進入並修改配置文件,但是您需要加 強自我保護,或至少能夠確定某人是否進入系統,並能夠驗證某人是否未經授權修改了配置文件(甚至任 何文件)。

那麼如何驗證文件內容呢?

這需要考慮許多不同的參數。如果在工作配置中更 改了所有以下項目,則可能會導致問題:

文件內容

文件所有者

組所有者

文 件權限

修改時間

創建時間

一個簡單的方法是在其他計算機上保存配置文件的副本 (及其關聯的參數),然後對本地文件和遠程文件進行常規比較。此方法帶來的問題是需要占用大量的空 間,更重要的是,需要花大量的時間記錄和比較這些信息。此方法還可能影響以實時方式比較信息。

另一個經常提議的方法是只記錄文件大小、修改時間、模式和所有權信息。因為與文件全部內容 相比,該信息比較短,更易於存儲和快速檢查和驗證。

問題是文件的大小無法確切指示內容是否 已更改。請考慮下面這個只包含一行的文件:location:/home/mcbrown

下面是一個 同樣大小的文件,但有一行已經更改:location:/home/slbrown

這兩個文件的長度 都是 22 個字符,但是內容不同,這種看似簡單的更改可能導致嚴重的後果,即使檢查文件大小,也查不 出有任何不同。

至於其他參數、修改時間、文件模式和其他信息都有可能被修改。您可以使用 touch 命令更改修改時間。甚至通過更改計算機上的時間和重新創建該文件可以偽造文件創建時間。

在 UNIX 系統上非常難以更改的一個項目是文件索引節點數值。索引節點數值是第一次創建文件 時提供給文件的唯一 ID。基礎文件系統驅動程序使用索引節點數值識別文件系統上的文件。在編輯文件 後,索引節點通常會發生更改,因為大多數編輯器在刪除舊文件並將新文件重命名為最初名稱之前會創建 新文件,並將新內容寫入該文件。因此,進行索引節點比較是檢查文件是否已編輯的很好方法。

記錄這些信息片段仍然是不夠的,還需要一種比較文件內容的有效方法。最好的方法可能要數使用文件校 驗和。

文件校驗和

為文件創建校驗和是比較文件內容是否更改的傳統方法,該方法無需物 理比較每個文件的每個字節。

校驗和的工作方法是對文件內容使用一個算法。該算法為文件內容 生成幾乎是唯一的指紋。可以通過許多不同的方法完成此任務。例如,可以將每個字節的值加起來,使用 一種算法將復雜的計算應用到給定文件的各個位或位組。具體方法不在本文的討論范圍之內,並且使用哪 種方法取決於您使用的校驗和工具。

UNIX 包括一個簡單的校驗和命令 sum。此命令非常簡單,但 是它提供了可用於識別大多數文件之間差異的近乎唯一的數值。不過,此算法也存在一些局限性。許多現 代解決方案提供了 md5 命令。後者生成一個文件的 128 位指紋,並且可以在理論上為任意大小的任何文 件生成唯一的簽名。

生成校驗和信息的 md5 算法最初是為在加密文件之前生成文件的唯一指紋而 開發的,這樣可以保證解密文件的有效性。可以將 md5 生成的校驗和表示為二進制字符串、十六進制字 符串或 base64 編碼字符串。在 MIME 電子郵件中使用了後一格式,以確保唯一地標識文件中不同的附件 。

為文件創建校驗和

因為存在用於創建校驗和信息的命令行解決方案,所以可以直接在命 令行上創建任何文件的校驗和。校驗和信息唯一程度的一個很好示例是使用先前演示的文件示例,該示例 具有相同的物理長度和內容,但只有字符不同。

您可以使用一個命令獲得兩個文件的校驗和,如 清單 1 所示。

清單 1. 使用一個命令獲得兩個文件的校驗和

$ sum old new
50093 1 old
62381 1 new

即使清單 1 中只有兩個字符不同,但獲得的校驗和數 字卻大相徑庭。清單 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

為使此流程派上用場,需要將信息記錄到文件中,這 樣可以將該信息與以後的信息進行比較。在執行此操作之前,將需要比較的其他信息(修改時間、文件大 小、所有權、索引節點等)添加到存儲數據中。

將其他數據添加到報告中

Perl stat() 函 數可以從給定的文件獲取完整的信息(可以使用其中的大多數信息)。清單 5 顯示了可以從該文件獲取 的信息列表。

清單 5. Perl stat() 函數

0 dev   device number of filesystem
1 ino   inode number
2 mode   file mode (type and permissions)
3 nlink  number of (hard) links to the file
4 uid   numeric user ID of file's owner
5 gid   numeric group ID of file's owner
6 rdev   the device identifier (special files only)
7 size   total size of file, in bytes
8 atime  last access time in seconds since the epoch
9 mtime  last modify time in seconds since the epoch
10 ctime  inode change time in seconds since the epoch (*)
11 blksize preferred block size for file system I/O
12 blocks  actual number of blocks allocated

您幾乎可以記錄所有這些信息,但是其中一些信息是毫無使用價值的, 因為這些信息或者更改得太頻繁,或者在重新啟動過程中不一致。應該忽略以下字段:

rdev—因為它僅對於特殊文件是唯一的(通常為驅動器或管道),所以可以忽略它。

atime—每次訪問文件後,文件的最後訪問時間都會更改。這意味著該文件很可能會更改, 即使從未使用任何方式修改過該文件也會如此。在差異報告中記錄該信息可能會導致誤確認。

blksize—用於文件系統 I/O 的塊大小。盡管它可能不會有更改,但是除文件修改外的其他 因素也可能導致此值的更改,因此,逐文件記錄該值沒有任何意義。

blocks—在文件系統上 為該文件分配的塊數。此信息特定於某個文件,但是如果還記錄文件大小,則同時記錄二者沒有什麼必要 。

以下字段對記錄某些特定原因非常有用:

dev—假設您沒有經常安裝和卸載文件系 統,則在重新引導過程中文件系統的設備號應該是一致的。如果在每次重新啟動時文件系統是按同一順序 安裝的,則設備號應該一致。

nlink—文件的硬鏈接數可以幫助識別是否有人在可以覆蓋文 件的位置創建了文件的硬鏈接並繞過了原始文件的權限。您無法使用與原始文件不同的所有權和權限創建 文件的硬鏈接。

ctime—索引節點更改時間將隨創建文件的時間或更改所有權或模式信息的 時間而改變。如果此值已更改,則它可能指示上述值已改變,即使這些值稍後返回到正常值也是如此。

清單 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
...

此流程的最後一個階段是存儲信息,並提 供將當前信息與存儲的信息進行比較的方法。

驗證校驗和信息

最後一個腳本基於清單 6 中的腳本。該腳本對原始腳本進行了顯著擴展,合並了許多新功能:

使用 Getopt::Long 模塊分 析的命令行選項。這使您能夠指定校驗和文件(存儲您計算的校驗和與其他信息)、是否比較新信息和舊 信息(通過閱讀校驗和文件的內容)和指定要搜索的基本目錄。如果比較該文件,將會更新數據並僅報告 差異。

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,它們可以 完全脫離計算機保存。

此解決方案的問題是您必須保持該信息是最新的。每次合法更新或更改您 監控的文件後,必須更新校驗和文件。

盡管該流程有些繁瑣,但該文件提供的安全信息帶來的好 處是不可估量的。

總結

在本文中,您開發了可用於生成信息的腳本,使用它可以檢查文件 或整個文件目錄的有效性。記錄的信息包括文件路徑、比較文件內容的文件校驗和與識別文件差異的唯一 信息(索引節點、權限、所有權信息)。

如何使用此腳本完全取決於您自己。您可以存儲該信息 ,並經常運行腳本,以便在發生問題時立即發現問題,或者在出現問題時將該文件用作事後檢查工具,來 查找更改了哪些文件,從而列出要檢查的文件。

Copyright © Linux教程網 All Rights Reserved