本文目录导读:

前端页面完整性检测
的哈希校验
(function() {
// 存储原始内容的哈希值
const PAGE_HASHES = {
'index.html': 'abc123...', // 部署时计算的实际hash
'about.html': 'def456...',
// 其他页面...
};
// 计算当前页面内容哈希
async function calculateHash(content) {
const encoder = new TextEncoder();
const data = encoder.encode(content);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// 检测页面是否被篡改
async function detectTampering() {
const bodyContent = document.body.innerHTML;
const currentHash = await calculateHash(bodyContent);
const pageName = window.location.pathname.split('/').pop() || 'index.html';
if (PAGE_HASHES[pageName] && currentHash !== PAGE_HASHES[pageName]) {
console.warn('警告:页面内容已被篡改!');
// 执行告警操作
alertTampering();
}
}
function alertTampering() {
// 清除可疑内容
document.body.innerHTML = '<h1>页面已被篡改,请联系管理员</h1>';
// 发送告警到服务器
fetch('/api/alert/tampering', {
method: 'POST',
body: JSON.stringify({
page: window.location.href,
time: new Date().toISOString()
})
});
}
// 在页面加载完成后执行检测
window.addEventListener('load', detectTampering);
// 定期检测(可选)
setInterval(detectTampering, 5000);
})();
DOM节点监控
// 使用MutationObserver监控DOM变化
const tamperDetector = {
observer: null,
config: {
childList: true,
subtree: true,
attributes: true,
characterData: true,
attributeFilter: ['src', 'href', 'onclick', 'onerror']
},
// 白名单中的合法修改
whiteList: [
'analytics-script', // 允许的分析脚本
'user-generated-content' // 用户生成内容区域
],
init: function() {
this.observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
this.checkMutation(mutation);
});
});
this.observer.observe(document.body, this.config);
},
checkMutation: function(mutation) {
// 检查被修改的元素是否在白名单
const target = mutation.target;
const targetId = target.id;
if (!this.whiteList.includes(targetId)) {
this.handleTampering(mutation);
}
},
handleTampering: function(mutation) {
console.warn('检测到可疑的页面修改:', mutation);
// 尝试恢复原始内容
if (mutation.type === 'attributes') {
if (mutation.attributeName === 'src') {
// 恢复原始src
const originalSrc = mutation.target.getAttribute('data-original-src');
if (originalSrc) {
mutation.target.src = originalSrc;
}
}
}
// 记录篡改日志
this.logTampering(mutation);
},
logTampering: function(mutation) {
const logData = {
type: mutation.type,
target: mutation.target.outerHTML.substring(0, 100),
time: new Date().toISOString(),
url: window.location.href
};
// 发送到日志服务器
navigator.sendBeacon('/api/log/tampering', JSON.stringify(logData));
}
};
// 启动监控
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => tamperDetector.init());
} else {
tamperDetector.init();
}
服务器端检测脚本
Python版本
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
网站页面篡改检测脚本
"""
import hashlib
import json
import logging
import requests
from pathlib import Path
from datetime import datetime
class PageTamperDetector:
def __init__(self, config_file='page_hashes.json'):
self.config_file = config_file
self.logger = self.setup_logger()
self.known_hashes = self.load_hashes()
def setup_logger(self):
"""配置日志"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('tamper_detection.log'),
logging.StreamHandler()
]
)
return logging.getLogger(__name__)
def calculate_file_hash(self, file_path):
"""计算文件哈希值"""
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
def load_hashes(self):
"""加载已知的哈希值"""
try:
with open(self.config_file, 'r') as f:
return json.load(f)
except FileNotFoundError:
return {}
def save_hashes(self):
"""保存哈希值到配置文件"""
with open(self.config_file, 'w') as f:
json.dump(self.known_hashes, f, indent=2)
def initialize_hashes(self, web_root='/var/www/html'):
"""初始化所有页面的哈希值"""
web_root = Path(web_root)
for file_path in web_root.rglob('*.html'):
if file_path.is_file():
rel_path = str(file_path.relative_to(web_root))
hash_value = self.calculate_file_hash(str(file_path))
self.known_hashes[rel_path] = hash_value
self.save_hashes()
self.logger.info(f"已初始化 {len(self.known_hashes)} 个文件的哈希值")
def detect_changes(self, web_root='/var/www/html'):
"""检测文件是否被篡改"""
web_root = Path(web_root)
tampered_files = []
new_files = []
missing_files = []
# 检查已知文件
for rel_path in list(self.known_hashes.keys()):
file_path = web_root / rel_path
if file_path.exists():
current_hash = self.calculate_file_hash(str(file_path))
if current_hash != self.known_hashes[rel_path]:
tampered_files.append(rel_path)
self.logger.warning(f"文件被篡改: {rel_path}")
else:
missing_files.append(rel_path)
self.logger.warning(f"文件缺失: {rel_path}")
# 检查新文件
for file_path in web_root.rglob('*.html'):
if file_path.is_file():
rel_path = str(file_path.relative_to(web_root))
if rel_path not in self.known_hashes:
new_files.append(rel_path)
self.logger.warning(f"发现新文件: {rel_path}")
return tampered_files, new_files, missing_files
def send_alert(self, tampered_files):
"""发送告警通知"""
if not tampered_files:
return
alert_data = {
'timestamp': datetime.now().isoformat(),
'server': 'main-web-server',
'tampered_files': tampered_files,
'severity': 'high'
}
# 可以发送邮件、短信或集成其他告警系统
# 这里作为示例,发送到告警API
try:
response = requests.post(
'https://alert-system.example.com/api/alert',
json=alert_data,
timeout=5
)
if response.status_code == 200:
self.logger.info("告警发送成功")
else:
self.logger.error(f"告警发送失败: {response.status_code}")
except Exception as e:
self.logger.error(f"告警发送异常: {str(e)}")
def main():
"""主函数"""
detector = PageTamperDetector()
# 首次运行需要初始化
# detector.initialize_hashes()
# 检测页面篡改
tampered, new_files, missing = detector.detect_changes()
# 如果有篡改,发送告警
if tampered:
detector.send_alert(tampered)
# 输出结果
print(f"检测完成:")
print(f"- 被篡改文件: {len(tampered)}")
print(f"- 新文件: {len(new_files)}")
print(f"- 缺失文件: {len(missing)}")
if tampered:
print("\n被篡改文件:")
for f in tampered:
print(f" - {f}")
if __name__ == "__main__":
main()
Shell脚本版本
#!/bin/bash
# 页面篡改检测脚本
# 使用方法: ./tamper_detection.sh
# 配置
WEB_ROOT="/var/www/html"
HASH_FILE="/var/log/page_hashes.txt"
ALERT_EMAIL="admin@example.com"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 初始化哈希值数据库
initialize_hashes() {
echo "初始化页面哈希值..."
find "$WEB_ROOT" -name "*.html" -type f | while read file; do
hash=$(sha256sum "$file" | cut -d' ' -f1)
relative_path="${file#$WEB_ROOT/}"
echo "$relative_path:$hash" >> "$HASH_FILE"
done
echo "哈希值初始化完成"
}
# 检测文件篡改
detect_tampering() {
local tampered=0
local new_files=0
local missing_files=0
echo "开始检测页面篡改..."
echo "检测时间: $(date)"
echo "================================"
# 检查已知文件
while IFS=':' read -r file_path known_hash; do
full_path="$WEB_ROOT/$file_path"
if [ -f "$full_path" ]; then
current_hash=$(sha256sum "$full_path" | cut -d' ' -f1)
if [ "$current_hash" != "$known_hash" ]; then
echo -e "${RED}[篡改]${NC} $file_path"
echo " 原哈希: $known_hash"
echo " 新哈希: $current_hash"
tampered=$((tampered + 1))
fi
else
echo -e "${YELLOW}[缺失]${NC} $file_path"
missing_files=$((missing_files + 1))
fi
done < "$HASH_FILE"
# 检查新文件
find "$WEB_ROOT" -name "*.html" -type f | while read file; do
relative_path="${file#$WEB_ROOT/}"
if ! grep -q "^$relative_path:" "$HASH_FILE" 2>/dev/null; then
echo -e "${YELLOW}[新文件]${NC} $relative_path"
new_files=$((new_files + 1))
fi
done
# 输出统计信息
echo "================================"
echo -e "检测统计:"
echo -e "${RED}被篡改: $tampered${NC}"
echo -e "${YELLOW}新文件: $new_files${NC}"
echo -e "${YELLOW}缺失文件: $missing_files${NC}"
return $tampered
}
# 发送告警
send_alert() {
local tampered=$1
local subject="[告警] 网站页面被篡改 - $(date +%Y-%m-%d)"
local body="检测到 $tampered 个页面被篡改,请立即检查!
时间: $(date)
服务器: $(hostname)
站点目录: $WEB_ROOT"
# 发送邮件告警
echo "$body" | mail -s "$subject" "$ALERT_EMAIL"
# 也可以发送到其他告警平台
# curl -X POST https://alert-api.example.com/alert \
# -H "Content-Type: application/json" \
# -d "{\"message\": \"$subject\", \"detail\": \"$body\"}"
}
# 自动恢复被篡改的文件(如果存在备份)
restore_files() {
local backup_dir="/var/backup/web"
if [ -d "$backup_dir" ]; then
echo "尝试从备份恢复被篡改文件..."
while IFS=':' read -r file_path known_hash; do
full_path="$WEB_ROOT/$file_path"
backup_file="$backup_dir/$file_path"
if [ -f "$backup_file" ]; then
current_hash=$(sha256sum "$full_path" | cut -d' ' -f1)
if [ "$current_hash" != "$known_hash" ]; then
cp "$backup_file" "$full_path"
echo -e "${GREEN}[已恢复]${NC} $file_path"
fi
fi
done < "$HASH_FILE"
fi
}
# 主流程
main() {
# 检查是否需要初始化
if [ ! -f "$HASH_FILE" ]; then
echo "未找到哈希值文件,正在初始化..."
initialize_hashes
echo "初始化完成,请再次运行脚本进行检测"
exit 0
fi
# 执行检测
detect_tampering
tampered_count=$?
# 如果有篡改,执行相应操作
if [ $tampered_count -gt 0 ]; then
echo "检测到页面篡改,正在处理..."
# 发送告警
send_alert $tampered_count
# 自动恢复(可选)
# restore_files
echo "告警已发送"
exit 1
else
echo "所有页面完整,未发现篡改"
exit 0
fi
}
# 运行主函数
main
使用方法
前端脚本:
- 在页面部署时计算并记录哈希值
- 在页面加载时执行检测
- 配置告警和恢复机制
服务器端脚本:
-
首次运行:初始化哈希值数据库
python tamper_detector.py # 或者 ./tamper_detection.sh (首次运行会自动初始化)
-
定时检测:设置cron任务
# 每30分钟检测一次 */30 * * * * /path/to/tamper_detection.sh # 或者使用Python版本 */30 * * * * python3 /path/to/tamper_detector.py
安全建议
- 哈希值离线存储:不要将哈希值放在可被访问的页面中
- 多层级检测:结合前端和后端检测
- 实时监控:使用文件监控系统(如inotify)
- 备份恢复:保持完整备份以便快速恢复
- 告警机制:配置多种告警方式(邮件、短信、即时通讯)
- 日志审计:记录所有检测和变更日志
这些脚本可以根据您的具体需求进行调整和扩展。