Ultima attività 1 month ago

Revisione c368cb39c9b1e74222ec89384dedcf7defdc45df

arch_hardening_script.sh Raw
1#!/bin/bash
2
3################################################################################
4# 服务器自动化加固脚本 - 多发行版增强版
5# 作者: Mercas
6# 日期: 2025-11-09
7# 版本: v4.2 Multi-Distro Enhanced (依赖检查版)
8#
9# 支持的发行版:
10# - Ubuntu/Debian (apt包管理器)
11# - Arch Linux/Manjaro (pacman + AUR支持)
12#
13# 新增功能:
14# - 防火墙: ufw / iptables / nftables 多选一
15# - 入侵防护: fail2ban / sshguard / crowdsec 多选一
16# - AUR助手: 自动安装yay或paru
17# - SSH密钥: ED25519 (替代RSA 4096)
18#
19# 命令行参数:
20# -y, --yes 跳过所有确认提示 (非交互模式)
21# -h, --help 显示帮助信息
22################################################################################
23
24# ============================================================================
25# 命令行参数解析
26# ============================================================================
27
28FORCE_YES=false
29
30while [[ $# -gt 0 ]]; do
31 case $1 in
32 -y|--yes)
33 FORCE_YES=true
34 shift
35 ;;
36 -h|--help)
37 echo "用法: $0 [选项]"
38 echo "选项:"
39 echo " -y, --yes 跳过所有确认提示 (非交互模式)"
40 echo " -h, --help 显示此帮助信息"
41 exit 0
42 ;;
43 *)
44 echo "未知参数: $1"
45 echo "使用 -h 查看帮助"
46 exit 1
47 ;;
48 esac
49done
50
51# ============================================================================
52# 全局配置
53# ============================================================================
54
55LOG_FILE="/var/log/server_hardening_$(date +%Y%m%d_%H%M%S).log"
56BACKUP_DIR="/root/security_backup_$(date +%Y%m%d_%H%M%S)"
57ROLLBACK_DIR="/root/security_rollback_$(date +%Y%m%d_%H%M%S)"
58REPORT_FILE="/root/security_hardening_report_$(date +%Y%m%d_%H%M%S).txt"
59
60# 错误级别
61ERROR_CRITICAL=1
62ERROR_SEVERE=2
63ERROR_WARNING=3
64ERROR_INFO=4
65
66# ============================================================================
67# 依赖检查
68# ============================================================================
69
70check_dependencies() {
71 log_section "检查脚本依赖"
72
73 local missing_deps=()
74 local core_commands=("bash" "grep" "sed" "awk" "cat" "echo" "chmod" "chown" "cp" "mv" "rm" "mkdir" "date" "sleep" "tail" "head" "find")
75 local distro_commands=()
76
77 case $PACKAGE_MANAGER in
78 apt)
79 distro_commands=("apt" "dpkg" "systemctl")
80 ;;
81 pacman)
82 distro_commands=("pacman" "systemctl")
83 ;;
84 esac
85
86 # 检查核心命令
87 log_info "检查核心命令..."
88 for cmd in "${core_commands[@]}"; do
89 if ! command -v "$cmd" &> /dev/null; then
90 missing_deps+=("$cmd (core)")
91 log_warning "缺少核心命令: $cmd"
92 fi
93 done
94
95 # 检查发行版相关命令
96 log_info "检查发行版相关命令..."
97 for cmd in "${distro_commands[@]}"; do
98 if ! command -v "$cmd" &> /dev/null; then
99 missing_deps+=("$cmd (distro)")
100 log_warning "缺少发行版命令: $cmd"
101 fi
102 done
103
104 # 检查可选但重要的命令
105 local optional_commands=("curl" "wget" "git" "sha256sum" "openssl")
106 log_info "检查可选命令..."
107 for cmd in "${optional_commands[@]}"; do
108 if ! command -v "$cmd" &> /dev/null; then
109 log_info "可选命令未安装: $cmd (某些功能可能受限)"
110 fi
111 done
112
113 # 报告结果
114 if [[ ${#missing_deps[@]} -gt 0 ]]; then
115 log_error "缺少必要的依赖: ${missing_deps[*]}"
116 log_info "尝试安装缺失的包..."
117
118 case $PACKAGE_MANAGER in
119 apt)
120 apt update -y 2>&1 | tee -a "$LOG_FILE"
121 apt install -y coreutils systemd 2>&1 | tee -a "$LOG_FILE" || true
122 ;;
123 pacman)
124 pacman -Sy 2>&1 | tee -a "$LOG_FILE"
125 pacman -S --needed coreutils systemd 2>&1 | tee -a "$LOG_FILE" || true
126 ;;
127 esac
128
129 # 重新检查
130 for cmd in "${core_commands[@]}" "${distro_commands[@]}"; do
131 if ! command -v "$cmd" &> /dev/null; then
132 handle_error $ERROR_SEVERE "命令 $cmd 仍然不可用,脚本无法继续执行" 1 $LINENO
133 fi
134 done
135 fi
136
137 # 检查网络工具
138 if ! command -v ss &> /dev/null && ! command -v netstat &> /dev/null && ! command -v ip &> /dev/null; then
139 log_warning "网络工具(ss/netstat/ip)都不可用,端口检查功能将受限"
140 fi
141
142 # 检查SSH
143 if ! command -v sshd &> /dev/null && ! command -v ssh-keygen &> /dev/null; then
144 log_warning "OpenSSH未安装,SSH加固功能将受限"
145 fi
146
147 log_success "依赖检查完成"
148}
149
150# ============================================================================
151# 发行版检测
152# ============================================================================
153
154detect_distribution() {
155 if [[ -f /etc/os-release ]]; then
156 . /etc/os-release
157 DISTRO_ID="${ID}"
158 DISTRO_NAME="${NAME}"
159 DISTRO_VERSION="${VERSION_ID}"
160 elif [[ -f /etc/lsb-release ]]; then
161 . /etc/lsb-release
162 DISTRO_ID="${DISTRIB_ID}"
163 DISTRO_NAME="${DISTRIB_DESCRIPTION}"
164 DISTRO_VERSION="${DISTRIB_RELEASE}"
165 else
166 DISTRO_ID="unknown"
167 DISTRO_NAME="Unknown Linux"
168 DISTRO_VERSION="unknown"
169 fi
170
171 case "${DISTRO_ID}" in
172 ubuntu)
173 DISTRO_FAMILY="debian"
174 PACKAGE_MANAGER="apt"
175 ;;
176 debian)
177 DISTRO_FAMILY="debian"
178 PACKAGE_MANAGER="apt"
179 ;;
180 arch|manjaro|antergos)
181 DISTRO_FAMILY="arch"
182 PACKAGE_MANAGER="pacman"
183 ;;
184 *)
185 if command -v pacman &> /dev/null; then
186 DISTRO_FAMILY="arch"
187 PACKAGE_MANAGER="pacman"
188 else
189 DISTRO_FAMILY="debian"
190 PACKAGE_MANAGER="apt"
191 fi
192 ;;
193 esac
194
195 echo "检测到发行版: $DISTRO_NAME ($DISTRO_FAMILY)"
196}
197
198# ============================================================================
199# 颜色定义
200# ============================================================================
201
202setup_colors() {
203 if command -v tput &> /dev/null && [[ -n "$TERM" ]]; then
204 RED=$(tput setaf 1 2>/dev/null || echo '\033[0;31m')
205 GREEN=$(tput setaf 2 2>/dev/null || echo '\033[0;32m')
206 YELLOW=$(tput setaf 3 2>/dev/null || echo '\033[1;33m')
207 BLUE=$(tput setaf 4 2>/dev/null || echo '\033[0;34m')
208 CYAN=$(tput setaf 6 2>/dev/null || echo '\033[0;36m')
209 NC=$(tput sgr0 2>/dev/null || echo '\033[0m')
210 else
211 RED='\033[0;31m'
212 GREEN='\033[0;32m'
213 YELLOW='\033[1;33m'
214 BLUE='\033[0;34m'
215 CYAN='\033[0;36m'
216 NC='\033[0m'
217 fi
218}
219
220# ============================================================================
221# 日志函数
222# ============================================================================
223
224log() {
225 echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
226}
227
228log_info() {
229 echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"
230}
231
232log_warning() {
233 echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
234}
235
236log_error() {
237 echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
238}
239
240log_success() {
241 echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
242}
243
244log_section() {
245 echo -e "\n${CYAN}========================================${NC}" | tee -a "$LOG_FILE"
246 echo -e "${CYAN}$1${NC}" | tee -a "$LOG_FILE"
247 echo -e "${CYAN}========================================${NC}\n" | tee -a "$LOG_FILE"
248}
249
250log_rollback() {
251 echo -e "${YELLOW}[ROLLBACK]${NC} $1" | tee -a "$LOG_FILE"
252}
253
254# ============================================================================
255# 核心工具函数
256# ============================================================================
257
258check_root() {
259 if [[ $EUID -ne 0 ]]; then
260 log_error "此脚本必须以root权限运行"
261 exit 1
262 fi
263}
264
265handle_error() {
266 local error_level=$1
267 local message=$2
268 local exit_code=${3:-1}
269 local lineno=${4:-0}
270
271 case $error_level in
272 $ERROR_CRITICAL)
273 log_error "[致命错误] $message (行号: $lineno, 退出码: $exit_code)"
274 exit $exit_code
275 ;;
276 $ERROR_SEVERE)
277 log_error "[严重错误] $message (行号: $lineno, 退出码: $exit_code)"
278 if confirm_action "发生严重错误,是否回滚所有更改并退出?"; then
279 execute_rollback
280 exit $exit_code
281 fi
282 ;;
283 $ERROR_WARNING)
284 log_warning "[警告] $message"
285 ;;
286 $ERROR_INFO)
287 log_info "[信息] $message"
288 ;;
289 esac
290}
291
292backup_file() {
293 local file=$1
294 local description=${2:-"备份"}
295
296 if [[ -f "$file" ]]; then
297 mkdir -p "$BACKUP_DIR"
298 local backup_path="$BACKUP_DIR/$(basename "$file").bak"
299 local checksum_file="$backup_path.sha256"
300
301 cp -p "$file" "$backup_path"
302
303 if command -v sha256sum &> /dev/null; then
304 sha256sum "$backup_path" > "$checksum_file"
305 log_info "已备份: $(basename "$file") (SHA256: $(sha256sum --short "$backup_path"))"
306 else
307 log_info "已备份: $(basename "$file")"
308 fi
309
310 echo "$file:$backup_path:$(date +%s)" >> "$ROLLBACK_DIR/rollback_list.txt"
311 fi
312}
313
314init_rollback() {
315 mkdir -p "$ROLLBACK_DIR"
316 touch "$ROLLBACK_DIR/rollback_list.txt"
317 touch "$ROLLBACK_DIR/actions.log"
318 log_info "回滚机制已初始化: $ROLLBACK_DIR"
319}
320
321execute_rollback() {
322 log_rollback "开始执行回滚操作..."
323
324 if [[ ! -f "$ROLLBACK_DIR/rollback_list.txt" ]]; then
325 log_warning "没有回滚记录可执行"
326 return 0
327 fi
328
329 while IFS=: read -r original backup timestamp; do
330 if [[ -f "$backup" ]] && [[ -f "$original" ]]; then
331 cp "$backup" "$original"
332 log_rollback "已还原: $original"
333 fi
334 done < "$ROLLBACK_DIR/rollback_list.txt"
335
336 log_success "回滚操作完成"
337}
338
339record_rollback_action() {
340 local action_type=$1
341 local target=$2
342 local command=$3
343 local timestamp=$(date +%s)
344 echo "$timestamp:$action_type:$target:$command" >> "$ROLLBACK_DIR/actions.log"
345}
346
347# 安全获取主机名 (处理hostname命令不存在的情况)
348get_hostname() {
349 if command -v hostname &> /dev/null; then
350 hostname
351 elif [[ -f /etc/hostname ]]; then
352 cat /etc/hostname
353 elif [[ -f /proc/sys/kernel/hostname ]]; then
354 cat /proc/sys/kernel/hostname
355 else
356 uname -n
357 fi
358}
359
360# 安全获取IP地址
361get_ip_address() {
362 if command -v hostname &> /dev/null; then
363 local ip=$(hostname -I 2>/dev/null | awk '{print $1}')
364 if [[ -n "$ip" ]]; then
365 echo "$ip"
366 elif command -v ip &> /dev/null; then
367 ip addr show 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1 || echo 'N/A'
368 else
369 echo 'N/A'
370 fi
371 elif command -v ip &> /dev/null; then
372 ip addr show 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1 || echo 'N/A'
373 elif [[ -f /proc/net/dev ]]; then
374 grep -oP 'inet \K[\d.]+' /proc/net/fib_trie 2>/dev/null | head -1 || echo 'N/A'
375 else
376 echo 'N/A'
377 fi
378}
379
380confirm_action() {
381 local message=$1
382 # 如果强制确认标志为真,直接返回成功
383 if [[ "$FORCE_YES" == "true" ]]; then
384 log_info "[自动确认] $message"
385 return 0
386 fi
387 if [[ -t 0 ]]; then
388 echo -e "${YELLOW}${message} [y/N]: ${NC}\c"
389 read -n 1 -r
390 echo
391 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
392 return 1
393 fi
394 return 0
395 else
396 log_info "[非交互模式跳过] $message"
397 return 1
398 fi
399}
400
401check_port_available() {
402 local port=$1
403 local service_name=$2
404
405 if ss -tunlp 2>/dev/null | grep -q ":$port "; then
406 log_warning "端口 $port 已被占用"
407 if ! confirm_action "是否继续使用端口 $port"; then
408 return 1
409 fi
410 fi
411 return 0
412}
413
414# ============================================================================
415# 包管理器抽象层
416# ============================================================================
417
418update_package_list() {
419 case $PACKAGE_MANAGER in
420 apt)
421 apt update -y 2>&1 | tee -a "$LOG_FILE"
422 ;;
423 pacman)
424 pacman -Sy 2>&1 | tee -a "$LOG_FILE"
425 ;;
426 esac
427}
428
429install_package() {
430 local package=$1
431 local description=${2:-"安装软件包"}
432
433 log_info "安装: $package ($description)"
434
435 case $PACKAGE_MANAGER in
436 apt)
437 if dpkg -l 2>/dev/null | grep -q "^ii $package "; then
438 log_info "$package 已安装"
439 return 0
440 fi
441 apt install -y "$package" 2>&1 | tee -a "$LOG_FILE"
442 return ${PIPESTATUS[0]}
443 ;;
444 pacman)
445 if pacman -Qq "$package" &>/dev/null; then
446 log_info "$package 已安装"
447 return 0
448 fi
449 pacman -S --noconfirm "$package" 2>&1 | tee -a "$LOG_FILE"
450 return ${PIPESTATUS[0]}
451 ;;
452 esac
453}
454
455is_package_installed() {
456 local package=$1
457
458 case $PACKAGE_MANAGER in
459 apt)
460 dpkg -l 2>/dev/null | grep -q "^ii $package"
461 ;;
462 pacman)
463 pacman -Qq "$package" &>/dev/null
464 ;;
465 esac
466}
467
468enable_service() {
469 local service=$1
470
471 if command -v systemctl &> /dev/null; then
472 systemctl enable "$service" 2>&1 | tee -a "$LOG_FILE"
473 systemctl start "$service" 2>&1 | tee -a "$LOG_FILE"
474 fi
475}
476
477disable_service() {
478 local service=$1
479
480 if command -v systemctl &> /dev/null; then
481 systemctl stop "$service" 2>&1 | tee -a "$LOG_FILE" || true
482 systemctl disable "$service" 2>&1 | tee -a "$LOG_FILE" || true
483 fi
484}
485
486# ============================================================================
487# AUR助手安装
488# ============================================================================
489
490install_aur_helper() {
491 log_section "安装AUR助手"
492
493 if ! command -v git &> /dev/null; then
494 log_info "安装git..."
495 pacman -S --noconfirm git 2>&1 | tee -a "$LOG_FILE"
496 fi
497
498 if command -v yay &> /dev/null || command -v paru &> /dev/null; then
499 log_info "AUR助手已安装"
500 return 0
501 fi
502
503 echo -e "${YELLOW}请选择AUR助手:${NC}"
504 echo "1) yay (更流行)"
505 echo "2) paru (功能更丰富)"
506 echo "3) 跳过安装"
507 echo -e "${YELLOW}选择 [1-3]: ${NC}\c"
508 read -p "" aur_choice
509
510 local aur_helper=""
511 local aur_repo=""
512
513 case $aur_choice in
514 1)
515 aur_helper="yay"
516 aur_repo="https://aur.archlinux.org/yay.git"
517 ;;
518 2)
519 aur_helper="paru"
520 aur_repo="https://aur.archlinux.org/paru.git"
521 ;;
522 3)
523 log_info "跳过AUR助手安装"
524 return 0
525 ;;
526 *)
527 log_warning "无效选择"
528 return 1
529 ;;
530 esac
531
532 # 确保base-devel已安装
533 log_info "安装构建依赖..."
534 pacman -S --needed --noconfirm base-devel 2>&1 | tee -a "$LOG_FILE"
535
536 # 克隆并安装AUR助手
537 local temp_dir=$(mktemp -d)
538 cd "$temp_dir"
539
540 log_info "从AUR安装 $aur_helper..."
541 git clone "$aur_repo" 2>&1 | tee -a "$LOG_FILE"
542 cd "$aur_helper"
543
544 if makepkg -si --noconfirm 2>&1 | tee -a "$LOG_FILE"; then
545 log_success "$aur_helper 安装成功"
546
547 # 记录回滚命令
548 record_rollback_action "aur_helper" "$aur_helper" "pacman -Rns $aur_helper"
549 else
550 log_error "$aur_helper 安装失败"
551 rm -rf "$temp_dir"
552 return 1
553 fi
554
555 rm -rf "$temp_dir"
556
557 # 验证安装
558 if command -v $aur_helper &> /dev/null; then
559 log_success "AUR助手 $aur_helper 已就绪"
560 fi
561}
562
563install_aur_package() {
564 local package=$1
565 local description=${2:-"AUR包"}
566
567 # 优先使用pacman
568 if is_package_installed "$package"; then
569 log_info "$package 已安装"
570 return 0
571 fi
572
573 # 尝试pacman
574 if pacman -S --noconfirm "$package" 2>&1 | tee -a "$LOG_FILE"; then
575 return 0
576 fi
577
578 # 使用AUR助手
579 if command -v yay &> /dev/null; then
580 log_info "使用yay安装 $package..."
581 yay -S --noconfirm "$package" 2>&1 | tee -a "$LOG_FILE"
582 elif command -v paru &> /dev/null; then
583 log_info "使用paru安装 $package..."
584 paru -S --noconfirm "$package" 2>&1 | tee -a "$LOG_FILE"
585 else
586 log_warning "无AUR助手可用,跳过 $package 安装"
587 return 1
588 fi
589}
590
591# ============================================================================
592# 密码策略配置
593# ============================================================================
594
595configure_password_policy() {
596 log_info "配置密码策略..."
597
598 case $PACKAGE_MANAGER in
599 apt)
600 if ! is_package_installed "libpam-pwquality"; then
601 install_package "libpam-pwquality" "密码质量检查"
602 fi
603
604 local pwquality_file="/etc/security/pwquality.conf"
605 backup_file "$pwquality_file"
606
607 if ! grep -q "^minlen = 12" "$pwquality_file" 2>/dev/null; then
608 cat >> "$pwquality_file" << 'EOF'
609
610# 密码安全策略
611minlen = 12
612dcredit = -1
613ucredit = -1
614lcredit = -1
615ocredit = -1
616maxrepeat = 3
617EOF
618 fi
619 ;;
620 pacman)
621 if ! is_package_installed "libpwquality"; then
622 install_package "libpwquality" "密码质量检查库"
623 fi
624
625 local login_defs="/etc/login.defs"
626 if [[ -f "$login_defs" ]]; then
627 backup_file "$login_defs"
628 sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' "$login_defs" 2>/dev/null || true
629 sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' "$login_defs" 2>/dev/null || true
630 sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE 14/' "$login_defs" 2>/dev/null || true
631 fi
632 ;;
633 esac
634
635 log_success "密码策略配置完成"
636}
637
638# ============================================================================
639# 防火墙配置 (支持 ufw / iptables / nftables)
640# ============================================================================
641
642configure_firewall() {
643 log_section "配置防火墙"
644
645 local ssh_port=22
646
647 # 检测SSH端口
648 if [[ -f "/etc/ssh/sshd_config" ]]; then
649 ssh_port=$(grep -E "^Port [0-9]+" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}' | head -1)
650 ssh_port=${ssh_port:-22}
651 fi
652
653 echo -e "${YELLOW}请选择防火墙方案:${NC}"
654 echo "1) UFW (简单防火墙) - 推荐Ubuntu/新手"
655 echo "2) iptables (传统防火墙) - 通用选择"
656 echo "3) nftables (下一代防火墙) - Arch推荐,更高效"
657 echo "4) 跳过防火墙配置"
658 echo -e "${YELLOW}选择 [1-4]: ${NC}\c"
659 read -p "" firewall_choice
660
661 case $firewall_choice in
662 1)
663 configure_ufw "$ssh_port"
664 ;;
665 2)
666 configure_iptables "$ssh_port"
667 ;;
668 3)
669 configure_nftables "$ssh_port"
670 ;;
671 4)
672 log_info "跳过防火墙配置"
673 ;;
674 *)
675 log_warning "无效选择,使用默认iptables"
676 configure_iptables "$ssh_port"
677 ;;
678 esac
679}
680
681configure_ufw() {
682 local ssh_port=$1
683
684 log_info "配置UFW防火墙..."
685
686 if ! is_package_installed "ufw"; then
687 install_package "ufw" "简单防火墙"
688 fi
689
690 ufw default deny incoming 2>&1 | tee -a "$LOG_FILE"
691 ufw default allow outgoing 2>&1 | tee -a "$LOG_FILE"
692
693 if [[ -t 0 ]]; then
694 echo -e "${YELLOW}SSH端口 (默认$ssh_port): ${NC}\c"
695 read -p "" ssh_port_input
696 ssh_port=${ssh_port_input:-$ssh_port}
697 fi
698
699 ufw allow "$ssh_port/tcp" comment 'SSH' 2>&1 | tee -a "$LOG_FILE"
700
701 if confirm_action "是否开放HTTP(80)端口?"; then
702 ufw allow 80/tcp comment 'HTTP' 2>&1 | tee -a "$LOG_FILE"
703 fi
704
705 if confirm_action "是否开放HTTPS(443)端口?"; then
706 ufw allow 443/tcp comment 'HTTPS' 2>&1 | tee -a "$LOG_FILE"
707 fi
708
709 if [[ -t 0 ]]; then
710 echo "y" | ufw enable 2>&1 | tee -a "$LOG_FILE"
711 else
712 ufw --force enable 2>&1 | tee -a "$LOG_FILE"
713 fi
714
715 ufw status numbered 2>/dev/null | tee -a "$LOG_FILE"
716
717 record_rollback_action "firewall" "ufw" "ufw reset"
718 log "UFW防火墙配置完成"
719}
720
721configure_iptables() {
722 local ssh_port=$1
723
724 log_info "配置iptables防火墙..."
725
726 if ! command -v iptables &> /dev/null; then
727 install_package "iptables" "防火墙工具"
728 fi
729
730 if command -v systemctl &> /dev/null; then
731 systemctl enable iptables 2>/dev/null || true
732 systemctl start iptables 2>/dev/null || true
733 fi
734
735 # 刷新现有规则
736 iptables -F 2>&1 | tee -a "$LOG_FILE" || true
737 iptables -X 2>&1 | tee -a "$LOG_FILE" || true
738
739 # 设置默认策略
740 iptables -P INPUT DROP 2>&1 | tee -a "$LOG_FILE"
741 iptables -P FORWARD DROP 2>&1 | tee -a "$LOG_FILE"
742 iptables -P OUTPUT ACCEPT 2>&1 | tee -a "$LOG_FILE"
743
744 if [[ -t 0 ]]; then
745 echo -e "${YELLOW}SSH端口 (默认$ssh_port): ${NC}\c"
746 read -p "" ssh_port_input
747 ssh_port=${ssh_port_input:-$ssh_port}
748 fi
749
750 # 允许SSH
751 iptables -A INPUT -p tcp --dport "$ssh_port" -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
752
753 # 允许回环
754 iptables -A INPUT -i lo -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
755 iptables -A OUTPUT -o lo -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
756
757 # 允许已建立的连接
758 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
759
760 if confirm_action "是否开放HTTP(80)端口?"; then
761 iptables -A INPUT -p tcp --dport 80 -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
762 fi
763
764 if confirm_action "是否开放HTTPS(443)端口?"; then
765 iptables -A INPUT -p tcp --dport 443 -j ACCEPT 2>&1 | tee -a "$LOG_FILE"
766 fi
767
768 # 保存规则
769 mkdir -p /etc/iptables
770 iptables-save > /etc/iptables/iptables.rules 2>&1 | tee -a "$LOG_FILE"
771
772 iptables -L -n 2>/dev/null | tee -a "$LOG_FILE"
773
774 record_rollback_action "firewall" "iptables" "iptables -F"
775 log "iptables防火墙配置完成"
776}
777
778configure_nftables() {
779 local ssh_port=$1
780
781 log_info "配置nftables防火墙..."
782
783 if ! command -v nft &> /dev/null; then
784 install_package "nftables" "下一代防火墙"
785 fi
786
787 # 确保服务已启用
788 if command -v systemctl &> /dev/null; then
789 systemctl enable nftables 2>&1 | tee -a "$LOG_FILE"
790 systemctl start nftables 2>&1 | tee -a "$LOG_FILE"
791 fi
792
793 # 备份现有配置
794 if [[ -f /etc/nftables.conf ]]; then
795 backup_file "/etc/nftables.conf"
796 fi
797
798 if [[ -t 0 ]]; then
799 echo -e "${YELLOW}SSH端口 (默认$ssh_port): ${NC}\c"
800 read -p "" ssh_port_input
801 ssh_port=${ssh_port_input:-$ssh_port}
802 fi
803
804 # 创建nftables配置
805 cat > /etc/nftables.conf << EOF
806#!/usr/bin/nft -f
807
808# 刷新所有规则
809flush ruleset
810
811# 定义表
812table inet filter {
813 # 链定义
814 chain input {
815 type filter hook input priority 0; policy drop;
816
817 # 允许回环
818 iif lo accept
819
820 # 允许已建立的连接
821 ct state established,related accept
822
823 # SSH
824 tcp dport $ssh_port accept
825
826 # HTTP/HTTPS (可选)
827 # tcp dport {80, 443} accept
828
829 # 拒绝其他入站
830 reject with icmpx type administratively-prohibited
831 }
832
833 chain forward {
834 type filter hook forward priority 0; policy drop;
835 }
836
837 chain output {
838 type filter hook output priority 0; policy accept;
839 }
840}
841EOF
842
843 log_info "SSH端口: $ssh_port"
844
845 if confirm_action "是否开放HTTP(80)和HTTPS(443)端口?"; then
846 sed -i 's|# tcp dport {80, 443} accept|tcp dport {80, 443} accept|' /etc/nftables.conf
847 log_info "已添加HTTP/HTTPS规则"
848 fi
849
850 # 测试并加载配置
851 nft -f /etc/nftables.conf 2>&1 | tee -a "$LOG_FILE"
852
853 if [[ $? -eq 0 ]]; then
854 log_success "nftables配置已应用"
855 else
856 log_error "nftables配置失败"
857 return 1
858 fi
859
860 # 显示状态
861 nft list ruleset 2>&1 | tee -a "$LOG_FILE"
862
863 record_rollback_action "firewall" "nftables" "nft flush ruleset"
864 log "nftables防火墙配置完成"
865}
866
867# ============================================================================
868# 入侵防御系统 (支持 fail2ban / sshguard / crowdsec)
869# ============================================================================
870
871install_intrusion_prevention() {
872 log_section "配置入侵防御系统"
873
874 echo -e "${YELLOW}请选择入侵防御方案:${NC}"
875 echo "1) Fail2ban (功能丰富,支持多服务)"
876 echo "2) Sshguard (轻量级,专注SSH)"
877 echo "3) Crowdsec (社区驱动,AI增强)"
878 echo "4) 跳过安装"
879 echo -e "${YELLOW}选择 [1-4]: ${NC}\c"
880 read -p "" ips_choice
881
882 case $ips_choice in
883 1)
884 install_fail2ban
885 ;;
886 2)
887 install_sshguard
888 ;;
889 3)
890 install_crowdsec
891 ;;
892 4)
893 log_info "跳过入侵防御系统安装"
894 ;;
895 *)
896 log_warning "无效选择"
897 ;;
898 esac
899}
900
901install_fail2ban() {
902 log_info "安装Fail2ban..."
903
904 case $PACKAGE_MANAGER in
905 apt)
906 install_package "fail2ban" "入侵防御"
907 ;;
908 pacman)
909 install_package "fail2ban" "入侵防御"
910 ;;
911 esac
912
913 if command -v fail2ban-client &> /dev/null; then
914 configure_fail2ban
915 fi
916}
917
918configure_fail2ban() {
919 log_info "配置Fail2ban..."
920
921 local jail_local="/etc/fail2ban/jail.local"
922 backup_file "$jail_local" 2>/dev/null || true
923
924 cat > "$jail_local" << 'EOF'
925[DEFAULT]
926bantime = 3600
927findtime = 600
928maxretry = 5
929
930[sshd]
931enabled = true
932port = ssh
933filter = sshd
934logpath = /var/log/auth.log
935maxretry = 3
936bantime = 7200
937
938[sshd-ddos]
939enabled = true
940port = ssh
941filter = sshd-ddos
942logpath = /var/log/auth.log
943maxretry = 2
944bantime = 7200
945EOF
946
947 enable_service "fail2ban"
948 sleep 2
949
950 if command -v fail2ban-client &> /dev/null; then
951 fail2ban-client status 2>/dev/null | tee -a "$LOG_FILE"
952 fi
953
954 log_success "Fail2ban配置完成"
955}
956
957install_sshguard() {
958 log_info "安装Sshguard..."
959
960 case $PACKAGE_MANAGER in
961 apt)
962 install_package "sshguard" "SSH入侵防御"
963 ;;
964 pacman)
965 install_package "sshguard" "SSH入侵防御"
966 ;;
967 esac
968
969 if command -v sshguard &> /dev/null; then
970 configure_sshguard
971 fi
972}
973
974configure_sshguard() {
975 log_info "配置Sshguard..."
976
977 if command -v systemctl &> /dev/null; then
978 systemctl enable sshguard 2>&1 | tee -a "$LOG_FILE"
979 systemctl start sshguard 2>&1 | tee -a "$LOG_FILE"
980 fi
981
982 log_success "Sshguard已启动"
983}
984
985install_crowdsec() {
986 log_section "安装Crowdsec"
987
988 log_info "Crowdsec - 社区驱动的入侵防御系统"
989 echo -e "${YELLOW}特点:${NC}"
990 echo "• 社区威胁情报共享"
991 echo "• 轻量级,高性能"
992 echo "• 自动学习正常行为"
993 echo "• 支持多种防火墙集成"
994
995 if ! confirm_action "是否安装Crowdsec?"; then
996 log_info "跳过Crowdsec安装"
997 return 0
998 fi
999
1000 case $PACKAGE_MANAGER in
1001 apt)
1002 # 使用官方安装脚本
1003 log_info "从官方源安装Crowdsec..."
1004 curl -s https://install.crowdsec.net | sh 2>&1 | tee -a "$LOG_FILE"
1005 ;;
1006 pacman)
1007 # 从AUR安装
1008 log_info "从AUR安装Crowdsec..."
1009 if ! is_package_installed "crowdsec"; then
1010 install_aur_package "crowdsec" "Crowdsec核心"
1011 fi
1012 if ! is_package_installed "crowdsec-firewall-bouncer"; then
1013 install_aur_package "crowdsec-firewall-bouncer" "防火墙联动"
1014 fi
1015 ;;
1016 esac
1017
1018 if command -v cscli &> /dev/null; then
1019 configure_crowdsec
1020 fi
1021}
1022
1023configure_crowdsec() {
1024 log_info "配置Crowdsec..."
1025
1026 # 初始化
1027 cscli console enable 2>&1 | tee -a "$LOG_FILE"
1028
1029 # 获取推荐场景
1030 log_info "安装推荐场景..."
1031 cscli scenarios list 2>&1 | tee -a "$LOG_FILE" | head -20
1032
1033 # 安装SSH防护
1034 log_info "启用SSH防护..."
1035 cscli scenarios install crowdsecurity/ssh-bf 2>&1 | tee -a "$LOG_FILE"
1036
1037 # 安装防火墙bouncer
1038 log_info "配置防火墙联动..."
1039 case $PACKAGE_MANAGER in
1040 apt)
1041 if is_package_installed "ufw"; then
1042 cscli bouncers add crowdsec-ufw-bouncer 2>&1 | tee -a "$LOG_FILE"
1043 elif command -v nft &> /dev/null; then
1044 cscli bouncers add crowdsec-nft-bouncer 2>&1 | tee -a "$LOG_FILE"
1045 fi
1046 ;;
1047 pacman)
1048 if command -v nft &> /dev/null; then
1049 cscli bouncers add crowdsec-nft-bouncer 2>&1 | tee -a "$LOG_FILE"
1050 fi
1051 ;;
1052 esac
1053
1054 # 启动服务
1055 enable_service "crowdsec"
1056
1057 sleep 2
1058
1059 # 显示状态
1060 cscli metrics 2>&1 | tee -a "$LOG_FILE" | head -20
1061
1062 log_success "Crowdsec配置完成"
1063 log_info "运行 'cscli dashboard setup' 可安装可视化面板"
1064}
1065
1066# ============================================================================
1067# 自动安全更新
1068# ============================================================================
1069
1070configure_auto_updates() {
1071 log_section "配置自动安全更新"
1072
1073 case $PACKAGE_MANAGER in
1074 apt)
1075 if confirm_action "是否启用自动安全更新?"; then
1076 if ! is_package_installed "unattended-upgrades"; then
1077 install_package "unattended-upgrades" "自动更新"
1078 fi
1079 echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | debconf-set-selections 2>&1 | tee -a "$LOG_FILE"
1080 log "自动安全更新已启用"
1081 fi
1082 ;;
1083 pacman)
1084 log_warning "Arch Linux不推荐完全自动更新"
1085 if confirm_action "是否配置pacman更新通知?"; then
1086 local cron_file="/etc/cron.daily/check-updates"
1087 cat > "$cron_file" << 'EOF'
1088#!/bin/bash
1089pacman -Sy 2>/dev/null
1090echo "系统检查完成"
1091EOF
1092 chmod +x "$cron_file"
1093 log_info "已配置每日更新检查"
1094 fi
1095 ;;
1096 esac
1097}
1098
1099# ============================================================================
1100# 安全审计工具
1101# ============================================================================
1102
1103install_security_tools() {
1104 log_section "安装额外安全工具"
1105
1106 if [[ "$PACKAGE_MANAGER" == "pacman" ]]; then
1107 # 确保AUR助手已安装
1108 if ! command -v yay &> /dev/null && ! command -v paru &> /dev/null; then
1109 if confirm_action "是否安装AUR助手以获取更多安全工具?"; then
1110 install_aur_helper
1111 fi
1112 fi
1113 fi
1114
1115 local tools=()
1116
1117 case $PACKAGE_MANAGER in
1118 apt)
1119 tools=("auditd")
1120 echo -e "${YELLOW}注意: aide和rkhunter可通过apt安装${NC}"
1121 ;;
1122 pacman)
1123 tools=("auditd")
1124 echo -e "${YELLOW}提示: aide和rkhunter可从AUR安装${NC}"
1125 ;;
1126 esac
1127
1128 for tool in "${tools[@]}"; do
1129 if confirm_action "是否安装 $tool"; then
1130 if is_package_installed "$tool"; then
1131 log_info "$tool 已安装"
1132 continue
1133 fi
1134 install_package "$tool" "安全工具"
1135 enable_service "$tool" 2>/dev/null || true
1136 fi
1137 done
1138
1139 # 额外的AUR选项
1140 if [[ "$PACKAGE_MANAGER" == "pacman" ]]; then
1141 if confirm_action "是否从AUR安装 aide (文件完整性)?"; then
1142 install_aur_package "aide" "文件完整性检查"
1143 fi
1144 if confirm_action "是否从AUR安装 rkhunter (Rootkit检测)?"; then
1145 install_aur_package "rkhunter" "Rootkit检测"
1146 fi
1147 fi
1148}
1149
1150# ============================================================================
1151# SSH密钥和用户管理 (使用ED25519)
1152# ============================================================================
1153
1154verify_ssh_key_exists() {
1155 local username=$1
1156
1157 if [[ -z "$username" ]]; then
1158 return 1
1159 fi
1160
1161 local user_home=$(eval echo "~$username")
1162 local ssh_dir="$user_home/.ssh"
1163 local authorized_keys="$ssh_dir/authorized_keys"
1164
1165 if [[ -f "$authorized_keys" ]] && [[ -s "$authorized_keys" ]]; then
1166 local key_count=$(grep -c "ssh-" "$authorized_keys" 2>/dev/null || echo 0)
1167 if [[ $key_count -gt 0 ]]; then
1168 log_success "用户 $username 已有 $key_count 个SSH公钥"
1169 return 0
1170 fi
1171 fi
1172 return 1
1173}
1174
1175setup_ssh_key() {
1176 local username=$1
1177 local public_key=$2
1178 local user_home=$(eval echo "~$username")
1179 local ssh_dir="$user_home/.ssh"
1180 local authorized_keys="$ssh_dir/authorized_keys"
1181
1182 mkdir -p "$ssh_dir"
1183 echo "$public_key" > "$authorized_keys"
1184 record_rollback_action "ssh_key" "$username" "rm -f $authorized_keys"
1185 log_success "SSH公钥已设置"
1186}
1187
1188# 优化:使用ED25519替代RSA
1189setup_generate_key() {
1190 local username=$1
1191 local user_home=$(eval echo "~$username")
1192 local ssh_dir="$user_home/.ssh"
1193 local key_file="$ssh_dir/id_ed25519"
1194
1195 mkdir -p "$ssh_dir"
1196 chown "$username:$username" "$ssh_dir"
1197
1198 if [[ ! -f "$key_file" ]]; then
1199 log_info "生成ED25519 SSH密钥对..."
1200 log_info "ED25519: 比RSA更安全更快,256位即可达到4096位RSA的安全性"
1201
1202 record_rollback_action "ssh_keygen" "$username" "rm -f $key_file $key_file.pub"
1203
1204 # 使用ED25519生成密钥
1205 su - "$username" -c "ssh-keygen -t ed25519 -f '$key_file' -C '$username@$(get_hostname)'"
1206
1207 if [[ -f "$key_file" ]]; then
1208 log_success "ED25519密钥对生成成功"
1209 log_info "私钥文件: $key_file"
1210 log_info "公钥文件: $key_file.pub"
1211 log_warning "请妥善保管私钥文件"
1212
1213 echo -e "${YELLOW}公钥内容 (添加到authorized_keys):${NC}"
1214 cat "$key_file.pub"
1215 echo ""
1216 else
1217 log_error "SSH密钥生成失败,回退到RSA..."
1218 # 回退到RSA
1219 local rsa_key_file="$ssh_dir/id_rsa"
1220 su - "$username" -c "ssh-keygen -t rsa -b 4096 -f '$rsa_key_file' -N '' -C '$username@$(get_hostname)'"
1221 if [[ -f "$rsa_key_file" ]]; then
1222 log_success "RSA密钥对生成成功"
1223 log_info "密钥文件: $rsa_key_file"
1224 fi
1225 return 1
1226 fi
1227 else
1228 log_info "SSH密钥已存在 ($key_file)"
1229 fi
1230}
1231
1232configure_sudo_settings() {
1233 local username=$1
1234
1235 log_info "配置sudo权限..."
1236
1237 echo -e "${YELLOW}请选择sudo权限级别:${NC}"
1238 echo "1) 完全无密码sudo"
1239 echo "2) 需要密码sudo (推荐)"
1240 echo "3) 仅特定命令无密码"
1241 echo "4) 不配置"
1242 echo -e "${YELLOW}选择 [1-4]: ${NC}\c"
1243 read -p "" sudo_option
1244
1245 local sudoers_file="/etc/sudoers.d/$username"
1246
1247 case $sudo_option in
1248 1)
1249 echo "$username ALL=(ALL) NOPASSWD:ALL" > "$sudoers_file"
1250 chmod 440 "$sudoers_file"
1251 record_rollback_action "sudoers" "$username" "rm -f $sudoers_file"
1252 log_warning "已配置无密码sudo (安全性较低)"
1253 ;;
1254 2)
1255 echo "$username ALL=(ALL) ALL" > "$sudoers_file"
1256 chmod 440 "$sudoers_file"
1257 record_rollback_action "sudoers" "$username" "rm -f $sudoers_file"
1258 log_success "已配置需要密码的sudo"
1259 ;;
1260 3)
1261 echo -e "${YELLOW}输入允许无密码执行的命令: ${NC}\c"
1262 read -p "" sudo_commands
1263 if [[ -n "$sudo_commands" ]]; then
1264 echo "$username ALL=(ALL) NOPASSWD: $sudo_commands" > "$sudoers_file"
1265 chmod 440 "$sudoers_file"
1266 record_rollback_action "sudoers" "$username" "rm -f $sudoers_file"
1267 log_success "已配置限制性sudo"
1268 fi
1269 ;;
1270 *)
1271 log_info "跳过sudo配置"
1272 ;;
1273 esac
1274}
1275
1276manage_users() {
1277 log_section "创建管理用户和配置SSH密钥"
1278
1279 if ! confirm_action "是否创建专用管理用户?"; then
1280 log_warning "跳过用户创建"
1281 return 0
1282 fi
1283
1284 local username=""
1285
1286 if [[ -t 0 ]]; then
1287 echo -e "${YELLOW}请输入新用户名: ${NC}\c"
1288 read -p "" username
1289 else
1290 username="admin"
1291 fi
1292
1293 if [[ -z "$username" ]] || [[ ! "$username" =~ ^[a-z_][a-z0-9_-]*$ ]]; then
1294 handle_error $ERROR_SEVERE "无效的用户名: $username"
1295 return 1
1296 fi
1297
1298 # 检查用户是否存在
1299 if id "$username" &>/dev/null 2>&1; then
1300 log_info "用户 $username 已存在"
1301 else
1302 log_info "创建用户: $username"
1303 useradd -m -s /bin/bash "$username" 2>&1 | tee -a "$LOG_FILE"
1304
1305 if [[ -t 0 ]]; then
1306 echo -e "${YELLOW}为用户 $username 设置密码: ${NC}\c"
1307 passwd "$username"
1308 else
1309 local temp_password=$(openssl rand -base64 32)
1310 echo "$username:$temp_password" | chpasswd
1311 record_rollback_action "password" "$username" "passwd -d $username"
1312 log_warning "临时密码: $temp_password"
1313 fi
1314
1315 case $PACKAGE_MANAGER in
1316 apt)
1317 usermod -aG sudo "$username" 2>&1 | tee -a "$LOG_FILE"
1318 record_rollback_action "usermod" "$username" "gpasswd -d $username sudo"
1319 ;;
1320 pacman)
1321 usermod -aG wheel "$username" 2>&1 | tee -a "$LOG_FILE"
1322 record_rollback_action "usermod" "$username" "gpasswd -d $username wheel"
1323 if [[ -f "/etc/sudoers" ]]; then
1324 if ! grep -q "^%wheel ALL=" /etc/sudoers 2>/dev/null; then
1325 backup_file "/etc/sudoers"
1326 echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers
1327 fi
1328 fi
1329 ;;
1330 esac
1331 fi
1332
1333 log_info "配置SSH密钥..."
1334 local key_configured=false
1335
1336 if [[ -t 0 ]]; then
1337 echo -e "${YELLOW}选择密钥配置方式: ${NC}"
1338 echo "1) 现有公钥"
1339 echo "2) 生成ED25519密钥 (推荐)"
1340 echo "3) 跳过"
1341 echo -e "${YELLOW}选择 [1-3]: ${NC}\c"
1342 read -p "" key_option
1343 else
1344 key_option="3"
1345 fi
1346
1347 case $key_option in
1348 1)
1349 echo -e "${YELLOW}输入SSH公钥: ${NC}\c"
1350 read -p "" public_key
1351 if [[ -n "$public_key" ]] && [[ "$public_key" =~ ^ssh- ]]; then
1352 setup_ssh_key "$username" "$public_key"
1353 key_configured=true
1354 fi
1355 ;;
1356 2)
1357 setup_generate_key "$username"
1358 key_configured=true
1359 ;;
1360 *)
1361 log_info "跳过密钥配置"
1362 ;;
1363 esac
1364
1365 configure_sudo_settings "$username"
1366
1367 local user_home=$(eval echo "~$username")
1368 local ssh_dir="$user_home/.ssh"
1369
1370 if [[ -d "$ssh_dir" ]]; then
1371 chown -R "$username:$username" "$ssh_dir" 2>&1 | tee -a "$LOG_FILE"
1372 chmod 700 "$ssh_dir" 2>&1 | tee -a "$LOG_FILE"
1373 chmod 600 "$ssh_dir/authorized_keys" 2>&1 | tee -a "$LOG_FILE" || true
1374 fi
1375
1376 if id "$username" &>/dev/null; then
1377 log_success "用户 $username 配置成功"
1378 fi
1379
1380 if $key_configured; then
1381 return 0
1382 else
1383 return 1
1384 fi
1385}
1386
1387# ============================================================================
1388# SSH安全加固
1389# ============================================================================
1390
1391validate_ssh_config() {
1392 local ssh_config="/etc/ssh/sshd_config"
1393
1394 if [[ ! -f "$ssh_config" ]]; then
1395 log_error "SSH配置文件不存在"
1396 return 1
1397 fi
1398
1399 log_info "验证SSH配置语法..."
1400
1401 if command -v sshd &> /dev/null; then
1402 if sshd -t 2>&1; then
1403 log_success "SSH配置语法验证通过"
1404 return 0
1405 else
1406 log_error "SSH配置语法验证失败"
1407 return 1
1408 fi
1409 fi
1410 return 0
1411}
1412
1413harden_ssh() {
1414 log_section "SSH安全加固"
1415
1416 local ssh_config="/etc/ssh/sshd_config"
1417 local ssh_port=22
1418 local key_configured=false
1419
1420 if [[ ! -f "$ssh_config" ]]; then
1421 handle_error $ERROR_SEVERE "SSH配置文件不存在"
1422 fi
1423
1424 backup_file "$ssh_config"
1425
1426 ssh_port=$(grep -E "^Port [0-9]+" "$ssh_config" 2>/dev/null | awk '{print $2}' | head -1)
1427 ssh_port=${ssh_port:-22}
1428
1429 log_info "步骤1/3: 配置用户和SSH密钥..."
1430 if manage_users; then
1431 key_configured=true
1432 fi
1433
1434 log_info "步骤2/3: 配置安全参数..."
1435
1436 if [[ -t 0 ]]; then
1437 echo -e "${YELLOW}修改SSH端口($ssh_port)? 输入新端口或留空: ${NC}\c"
1438 read -p "" new_port
1439 if [[ -n "$new_port" ]] && [[ "$new_port" =~ ^[0-9]+$ ]] && [[ "$new_port" -gt 1024 ]] && [[ "$new_port" -lt 65536 ]]; then
1440 if ! check_port_available "$new_port" "SSH"; then
1441 log_warning "端口检查未通过"
1442 else
1443 log_warning "请更新防火墙开放端口 $new_port"
1444 ssh_port=$new_port
1445 fi
1446 fi
1447 fi
1448
1449 if confirm_action "是否禁用SSH root登录?"; then
1450 sed -i "s/^#*PermitRootLogin.*/PermitRootLogin no/" "$ssh_config"
1451 record_rollback_action "ssh_config" "PermitRootLogin" "sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' $ssh_config"
1452 fi
1453
1454 if $key_configured; then
1455 if confirm_action "SSH密钥已配置,是否禁用密码认证?"; then
1456 sed -i "s/^#*PasswordAuthentication.*/PasswordAuthentication no/" "$ssh_config"
1457 record_rollback_action "ssh_config" "PasswordAuthentication" "sed -i 's/^PasswordAuthentication.*/PasswordAuthentication yes/' $ssh_config"
1458 fi
1459 else
1460 log_warning "SSH密钥未配置,跳过密码认证禁用"
1461 fi
1462
1463 # 添加安全配置
1464 cat >> "$ssh_config" << EOF
1465
1466# 安全加固配置
1467Protocol 2
1468MaxAuthTries 3
1469MaxSessions 2
1470LoginGraceTime 60
1471ClientAliveInterval 300
1472ClientAliveCountMax 2
1473PermitEmptyPasswords no
1474X11Forwarding no
1475UseDNS no
1476EOF
1477
1478 log_info "步骤3/3: 验证并应用配置..."
1479
1480 if ! validate_ssh_config; then
1481 handle_error $ERROR_SEVERE "SSH配置验证失败"
1482 execute_rollback
1483 return 1
1484 fi
1485
1486 if systemctl restart sshd 2>&1 | tee -a "$LOG_FILE"; then
1487 log_success "SSH服务已重启 (端口: $ssh_port)"
1488 else
1489 handle_error $ERROR_SEVERE "SSH服务重启失败"
1490 return 1
1491 fi
1492
1493 log "SSH加固完成"
1494}
1495
1496# ============================================================================
1497# 系统加固
1498# ============================================================================
1499
1500harden_users() {
1501 log_section "用户和权限加固"
1502 configure_password_policy
1503
1504 log_info "锁定系统账户..."
1505 local system_users=("bin" "daemon" "adm" "lp" "sync" "shutdown" "halt" "mail" "news" "uucp" "operator" "games" "gopher" "ftp")
1506
1507 for user in "${system_users[@]}"; do
1508 if id "$user" &>/dev/null 2>&1; then
1509 usermod -L -s /usr/sbin/nologin "$user" 2>/dev/null || true
1510 fi
1511 done
1512
1513 log "用户加固完成"
1514}
1515
1516disable_services() {
1517 log_section "禁用不必要的服务"
1518 local services_to_disable=("avahi-daemon" "cups" "bluetooth")
1519
1520 for service in "${services_to_disable[@]}"; do
1521 if command -v systemctl &> /dev/null; then
1522 if systemctl is-enabled "$service" &>/dev/null 2>&1; then
1523 if confirm_action "是否禁用服务: $service"; then
1524 disable_service "$service"
1525 record_rollback_action "service" "$service" "systemctl enable $service; systemctl start $service"
1526 log_info "已禁用: $service"
1527 fi
1528 fi
1529 fi
1530 done
1531}
1532
1533harden_kernel() {
1534 log_section "内核参数安全配置"
1535 local sysctl_conf="/etc/sysctl.d/99-security.conf"
1536 backup_file "$sysctl_conf" 2>/dev/null || true
1537
1538 log_info "配置内核安全参数..."
1539
1540 cat > "$sysctl_conf" << 'EOF'
1541# IP转发禁用
1542net.ipv4.ip_forward = 0
1543net.ipv6.conf.all.forwarding = 0
1544
1545# SYN cookies保护
1546net.ipv4.tcp_syncookies = 1
1547
1548# 忽略ICMP重定向
1549net.ipv4.conf.all.accept_redirects = 0
1550net.ipv6.conf.all.accept_redirects = 0
1551net.ipv4.conf.default.accept_redirects = 0
1552net.ipv6.conf.default.accept_redirects = 0
1553
1554# 禁用源路由
1555net.ipv4.conf.all.accept_source_route = 0
1556net.ipv6.conf.all.accept_source_route = 0
1557
1558# 记录可疑包
1559net.ipv4.conf.all.log_martians = 1
1560net.ipv4.conf.default.log_martians = 1
1561
1562# 忽略ICMP ping请求
1563net.ipv4.icmp_echo_ignore_broadcasts = 1
1564
1565# 反向路径过滤
1566net.ipv4.conf.all.rp_filter = 1
1567net.ipv4.conf.default.rp_filter = 1
1568
1569# SYN flood保护
1570net.ipv4.tcp_max_syn_backlog = 2048
1571net.ipv4.tcp_synack_retries = 2
1572net.ipv4.tcp_syn_retries = 5
1573EOF
1574
1575 if command -v sysctl &> /dev/null; then
1576 sysctl -p "$sysctl_conf" 2>&1 | tee -a "$LOG_FILE" || log_warning "应用内核参数失败"
1577 fi
1578
1579 log "内核参数配置完成"
1580}
1581
1582harden_filesystem() {
1583 log_section "文件系统权限加固"
1584 log_info "设置重要文件权限..."
1585
1586 local files_to_protect=(
1587 "/etc/ssh/sshd_config:600"
1588 "/etc/passwd:644"
1589 "/etc/shadow:640"
1590 "/etc/group:644"
1591 "/etc/gshadow:600"
1592 )
1593
1594 for file_perm in "${files_to_protect[@]}"; do
1595 local file="${file_perm%:*}"
1596 local perm="${file_perm#*:}"
1597 if [[ -f "$file" ]]; then
1598 chmod "$perm" "$file" 2>&1 | tee -a "$LOG_FILE"
1599 record_rollback_action "chmod" "$file" "chmod 644 $file"
1600 fi
1601 done
1602
1603 log_info "SUID/SGID文件检查..."
1604 if command -v find &> /dev/null; then
1605 find / -perm /6000 -type f 2>/dev/null >> "$LOG_FILE" || true
1606 fi
1607}
1608
1609collect_system_info() {
1610 log_section "收集系统信息"
1611 log_info "操作系统: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 || echo "Unknown")"
1612 log_info "内核版本: $(uname -r)"
1613 log_info "主机名: $(get_hostname)"
1614 log_info "IP地址: $(get_ip_address)"
1615}
1616
1617update_system() {
1618 log_section "系统更新"
1619
1620 if confirm_action "是否执行系统更新?"; then
1621 case $PACKAGE_MANAGER in
1622 apt)
1623 apt update -y 2>&1 | tee -a "$LOG_FILE"
1624 apt upgrade -y 2>&1 | tee -a "$LOG_FILE"
1625 apt autoremove -y 2>&1 | tee -a "$LOG_FILE"
1626 ;;
1627 pacman)
1628 pacman -Syu --noconfirm 2>&1 | tee -a "$LOG_FILE"
1629 pacman -Rns $(pacman -Qdtq) --noconfirm 2>/dev/null || true
1630 ;;
1631 esac
1632 log "系统更新完成"
1633 else
1634 log_warning "跳过系统更新"
1635 fi
1636}
1637
1638generate_report() {
1639 log_section "生成安全加固报告"
1640
1641 local os_info=$(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 || echo "Unknown")
1642 local kernel_info=$(uname -r)
1643 local hostname_info=$(get_hostname)
1644
1645 cat > "$REPORT_FILE" << EOF
1646================================================================================
1647服务器安全加固报告
1648================================================================================
1649生成时间: $(date)
1650主机名: $hostname_info
1651操作系统: $os_info
1652内核版本: $kernel_info
1653包管理器: $PACKAGE_MANAGER
1654
1655备份目录: $BACKUP_DIR
1656回滚目录: $ROLLBACK_DIR
1657日志文件: $LOG_FILE
1658
1659--------------------------------------------------------------------------------
16601. SSH配置
1661--------------------------------------------------------------------------------
1662$(grep -E "^(Port|PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config 2>/dev/null || echo "N/A")
1663
1664--------------------------------------------------------------------------------
16652. 防火墙状态
1666--------------------------------------------------------------------------------
1667$(case $PACKAGE_MANAGER in
1668 apt) ufw status verbose 2>/dev/null ;;
1669 pacman)
1670 if command -v nft &> /dev/null; then nft list ruleset 2>/dev/null;
1671 else iptables -L -n 2>/dev/null; fi
1672 esac || echo "N/A")
1673
1674--------------------------------------------------------------------------------
16753. 入侵防御系统
1676--------------------------------------------------------------------------------
1677$(command -v fail2ban-client &> /dev/null && fail2ban-client status 2>/dev/null || echo "N/A")
1678
1679--------------------------------------------------------------------------------
16804. 已安装安全工具
1681--------------------------------------------------------------------------------
1682$(case $PACKAGE_MANAGER in
1683 apt) dpkg -l 2>/dev/null | grep -E "fail2ban|ufw|auditd" | awk '{print $2 " " $3}' ;;
1684 pacman) pacman -Q 2>/dev/null | grep -E "fail2ban|crowdsec|nftables|auditd" | head -10 ;;
1685 esac || echo "N/A")
1686
1687--------------------------------------------------------------------------------
16885. AUR助手状态
1689--------------------------------------------------------------------------------
1690$(command -v yay &> /dev/null && echo "yay: 已安装" || echo "yay: 未安装")
1691$(command -v paru &> /dev/null && echo "paru: 已安装" || echo "paru: 未安装")
1692
1693================================================================================
1694EOF
1695
1696 if command -v sha256sum &> /dev/null; then
1697 sha256sum "$REPORT_FILE" > "${REPORT_FILE}.sha256"
1698 fi
1699
1700 log_info "报告已生成: $REPORT_FILE"
1701}
1702
1703# ============================================================================
1704# 主程序
1705# ============================================================================
1706
1707main() {
1708 clear
1709
1710 echo -e "${CYAN}"
1711 cat << "EOF"
1712╔══════════════════════════════════════════════════════════════╗
1713║ 服务器安全加固脚本 (多发行版增强版)
1714║ v4.2 - 支持 Ubuntu + Arch Linux ║
1715║ • 多防火墙选择 (UFW/iptables/nftables)
1716║ • 多入侵防护 (Fail2ban/Sshguard/Crowdsec)
1717║ • AUR助手自动安装 (yay/paru)
1718║ • ED25519 SSH密钥 (替代RSA)
1719║ • 支持 -y 参数用于非交互模式 ║
1720║ • 依赖自动检查 ║
1721╚══════════════════════════════════════════════════════════════╝
1722EOF
1723 echo -e "${NC}"
1724
1725 check_root
1726 detect_distribution
1727 check_dependencies
1728 setup_colors
1729 init_rollback
1730
1731 log "开始服务器安全加固..."
1732 log_info "日志: $LOG_FILE | 备份: $BACKUP_DIR"
1733
1734 echo -e "${YELLOW}警告: 此脚本将修改系统配置${NC}"
1735
1736 if ! confirm_action "确认继续?"; then
1737 if [[ "$FORCE_YES" == "true" ]]; then
1738 log_info "自动模式: 继续执行加固操作"
1739 else
1740 log "用户取消"
1741 exit 0
1742 fi
1743 fi
1744
1745 collect_system_info
1746 update_system
1747 harden_ssh
1748 configure_firewall
1749 install_intrusion_prevention
1750 harden_users
1751 disable_services
1752 harden_kernel
1753 harden_filesystem
1754 configure_auto_updates
1755 install_security_tools
1756 generate_report
1757
1758 log_section "安全加固完成"
1759
1760 echo -e "${GREEN}"
1761 cat << EOF
1762╔══════════════════════════════════════════════════════════════╗
1763║ 安全加固已完成! ║
1764╚══════════════════════════════════════════════════════════════╝
1765
1766重要提醒:
1767• 备份: $BACKUP_DIR
1768• 回滚: $ROLLBACK_DIR
1769• 日志: $LOG_FILE
1770• 报告: $REPORT_FILE
1771• 建议重启服务器
1772
1773下一步:
1774• 测试SSH登录
1775• 检查防火墙规则
1776• 配置入侵防御
1777
1778EOF
1779 echo -e "${NC}"
1780
1781 if confirm_action "是否重启服务器?"; then
1782 log "5秒后重启..."
1783 sleep 5
1784 reboot
1785 fi
1786}
1787
1788main "$@"
1789