杭州网站防攻击与数据备份方案:从被动修复到主动防御的安全体系搭建
杭州企业网站安全威胁的现实
上城区某制造企业网站运行3年未做安全加固,某天首页被篡改为赌博广告页面,攻击者通过SQL注入获取了整个客户数据库。中小企业网站遭受Web攻击的平均概率为每年68%,常见的攻击手段包括SQL注入、XSS跨站脚本、CSRF、文件上传漏洞等。做好基础安全防护可降低90%以上被攻击概率。
SQL注入防御实战
攻击示例:URL参数中注入1' OR '1'='1可返回所有数据,攻击者甚至可获取管理员权限。防御方案——参数化查询:
<?php
// PDO参数化查询(推荐)
try {
$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// 安全查询示例
$stmt = $pdo->prepare("SELECT * FROM products WHERE category_id = :cat_id AND status = :status");
$stmt->execute(['cat_id' => $_GET['category'], 'status' => 1]);
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
error_log($e->getMessage());
die('系统错误,请稍后重试');
}
// MySQLi参数化查询
$mysqli = new mysqli('localhost', 'user', 'pass', 'myapp');
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param('i', $_GET['id']);
$stmt->execute();
拱墅区某企业产品搜索存在SQL注入,攻击者获取了管理员账号,修复后全部改为参数化查询。永远不要直接拼接SQL语句。
XSS与CSRF双重防御
<?php
// XSS防御:输入过滤与输出编码
function safe_input($data) {
return htmlspecialchars($data, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
// CSRF防御:Token验证
session_start();
function generate_csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verify_csrf_token($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
// 表单中添加
echo '<input type="hidden" name="csrf_token" value="' . generate_csrf_token() . '">';
// 提交时验证
if (!verify_csrf_token($_POST['csrf_token'] ?? '')) {
die('CSRF验证失败');
}
Content-Security-Policy头部可进一步防御XSS:Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-随机值'
安全文件上传验证
<?php
// 严格文件上传验证
function secure_upload($file) {
$allowed_types = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp'
];
// MIME类型检查
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$real_mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!array_key_exists($real_mime, $allowed_types)) {
return ['error' => '不支持的文件类型'];
}
// 图片内容验证
$image_info = @getimagesize($file['tmp_name']);
if (!$image_info || !in_array($image_info[2], [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP])) {
return ['error' => '不是有效的图片文件'];
}
// 文件大小限制(2MB)
if ($file['size'] > 2 * 1024 * 1024) {
return ['error' => '文件大小超过限制'];
}
// 生成安全文件名
$extension = $allowed_types[$real_mime];
$new_name = uniqid('img_', true) . '.' . $extension;
// 上传到隔离目录
$upload_dir = '/var/www/uploads/' . date('Y/md') . '/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$destination = $upload_dir . $new_name;
if (move_uploaded_file($file['tmp_name'], $destination)) {
return ['success' => true, 'path' => $destination];
}
return ['error' => '上传失败'];
}
西湖区某企业网站允许上传头像但未验证文件类型,攻击者上传PHP WebShell获取服务器控制权。文件上传必须验证MIME类型和内容。
WAF ModSecurity规则配置
# ModSecurity核心规则集配置
SecRuleEngine On
# SQL注入防护规则
SecRule REQUEST_URI|REQUEST_BODY|ARGS_NAMES|ARGS
"@rx (union.*select|or.*1.*=.*1|and.*1.*=.*1)"
"id:1001,phase:2,deny,status:403,msg:'SQL Injection Attack'"
# XSS跨站脚本防护
SecRule REQUEST_URI|REQUEST_BODY|ARGS_NAMES|ARGS|REQUEST_HEADERS
"@rx <script>|javascript:|onerror="
"id:1002,phase:2,deny,status:403,msg:'Cross-Site Scripting Attack'"
# 文件包含防护
SecRule REQUEST_URI
"@rx (\.\.\/|\.htaccess|\.git\/|\.env)"
"id:1003,phase:2,deny,status:403"
# 限制请求体大小
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
上城区某企业部署ModSecurity WAF后,每天拦截200+恶意请求,包括大量SQL注入和扫描探测。云WAF可提供开箱即用的防护能力。
登录暴力破解防护PHP代码
<?php
class BruteForceProtection {
private $max_attempts = 5;
private $lockout_minutes = 15;
private $redis;
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
// 检查IP是否被锁定
public function isLocked($ip) {
return $this->redis->exists("locked:$ip");
}
// 记录登录失败
public function recordFailedAttempt($ip) {
$key = "attempts:$ip";
$attempts = $this->redis->incr($key);
if ($attempts == 1) {
$this->redis->expire($key, $this->lockout_minutes * 60);
}
if ($attempts >= $this->max_attempts) {
$this->redis->setex("locked:$ip", $this->lockout_minutes * 60, '1');
$this->redis->del("attempts:$ip");
return false;
}
return true;
}
// 清除失败记录
public function clearAttempts($ip) {
$this->redis->del("attempts:$ip");
}
// 获取剩余尝试次数
public function getRemainingAttempts($ip) {
$attempts = (int)$this->redis->get("attempts:$ip");
return max(0, $this->max_attempts - $attempts);
}
}
// 使用示例
$security = new BruteForceProtection();
$client_ip = $_SERVER['REMOTE_ADDR'];
if ($security->isLocked($client_ip)) {
die('账户已锁定,请15分钟后重试');
}
if (!$security->recordFailedAttempt($client_ip)) {
die('登录失败次数过多,账户已锁定');
}
if (verifyUser($_POST['username'], $_POST['password'])) {
$security->clearAttempts($client_ip);
// 登录成功逻辑
} else {
$remaining = $security->getRemainingAttempts($client_ip);
die('用户名或密码错误,剩余尝试次数:' . $remaining);
}
拱墅区某企业后台登录页面添加暴力破解防护后,成功阻止了多起密码暴力破解攻击,平均每天阻止100+次恶意尝试。
完整数据备份脚本
#!/bin/bash
# /usr/local/bin/backup.sh - 完整网站备份脚本
set -euo pipefail
# 配置
BACKUP_ROOT="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
DB_HOST="localhost"
DB_USER="backup_user"
DB_PASS="secure_password"
DB_NAMES="myapp_db another_db"
OSS_BUCKET="myapp-backup"
OSS_PREFIX="backup/"
RETENTION_DAYS=30
LOG_FILE="/var/log/backup.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] {$1}" | tee -a "{$LOG_FILE}"
}
# 创建备份目录
BACKUP_DIR="$BACKUP_ROOT/{$DATE}"
mkdir -p "{$BACKUP_DIR}"
log "========== 开始备份 =========="
# 数据库备份
for DB_NAME in {$DB_NAME}S; do
log "备份数据库: {$DB_NAME}"
mysqldump -h"{$DB_HOST}" -u"{$DB_USER}" -p"{$DB_PASS}" --single-transaction --routines --triggers --events --hex-blob "{$DB_NAME}" | gzip > "{$BACKUP_DIR}/{{$DB_NAME}}.sql.gz"
if [ -s "{$BACKUP_DIR}/{{$DB_NAME}}.sql.gz" ]; then
log "数据库 {$DB_NAME} 备份成功"
else
log "ERROR: 数据库 {$DB_NAME} 备份失败"
exit 1
fi
done
# 网站文件备份
log "备份网站文件: /var/www/html"
tar -czf "{$BACKUP_DIR}/site_files.tar.gz" --exclude='/var/www/html/uploads' --exclude='/var/www/html/cache' --exclude='*.log' /var/www/html/ 2>/dev/null
if [ -s "{$BACKUP_DIR}/site_files.tar.gz" ]; then
log "网站文件备份成功"
fi
# 上传到OSS
log "上传备份到OSS..."
ossutil cp -r "{$BACKUP_DIR}" "oss://{$OSS_BUCKET}/{$OSS_PREFIX}{$DATE}/" --update --force
# 清理本地过期备份
log "清理本地过期备份(保留{$RETENTION_DAYS}天)..."
find "$BACKUP_ROOT" -maxdepth 1 -type d -name "20*" -mtime +{$RETENTION_DAYS} -exec rm -rf {} \;
log "========== 备份完成 =========="
西湖区某企业坚持备份2年但从未验证,恢复时发现文件损坏。必须定期验证备份可恢复性,异地容灾存储到不同云服务商。
文件完整性监控脚本
#!/bin/bash
# /usr/local/bin/file_integrity_check.sh
WATCH_DIRS="/var/www/html /etc/nginx /usr/local/bin"
ALERT_EMAIL="admin@example.com"
LOG_FILE="/var/log/integrity_check.log"
HASH_DB="/var/lib/website_hashes.db"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] {$1}" | tee -a "{$LOG_FILE}"
}
# 生成文件哈希数据库
generate_hash_db() {
log "生成文件哈希数据库..."
rm -f "{$HASH_DB}"
for dir in $WATCH_DIRS; do
if [ -d "$dir" ]; then
find "$dir" -type f \( -name "*.php" -o -name "*.js" -o -name "*.html" \) 2>/dev/null | while read -r file; do
hash=$(sha256sum "$file" | cut -d' ' -f1)
echo "$file|$hash" >> "{$HASH_DB}"
done
fi
done
log "哈希数据库已更新"
}
# 检查文件完整性
check_integrity() {
log "开始文件完整性检查..."
CHANGES_FOUND=0
while IFS='|' read -r file expected_hash; do
if [ ! -f "$file" ]; then
log "ALERT: 文件被删除 - $file"
CHANGES_FOUND=1
continue
fi
current_hash=$(sha256sum "$file" | cut -d' ' -f1)
if [ "$current_hash" != "$expected_hash" ]; then
log "ALERT: 文件被修改 - $file"
CHANGES_FOUND=1
fi
done < "{$HASH_DB}"
if [ $CHANGES_FOUND -eq 1 ]; then
log "WARNING: 发现文件变更,请立即检查!"
echo "网站文件完整性检查发现变更" | mail -s "[安全告警] 网站文件变更" "$ALERT_EMAIL"
else
log "文件完整性检查通过"
fi
}
case "{$1}" in
generate) generate_hash_db ;;
check)
[ ! -f "{$HASH_DB}" ] && generate_hash_db
check_integrity
;;
*) echo "用法: {$0} {generate|check}" ;;
esac
上城区某企业部署文件完整性监控后,成功在攻击者上传WebShell后10分钟内发现并告警,及时阻止了进一步渗透。建议配合定时任务每小时执行一次检查。
应急响应流程
被入侵后:1)立即隔离断开网络连接防止扩散;2)保全证据备份日志;3)清除后门查找eval/base64_decode/shell_exec等危险函数;4)修复安全漏洞;5)从干净备份恢复;6)安全加固部署WAF。杭州企业应将安全防护纳入日常运维,定期更新、检测、演练,形成主动防御体系。
声明:本文来自投稿,不代表本站立场,如若转载,请注明出处:https://hangzhou.bangying360.com/news/show03706948.html 若本站的内容无意侵犯了贵司版权,请给我们来信,我们会及时处理和回复。











