セキュリティログを監視し、ファイルシステムへのアクセスをモニタする
Windows では .NET Framework の FileSystemWatcher クラス を使うとファイルシステムの変更をモニタすることが出来ます。しかし、FileSystemWatcher クラスでは「ファイルやフォルダを操作したユーザが分からない」という、大きな欠点があるようです。
そこで、代替手段として Windows のセキュリティ監査の新機能 などに記載のある「オブジェクトアクセスの監査」機能を使い、記録されたセキュリティログをモニタし、ファイルシステムへの操作を監視することが出来ます(この方法であれば、ファイルやフォルダを操作したユーザを取得することが可能です。スマートとは言えませんが...)。イベントログは EventLog クラス の EventWritten イベント によってモニタすることが出来ます。ただし、Vista / 2003 以前と Windows 7 / 2008 ではオブジェクトアクセス時に発生するイベントの ID が以下のように異なるようで、やや注意が必要です。
イベント |
Vista / 2003 以前 |
Windows 7 / 2008 |
ファイルオープン |
560 |
4656 |
ファイルアクセス |
567 |
4663 |
ファイルコピー |
(N/A) |
4690 |
ファイル削除 |
564 |
4660 |
ファイルクローズ |
562 |
4658 |
ローカルコンピュータのセキュリティログをモニタする、簡単なサンプルを C# で作ってみました。例外処理も無く、Windows 7 / 2008 限定版です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 | using System;
using System.Diagnostics;
using System.IO;
using System.Net;
namespace EventLogWatchSample
{
class Program
{
private const int INDEX = 10;
private const string NOT_FOUND = "(Not found)";
static void Main(string[] args)
{
var elog = new EventLog("Security", ".");
elog.EnableRaisingEvents = true;
elog.EntryWritten += new EntryWrittenEventHandler(EventLogEntryWritten);
// キー入力があれば、アプリケーションを終了
Console.WriteLine("*** Press any key to exit. ***");
Console.Read();
}
private static void EventLogEntryWritten(
object sender, System.Diagnostics.EntryWrittenEventArgs e)
{
// Windows 7 / Windows Server 2008 における以下のイベント ID を監視
//
// 4656 ファイルオープン 4663 ファイルアクセス 4690 ファイルコピー
// 4660 ファイル削除 4658 ファイルクローズ
//
var id = e.Entry.InstanceId;
if (id == 4656 || id == 4663 || id == 4690 || id == 4690 || id == 4658)
{
string aName = GetValue(e.Entry.Message, "アカウント名");
string oName = GetValue(e.Entry.Message, "オブジェクト名");
// 以下のアクセスはログ監視の対象から除外
//
// (1) システム(ローカルマシン)からのアクセス
// (2) 対象オブジェクト名の無いログ
// (3) レジストリへのアクセス
//
if (aName == Dns.GetHostName() + "$" || oName == NOT_FOUND || oName.StartsWith("\\REGISTRY"))
return;
Console.WriteLine(
"---- EventID:" + e.Entry.InstanceId + " (" + DateTime.Now.ToString() + ") -----\n" +
" AccountName : " + aName + "\n" +
" ObjectName : " + oName + "\n");
}
}
private static string GetValue(string entry, string keyword)
{
string line = null;
string value = NOT_FOUND;
using (var sr = new StringReader(entry))
{
while ((line = sr.ReadLine()) != null)
{
if (line.IndexOf(keyword) != -1)
{
value = line.Substring(INDEX);
sr.Close();
break;
}
}
sr.Close();
}
return value;
}
}
}
|