简陋的Web监控工具





5.00/5 (1投票)
本文分享了如何利用免费工具从服务器下载日志文件、将 IIS 日志文件上传到数据库、显示结果以及比较基线文件和生产文件。
目录
- 背景
- 引言
- DownloadIISLog
- DownloadIISLog – 配置
- SimpleMonitor.Web
- SimpleMonitor.Web - 配置
- SimpleMonitor.BlockIpAddress
- SimpleMonitor.ScanFile
- SimpleMonitor.ScanFile – 配置
- 所需软件
- 如何设置
- 结论
- 历史
- 下载
- 资源
- 反馈/问题
背景
这个项目最初于 2012 年启动。后来有一天,我电脑的硬盘坏了。我很幸运能够恢复大部分文件。经过一段时间的努力,我得以重新编译它。之后,我每年可能会做一两次修改。毫无疑问,还有很多改进的空间。最近,我对项目做了一些修改,决定现在就分享出来,而不是让它再搁置几年。希望有人能发现这个项目很有用,并继续对其进行改进。
引言
和许多博主或网站所有者一样,我们中的大多数人由于成本原因,网站都托管在共享服务器上,而不是独立服务器。这里就不提具体的托管公司了。根据我自己的经验,时不时地,会有恶意文件夹和文件/恶意软件被注入到网站中。每次我提交相关的技术支持请求时,都会得到诸如“您的计算机已被入侵”、“您正在使用过时的软件”、“您需要更改密码”之类的回复。各种无稽之谈,而托管公司从不承担责任或进行尽职调查。有些托管公司甚至提供付费清理漏洞和监控 EACH 站点的服务,需要按年订阅。想象一下,如果您有不止一个网站,由于别人的疏忽,成本会迅速累积。
既然我拒绝每年向某些公司支付费用来监控我所有的网站,为什么不自己做一个呢?标题说明了一切,“穷人也能用的网站监控工具”,如果你穷,那么你就需要努力工作,自己组合所有可用的免费工具。现在它可能看起来像一个拼凑的工具,但我相信当我们投入更多思考后,它会变得更好。
下面是对解决方案中一些组件的简要描述。在本文中,我不会深入探讨解决方案的实现细节,因为我认为还需要做一些工作来优化它。但我会分享每个组件的作用以及如何设置。
DownloadIISLog
- 通过 FTP 下载 IIS 日志文件 (WinSCP)
- 使用 Log Parser 将日志文件数据插入 SQL 数据库
SimpleMonitor.Web
- 使用 jqGrid 显示 IIS 日志数据的 Web UI
- 选择标记某些 IP 地址为“
已封禁
”
SimpleMonitor.BlockIpAddress
- 用于阻止已封禁 IP 地址访问网站的 HTTP 模块示例
SimpleMonitor.ScanFile
- 下载最新文件
- 使用 WinMerge 比较基线与最新文件
- 发送结果的电子邮件通知
DownloadIISLog
这个控制台应用程序的职责之一是通过 WinSCP 从 FTP 服务器下载日志文件。请注意,我仅在两种不同的共享托管环境中进行了测试。如果您在访问日志文件夹时遇到“拒绝访问”错误,我建议以下方法。首先,登录您的托管账户,导航到文件管理器,找到 logs 文件夹并为其分配只读权限。第二个选择是提交技术支持请求。
列表 1 显示了下载日志文件的方法。首次运行可能需要一段时间,具体取决于托管日志文件夹中的日志文件数量。后续执行会快得多,因为此方法只会下载之前未下载过的文件。为此,该方法将首先使用 WinSCP ListDirectory
方法从服务器获取日志文件元数据的列表,并将其存储在 directoryInfo
对象中。接下来,它将获取存储在数据库中的最近一个日志文件的名称。之后,该模块将尝试根据日志文件名查询 directoryInfo
对象中的 LastWriteTime
。最后,该模块将下载所有 LastWriteTime
晚于先前确定的 LastWriteTime
的日志文件。
列表 1
static internal void WinScpGetLog() {
using(Session session = new Session()) {
// Connect
session.Open(GetWinScpSession());
string remotePath = ApplicationSetting.FtpRemoteFolder;
string localPath = ApplicationSetting.DownloadPath;
// Get list of files in the directory
RemoteDirectoryInfo directoryInfo = session.ListDirectory(remotePath);
//latest file name in the table by application name
var latestLogFileInDb = Path.GetFileName
(unitOfWork.IISLogRepository.LatestFileName(ApplicationSetting.ApplicationName));
//get the date of the latest file from FTP
var logFileDate = directoryInfo.Files
.Where(w => w.Name.ToLower() == latestLogFileInDb ? .ToLower())
.Select(s => s.LastWriteTime).FirstOrDefault();
// Select the files not in database table
IEnumerable notInLogTable =
directoryInfo.Files
.Where(file => !file.IsDirectory && file.LastWriteTime > logFileDate).ToList();
//// Download the selected file
foreach(RemoteFileInfo fileInfo in notInLogTable) {
string localFilePath =
RemotePath.TranslateRemotePathToLocal(
fileInfo.FullName, remotePath, localPath);
string remoteFilePath = RemotePath.EscapeFileMask(fileInfo.FullName);
//download
TransferOperationResult transferResult =
session.GetFiles(remoteFilePath, localFilePath);
}
}
}
列表 2 显示了使用 Microsoft Log Parser 工具查询日志文件并将其插入数据库的逻辑。在 CallLogParser()
方法中使用的 Log Parser 查询非常直接。它将使用提供的用户名和密码连接到 SQL 数据库。然后读取文件夹中的所有日志文件,并将它们插入表中。ApplicationName
参数是最近添加的一个选项,允许存储多个网站的日志文件数据。如果您有十个网站,可以复制此控制台应用程序十次,并在配置文件中配置不同的 ApplicationName
值。
列表 2
static void CallLogParser() {
ProcessStartInfo startInfo = new ProcessStartInfo(ApplicationSetting.LogParserPath);
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
startInfo.Arguments = string.Format("\"SELECT '{7}', *,1 INTO {0} FROM {1}{2}*.log\"
-o:SQL -createTable:OFF -server:{3} -database:{4} -username:{5} -password:{6}",
ApplicationSetting.LogParserSqlTable, ApplicationSetting.DownloadPath,
ApplicationSetting.LogFilePrefix, ApplicationSetting.LogParserSqlserver,
ApplicationSetting.LogParserSqlDatabase, ApplicationSetting.LogParserSqlUserName,
ApplicationSetting.LogParserSqlPassword,
ApplicationSetting.ApplicationName);
Process.Start(startInfo);
}
图 1 显示了通过 CallLogParser()
方法导入数据库表的数据。
DownloadIISLog - 配置
表 1 显示了 app.config 中设置的说明。
表 1
键 | 描述 |
FtpHost | 服务器地址。例如:poormantool.arr 或 123.123.123.123 |
FtpRemoteFolder | 服务器上日志文件的路径。例如:/virtualFolder/logs/W3SVC999/ |
FtpUserName | FTP 账户 |
FtpPassword | FTP 密码 |
FilePrefix | 日志文件的前缀(如果存在)。 |
DownloadPath | 下载日志文件的存储位置。例如:c:\temp\app1\download\ |
LogPath | LogPath 是用于日志记录的日志文件路径,例如控制台运行时、停止、错误等。例如:c:\temp\app1\log\log.txt |
LogParserPath | Log Parser 的路径。例如:C:\Program Files (x86)\Log Parser 2.2\LogParser.exe |
LogParserSqlTable | 在 SQL 数据库中用于存储日志文件数据的表。目前,它只能是“iislog ”,除非您更新实体和代码 |
应用程序名称 | 应用程序的名称。例如:app1 |
LogParserSqlserver | SQL 服务器地址 |
LogParserSqlDatabase | SQL 服务器数据库 |
LogParserSqlUserName | SQL 服务器用户名 |
LogParserSqlPassword | SQL 服务器密码 |
connectionStrings | 将 XXX 替换为您的 SQL 服务器信息 |
SimpleMonitor.Web
这个 Web 应用程序的目的是显示日志文件数据。现在数据已进入数据库,您可以选择任何技术来与数据进行交互。这个 Web 应用程序是使用 MVC 5、EntityFramework v6.0、jqGrid、Bootstrap v4.0 和 jQuery v3.3 开发的。
图 2 显示了 Web 浏览器界面的外观。所有列都可以排序和过滤。Blocked? 列指示 IP 地址是否被阻止访问站点。Blocked Hit 列的目的是显示被阻止的 IP 地址尝试访问网站的次数。
要阻止 IP 地址,请单击绿色图标,会出现一个确认对话框,单击 **Continue**。参见图 3。应用程序会将选定的 IP 地址插入 dbo.BlockedIp
表,然后在网格中用红色封禁圆圈图标标记所有被封禁的 IP。
要解除阻止 IP 地址,请单击红色圆圈图标并继续按钮。参见图 4。
SimpleMonitor.Web - 配置
请确保更新 web.config 中的连接字符串以反映您的 SQL 服务器环境。
SimpleMonitor.BlockIpAddress
此模块的目的是演示如何利用 dbo.BlockedIp
表中的数据。此模块将检查请求的 IP 地址是否存在于表中,如果存在,则将请求重定向到错误页面,然后增加已封禁的访问次数。列表 3 显示了如何在 Web 应用程序 web.config 文件中注册 httpModules
。为了测试,我将我的 IP 地址添加到表中并重新运行 Web 应用程序。同样,这只是一个示例,检测和防御控制的实现方式取决于您。
列表 3
<system.web>
<httpModules>
<remove name="BlockIpHttpModules" />
<add type="SimpleMonitor.BlockIpAddress.BlockIpHttpModule,
SimpleMonitor.BlockIpAddress" name="BlockIpHttpModules" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add type="SimpleMonitor.BlockIpAddress.BlockIpHttpModule,
SimpleMonitor.BlockIpAddress" name="BlockIpHttpModules" preCondition="managedHandler" />
</modules>
</system.webServer>
SimpleMonitor.ScanFile
此控制台应用程序的主要目的是比较基线和生产环境中的文件夹和文件。最初,应用程序将使用 WinSCP
下载文件并将其保存到指定文件夹。然后它将运行 WinMerge
命令来比较文件与基线。列表 4 显示了用于比较文件的 WinMerge
命令行。
列表 4
static void CompareFiles() {
var tempFileName = $ "{Guid.NewGuid()}.html";
ProcessStartInfo startInfo = new ProcessStartInfo(ApplicationSetting.WinMergePath);
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
startInfo.Arguments = $ " {ApplicationSetting.BaselineFilesPath}
{ApplicationSetting.LatestFilesPath} -minimize " +
"-noninteractive -noprefs -cfg Settings/DirViewExpandSubdirs=1 -cfg Settings/DiffContextV2=2 " +
"-cfg ReportFiles/ReportType=2 -cfg ReportFiles/IncludeFileCmpReport=1 -
cfg Settings/ShowIdentical=0 " +
$ " -r -u -or {ApplicationSetting.FileCompareOutputPath}{tempFileName}";
var process = Process.Start(startInfo);
process.WaitForExit();
Email.SendEmail($ "{ ApplicationSetting.FileCompareOutputPath}{ tempFileName}");
}
表 2 显示了列表 4 中的 WinMerge
参数及其说明。
表 2
键 | 描述 |
-minimize | 将 WinMerge 启动为最小化窗口。 |
-noninteractive | 比较/报告生成后退出 WinMerge |
-noprefs | 不从注册表中读取/写入设置信息(使用默认值) |
-cfg Settings/DirViewExpandSubdirs=1 | 比较后展开文件夹树 0:不展开文件夹树 |
-cfg Settings/DiffContextV2=2 | 0:仅显示差异 1:显示差异以及上下各一行 2:显示差异以及上下各两行 |
-cfg ReportFiles/ReportType=2 | 生成 HTML 格式报告 |
-cfg ReportFiles/IncludeFileCmpReport=1 | 在文件夹比较报告中包含文件比较报告,0:不包含 |
-cfg Settings/ShowIdentical=0 | 不在结果中显示相同文件 |
-r | 比较所有子文件夹中的所有文件 |
-u | 防止 WinMerge 将任一路径(左或右)添加到最近使用 (MRU) 列表中 |
-or | 输出文件的路径 |
比较结束后,CompareFiles()
方法将使用 Gmail 向指定电子邮件地址发送摘要。图 5 显示了比较摘要的外观。
图 6 显示了单击文件名从保存了比较报告的计算机钻取详细信息的外观。
SimpleMonitor.ScanFile – 配置
表 3 显示了 app.config 中设置的说明。
表 3
键 | 描述 |
---|---|
FtpHost | 服务器地址。例如:poormantool.arr 或 123.123.123.123 |
FtpRemoteFolder | 服务器上日志文件的路径。例如:/virtualFolder/wwwroot/ |
FtpUserName | FTP 账户 |
FtpPassword | FTP 密码 |
BaselineFilesPath | 应用程序生产文件的路径 |
LatestFilesPath | 使用 WinSCP 从 FTP 服务器下载的最新文件的路径 |
FileCompareOutputPath | 存储比较结果的路径 |
WinMergePath | WinMerge 应用程序的路径 |
SmtpHost | 电子邮件 SMTP 主机 |
SmtpTo | 收件人 |
SmtpPort | SMTP 端口号 |
SmtpUserName | 电子邮件账户用户名/邮箱 |
SmtpPassword | 电子邮件账户密码 |
SmtpSubject | 电子邮件主题 |
所需软件
下载并安装以下软件。
- WinMerge v2.15.2 (https://sourceforge.net/projects/winmerge/files/alpha/2.15.2/)
- Log parser v2.2 (https://www.microsoft.com/en-us/download/details.aspx?id=24659)
如何设置
在现有/新数据库实例上执行 database_objects.sql 脚本。该脚本将创建以下对象:
- [
BlockedIp
] 表 - [
iislog
] 表 - [
vwIISLog
] 视图 - [
InsertUpdateBlockedIp
] 存储过程
结论
首先,我想感谢 WinMerge
的新所有者继续维护 WinMerge
软件。请记住,此处提供的解决方案不是一种预防控制措施。您在日志和比较结果中看到的一切都是事后信息。但是,在查看和分析信息后,您可以创建自己的预防控制措施,例如 IP 阻止程序。
以下是您可以从该项目中提取的其他感兴趣的主题。
- 如何将 jqGrid 与服务器端分页、过滤、排序结合使用
- 如何使用 Log Parser 将 IISLog 导入 SQL 数据库表
- 如何使用 WinSCP 从 FTP 服务器下载文件
- 如何使用 WinMerge 比较文件
- 如何创建和利用 HTTP 模块
- 如何使用 Gmail 发送电子邮件
我希望有人会发现这个项目很有用。如果您发现任何错误,或不同意本文内容,或想帮助改进本文,请给我发条消息,我会与您合作进行修正。我建议访问演示站点并进行探索,以完全掌握其中的概念,因为我可能在本文中遗漏了一些重要信息。如果您想帮助改进本文,请与我联系。
历史
- 08/12/2018 - 初始版本