简介
作为系统管理员或安全分析师,你经常会遇到由 Apache 或 Nginx 等 Web 服务器生成的海量日志文件。手动阅读数千行日志来查找恶意活动不仅效率低下,而且容易出现人为错误。
在本实验中,你将扮演一名安全响应人员。你将编写一个 Python 脚本,用于处理 Apache Web 服务器的访问日志。通过利用 Python 的正则表达式(re)库,你将自动解析出 IP 地址并检测已知的 SQL 注入(SQLi)攻击特征。最后,你将把这些发现导出为结构化的 CSV 报告,以便进行进一步分析。
本模块展示了 Python 如何从单纯的编程语言转变为分析师的效率倍增器。日志是自动化处理最典型的场景之一:它们的工作量太大,不适合人工仔细审查,但结构又足够清晰,非常适合立即进行自动化处理。
在 Python 中读取日志文件
在这一步中,你将学习如何使用 Python 打开并读取日志文件。实验环境已在你的工作目录中准备好了一个名为 access.log 的示例 Apache 日志文件。
逐行读取文件是一种基础的自动化模式。它比手动复制数据更具扩展性,并且为你后续添加过滤、解析、计数和报告逻辑奠定了基础,而无需更改基本的读取方式。
首先,让我们查看示例日志文件的内容,以了解我们要处理的数据。在终端中使用 cat 命令打印文件内容。
cat access.log
你应该会看到几行标准的 Apache 访问日志。其中一些行包含正常的 Web 请求,而另一些则包含可疑的 SQL 注入尝试。
现在,让我们创建一个 Python 脚本来以编程方式读取此文件。我们将使用 nano 文本编辑器创建一个名为 log_analyzer.py 的文件。
nano log_analyzer.py
在 Python 中,open() 函数用于打开文件,而 with 语句确保我们在读取完成后文件能被正确关闭。将以下 Python 代码复制并粘贴到你的 nano 编辑器中:
def analyze_logs(file_path):
print(f"Opening log file: {file_path}")
## Open the file in read mode ('r')
with open(file_path, 'r') as file:
## Read the file line by line
for line in file:
## Print each line, stripping the extra newline character
print(line.strip())
if __name__ == "__main__":
log_file = "access.log"
analyze_logs(log_file)
在 nano 中按 Ctrl+O 保存文件,然后按 Enter 确认文件名。如果你想在测试前继续编写脚本,可以留在 nano 中并进入下一步。仅当你准备好返回终端时,才使用 Ctrl+X。
使用 python3 命令运行你刚刚创建的 Python 脚本:
python3 log_analyzer.py
你将看到脚本输出的内容与之前使用 cat 命令看到的内容完全一致。这证实了你的 Python 脚本可以成功地逐行读取日志数据。
应用正则表达式提取 IP
在这一步中,你将增强你的 Python 脚本,使其能够自动从每一行日志中提取 IP 地址。为此,我们将使用正则表达式(Regex)。正则表达式是匹配文本模式的强大工具。
正则表达式之所以有用,是因为日志是半结构化的:它们遵循一定的模式,但通常不是整洁的 Python 对象。正则表达式为你提供了一种描述所需文本模式的方法,并让解释器完成重复的匹配工作。
Python 提供了一个名为 re 的内置模块来处理正则表达式。我们需要导入此模块并定义一个匹配 IPv4 地址的模式。IPv4 地址由四个数字(范围从 0 到 255)组成,中间用点分隔。
如果 log_analyzer.py 仍在 nano 中打开,请继续在那里编辑。否则,请使用以下命令重新打开它:
nano log_analyzer.py
更新你的脚本以包含 re 模块以及搜索 IP 地址的逻辑。用以下代码替换文件的全部内容:
import re
def analyze_logs(file_path):
print(f"Analyzing log file: {file_path}\n")
## Define a Regex pattern for an IPv4 address
## \b ensures word boundaries, \d{1,3} matches 1 to 3 digits, \. matches a literal dot
ip_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
with open(file_path, 'r') as file:
for line in file:
## re.findall returns a list of all matches in the string
ips_found = re.findall(ip_pattern, line)
if ips_found:
## We take the first IP found in the line
source_ip = ips_found[0]
print(f"Extracted IP: {source_ip}")
if __name__ == "__main__":
log_file = "access.log"
analyze_logs(log_file)
按 Ctrl+O 和 Enter 保存文件。如果你现在想测试这个中间版本,请按 Ctrl+X 退出并运行脚本。如果不想,可以直接继续下一步。
python3 log_analyzer.py
你应该会看到类似以下的输出:
Analyzing log file: access.log
Extracted IP: 192.168.1.10
Extracted IP: 10.0.0.15
Extracted IP: 172.16.0.5
Extracted IP: 192.168.1.22
Extracted IP: 10.0.0.25
现在,脚本已成功忽略了日志中的其余文本,并利用正则表达式的强大功能单独提取出了源 IP 地址。
检测 SQL 注入特征
在这一步中,你将为脚本添加安全检测功能。SQL 注入(SQLi)是一种常见的 Web 攻击,攻击者将恶意的 SQL 语句插入到输入字段中。
这将使脚本从解析器转变为检测器。你不再仅仅是提取字段,而是应用安全逻辑来决定哪些行值得关注。这种从收集到解释的转变,正是自动化在操作层面上的价值所在。
攻击者通常使用 UNION SELECT 等关键字来窃取数据,或使用 ' OR '1'='1 来绕过身份验证。我们可以使用正则表达式扫描日志行,查找这些已知的攻击特征。
如果你仍在 nano 中编辑同一个文件,请继续操作。否则,请重新打开它:
nano log_analyzer.py
我们将定义一个新的正则表达式模式来捕获常见的 SQLi 短语。我们将使用 (?i) 使搜索不区分大小写,这意味着它将捕获 UNION、union 或 uNiOn。更新你的脚本以匹配以下代码:
import re
def analyze_logs(file_path):
print(f"Scanning log file for SQLi attacks: {file_path}\n")
ip_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
## Define a Regex pattern for SQL Injection signatures
## (?i) makes it case-insensitive
## It looks for 'union select' OR 'or 1=1' variations
sqli_pattern = r"(?i)(union.*select|or\s+1\s*=\s*1|'.*or.*')"
with open(file_path, 'r') as file:
for line in file:
ips_found = re.findall(ip_pattern, line)
source_ip = ips_found[0] if ips_found else "Unknown IP"
## re.search returns a match object if the pattern is found, otherwise None
if re.search(sqli_pattern, line):
print(f"[ALERT] SQL Injection detected from IP: {source_ip}")
print(f"Raw Log: {line.strip()}\n")
if __name__ == "__main__":
log_file = "access.log"
analyze_logs(log_file)
按 Ctrl+O 和 Enter 保存文件。仅当你准备好从终端运行脚本时,才使用 Ctrl+X 退出 nano。
python3 log_analyzer.py
你的输出现在应该能专门标记出恶意请求:
Scanning log file for SQLi attacks: access.log
[ALERT] SQL Injection detected from IP: 10.0.0.15
Raw Log: 10.0.0.15 - - [10/Oct/2026:13:55:45 -0700] "GET /login.php?user=admin' OR '1'='1 HTTP/1.1" 200 5120
[ALERT] SQL Injection detected from IP: 192.168.1.22
Raw Log: 192.168.1.22 - - [10/Oct/2026:13:56:12 -0700] "GET /products.php?id=1 UNION SELECT username, password FROM users HTTP/1.1" 200 4012
你的脚本现在充当了一个基本的入侵检测系统(IDS),自动识别出日志文件中的可疑请求。
输出到 CSV 报告
在最后一步中,你将格式化结果并将其保存到 CSV(逗号分隔值)文件中。打印到终端对于测试来说很棒,但安全团队需要结构化的报告,以便在电子表格软件中打开或被其他工具读取。
Python 有一个内置的 csv 模块,可以非常轻松地编写 CSV 文件。
如果你保持文件打开状态,请继续编辑。否则,请重新打开它:
nano log_analyzer.py
我们将导入 csv 模块,以写入模式('w')打开一个名为 report.csv 的新文件,并将我们的发现写入其中。用此最终版本替换你的代码:
import re
import csv
def analyze_logs(file_path, output_csv):
print(f"Analyzing logs and generating report: {output_csv}...")
ip_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
sqli_pattern = r"(?i)(union.*select|or\s+1\s*=\s*1|'.*or.*')"
## Open the output CSV file in write mode
with open(output_csv, 'w', newline='') as csv_file:
writer = csv.writer(csv_file)
## Write the header row
writer.writerow(['Source IP', 'SQLi Detected', 'Raw Log'])
with open(file_path, 'r') as file:
for line in file:
clean_line = line.strip()
ips_found = re.findall(ip_pattern, clean_line)
source_ip = ips_found[0] if ips_found else "Unknown IP"
## Check if SQLi is detected
sqli_detected = "Yes" if re.search(sqli_pattern, clean_line) else "No"
## Write the data row to the CSV
writer.writerow([source_ip, sqli_detected, clean_line])
print("Report generation finished.")
if __name__ == "__main__":
log_file = "access.log"
report_file = "report.csv"
analyze_logs(log_file, report_file)
保存文件并执行脚本:
python3 log_analyzer.py
你将看到一条消息,表明报告生成已完成。现在,让我们验证 CSV 文件是否已创建,并使用 cat 命令检查其内容:
cat report.csv
你应该会看到格式整齐的 CSV 输出:
Source IP,SQLi Detected,Raw Log
192.168.1.10,No,192.168.1.10 - - [10/Oct/2026:13:55:36 -0700] "GET /index.html HTTP/1.1" 200 2326
10.0.0.15,Yes,10.0.0.15 - - [10/Oct/2026:13:55:45 -0700] "GET /login.php?user=admin' OR '1'='1 HTTP/1.1" 200 5120
172.16.0.5,No,172.16.0.5 - - [10/Oct/2026:13:56:01 -0700] "POST /api/data HTTP/1.1" 404 134
192.168.1.22,Yes,192.168.1.22 - - [10/Oct/2026:13:56:12 -0700] "GET /products.php?id=1 UNION SELECT username, password FROM users HTTP/1.1" 200 4012
10.0.0.25,No,10.0.0.25 - - [10/Oct/2026:13:57:00 -0700] "GET /about.html HTTP/1.1" 200 1024
总结
在本实验中,你成功地从手动阅读日志过渡到了使用 Python 进行自动化日志分析。你学习了如何使用 Python 的内置文件处理功能逐行读取和处理文本文件。你还利用 re 模块应用正则表达式来提取特定的数据格式,例如 IP 地址。此外,你通过将已知的 SQL 注入攻击特征与原始日志数据进行匹配,实现了安全检测逻辑。最后,你练习了使用 csv 模块将结构化数据导出为 CSV 报告,使结果易于共享和进一步分析。
这些技能构成了安全自动化和数据解析的基础,使你能够高效地处理海量数据集。



