#!/bin/bash
# ============================================
# Linux系统安全加固与审计脚本
# 功能:自动化安全检查和系统加固
# 使用方法:sudo ./security-audit.sh [选项]
## 保存脚本
## sudo nano /usr/local/bin/security-audit.sh
## 赋予执行权限
## sudo chmod +x /usr/local/bin/security-audit.sh
## 运行交互式菜单
## sudo security-audit.sh
## 或直接运行完整审计
## sudo security-audit.sh --audit
# ============================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# 配置
REPORT_FILE="/var/log/security-audit-$(date +%Y%m%d).report"
LOG_FILE="/var/log/security-audit.log"
BACKUP_DIR="/root/security-backup-$(date +%Y%m%d)"
AUDIT_SCORE=0
MAX_SCORE=100
CHECK_COUNT=0
PASS_COUNT=0
FAIL_COUNT=0
WARN_COUNT=0
# 函数:打印带颜色的消息
print_color() {
local color=$1
local msg=$2
echo -e "${color}${msg}${NC}"
}
# 函数:记录日志
log_message() {
local message=$1
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" >> "$LOG_FILE"
}
# 函数:打印检查结果
print_result() {
local level=$1
local check_name=$2
local status=$3
local message=$4
CHECK_COUNT=$((CHECK_COUNT + 1))
case $status in
"PASS")
PASS_COUNT=$((PASS_COUNT + 1))
AUDIT_SCORE=$((AUDIT_SCORE + 2))
printf "[${GREEN}✓${NC}] %-50s ${GREEN}通过${NC}\n" "$check_name"
log_message "PASS - $check_name: $message"
;;
"FAIL")
FAIL_COUNT=$((FAIL_COUNT + 1))
printf "[${RED}✗${NC}] %-50s ${RED}失败${NC}\n" "$check_name"
printf " ${YELLOW}建议: $message${NC}"
log_message "FAIL - $check_name: $message"
;;
"WARN")
WARN_COUNT=$((WARN_COUNT + 1))
AUDIT_SCORE=$((AUDIT_SCORE + 1))
printf "[${YELLOW}!${NC}] %-50s ${YELLOW}警告${NC}\n" "$check_name"
printf " ${CYAN}信息: $message${NC}"
log_message "WARN - $check_name: $message"
;;
"INFO")
printf "[${BLUE}i${NC}] %-50s ${BLUE}信息${NC}\n" "$check_name"
printf " ${CYAN}详情: $message${NC}"
log_message "INFO - $check_name: $message"
;;
esac
}
# 函数:生成报告头部
report_header() {
cat > "$REPORT_FILE" << EOF ============================================ Linux系统安全审计报告 生成时间: $(date) 主机名: $(hostname) 操作系统: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2 2>/dev/null || uname -o)
内核版本: $(uname -r)
============================================
EOF
log_message "生成审计报告头部"
}
# 函数:添加报告内容
add_report() {
local section=$1
local content=$2
echo -e "\n=== $section ===" >> "$REPORT_FILE"
echo "$content" >> "$REPORT_FILE"
}
# 函数:显示进度条
show_progress() {
local current=$1
local total=$2
local width=50
local percent=$((current * 100 / total))
local filled=$((current * width / total))
local empty=$((width - filled))
printf "\r["
printf "%${filled}s" | tr " " "="
printf "%${empty}s" | tr " " " "
printf "] %3d%%" "$percent"
}
# 函数:显示标题
show_section() {
local title=$1
echo ""
print_color "$PURPLE" "┌──────────────────────────────────────────────────────┐"
print_color "$PURPLE" "│ $(printf "%-52s" "$title") │"
print_color "$PURPLE" "└──────────────────────────────────────────────────────┘"
}
# 函数:检查是否为root用户
check_root() {
if [ "$EUID" -ne 0 ]; then
print_color "$RED" "错误:此脚本需要root权限运行!"
print_color "$CYAN" "请使用: sudo $0"
exit 1
fi
}
# 函数:备份配置文件
backup_config() {
local file=$1
if [ -f "$file" ]; then
mkdir -p "$BACKUP_DIR"
cp "$file" "$BACKUP_DIR/" 2>/dev/null
if [ $? -eq 0 ]; then
print_color "$CYAN" "已备份: $file -> $BACKUP_DIR/"
else
print_color "$YELLOW" "备份失败: $file (可能权限不足)"
fi
fi
}
# 函数:暂停等待
pause() {
echo ""
print_color "$CYAN" "按回车键继续..."
read -n 1
}
# ==================== 安全检查模块 ====================
# 1. 检查SSH安全配置
check_ssh_security() {
show_section "SSH服务安全检查"
local ssh_config="/etc/ssh/sshd_config"
if [ -f "$ssh_config" ]; then
backup_config "$ssh_config"
# 检查PermitRootLogin
if grep -q "^PermitRootLogin no" "$ssh_config" || grep -q "^#PermitRootLogin no" "$ssh_config"; then
print_result "HIGH" "SSH禁止root登录" "PASS" "已禁止root通过SSH登录"
else
print_result "HIGH" "SSH禁止root登录" "FAIL" "建议设置 PermitRootLogin no"
fi
# 检查密码认证
if grep -q "^PasswordAuthentication no" "$ssh_config"; then
print_result "MEDIUM" "SSH密码认证" "PASS" "已禁用密码认证"
elif grep -q "^#PasswordAuthentication no" "$ssh_config"; then
print_result "MEDIUM" "SSH密码认证" "WARN" "考虑禁用密码认证,使用密钥"
else
print_result "MEDIUM" "SSH密码认证" "FAIL" "建议禁用密码认证"
fi
# 检查空闲超时
if grep -q "^ClientAliveInterval 300" "$ssh_config" && grep -q "^ClientAliveCountMax 3" "$ssh_config"; then
print_result "LOW" "SSH连接超时" "PASS" "已设置连接超时"
else
print_result "LOW" "SSH连接超时" "WARN" "建议设置 ClientAliveInterval 300 和 ClientAliveCountMax 3"
fi
# 检查端口
local ssh_port=$(grep "^Port" "$ssh_config" | awk '{print $2}' | head -1)
if [ "$ssh_port" = "22" ] || [ -z "$ssh_port" ]; then
print_result "MEDIUM" "SSH默认端口" "WARN" "考虑修改默认SSH端口"
else
print_result "MEDIUM" "SSH默认端口" "PASS" "已修改默认端口: $ssh_port"
fi
# 检查协议版本
if grep -q "^Protocol 2" "$ssh_config"; then
print_result "HIGH" "SSH协议版本" "PASS" "已使用SSH协议版本2"
else
print_result "HIGH" "SSH协议版本" "FAIL" "必须使用SSH协议版本2"
fi
# 检查失败登录限制
if grep -q "^MaxAuthTries 3" "$ssh_config"; then
print_result "MEDIUM" "SSH登录尝试次数" "PASS" "已限制登录尝试次数"
else
print_result "MEDIUM" "SSH登录尝试次数" "WARN" "建议设置 MaxAuthTries 3"
fi
else
print_result "HIGH" "SSH配置文件" "WARN" "SSH配置文件不存在"
fi
}
# 2. 检查防火墙配置
check_firewall() {
show_section "防火墙安全检查"
# 检查iptables
if command -v iptables &> /dev/null; then
local iptables_rules=$(iptables -L -n 2>/dev/null | grep -c "^ACCEPT")
if [ $iptables_rules -gt 0 ]; then
print_result "HIGH" "iptables防火墙" "PASS" "iptables规则已配置"
# 检查默认策略
local input_policy=$(iptables -L INPUT -n 2>/dev/null | grep "policy" | awk '{print $4}')
local forward_policy=$(iptables -L FORWARD -n 2>/dev/null | grep "policy" | awk '{print $4}')
if [ "$input_policy" = "DROP" ] || [ "$input_policy" = "REJECT" ]; then
print_result "HIGH" "INPUT链默认策略" "PASS" "INPUT策略: $input_policy"
else
print_result "HIGH" "INPUT链默认策略" "FAIL" "建议设置INPUT链为DROP"
fi
else
print_result "HIGH" "iptables防火墙" "FAIL" "未配置iptables规则"
fi
fi
# 检查firewalld
if command -v systemctl &> /dev/null && systemctl is-active firewalld &> /dev/null; then
print_result "MEDIUM" "firewalld防火墙" "PASS" "firewalld正在运行"
if command -v firewall-cmd &> /dev/null; then
local firewalld_zones=$(firewall-cmd --get-active-zones 2>/dev/null | wc -l)
if [ $firewalld_zones -gt 0 ]; then
print_result "MEDIUM" "firewalld区域" "PASS" "已配置防火墙区域"
fi
fi
fi
# 检查UFW
if command -v ufw &> /dev/null; then
local ufw_status=$(ufw status 2>/dev/null | grep -i "active")
if [ -n "$ufw_status" ]; then
print_result "MEDIUM" "UFW防火墙" "PASS" "UFW已启用"
else
print_result "MEDIUM" "UFW防火墙" "WARN" "UFW已安装但未启用"
fi
fi
}
# 3. 检查密码策略
check_password_policy() {
show_section "密码策略检查"
local login_defs="/etc/login.defs"
local common_auth="/etc/pam.d/common-auth"
local common_password="/etc/pam.d/common-password"
if [ -f "$login_defs" ]; then
# 检查密码最大天数
local pass_max_days=$(grep "^PASS_MAX_DAYS" "$login_defs" | awk '{print $2}')
if [ -n "$pass_max_days" ] && [ "$pass_max_days" -le 90 ]; then
print_result "MEDIUM" "密码最大有效期" "PASS" "密码有效期: $pass_max_days 天"
else
print_result "MEDIUM" "密码最大有效期" "FAIL" "建议设置密码有效期不超过90天"
fi
# 检查密码最小天数
local pass_min_days=$(grep "^PASS_MIN_DAYS" "$login_defs" | awk '{print $2}')
if [ -n "$pass_min_days" ] && [ "$pass_min_days" -ge 1 ]; then
print_result "LOW" "密码最小修改间隔" "PASS" "最小修改间隔: $pass_min_days 天"
else
print_result "LOW" "密码最小修改间隔" "WARN" "建议设置密码最小修改间隔为1天"
fi
# 检查密码警告天数
local pass_warn_age=$(grep "^PASS_WARN_AGE" "$login_defs" | awk '{print $2}')
if [ -n "$pass_warn_age" ] && [ "$pass_warn_age" -ge 7 ]; then
print_result "LOW" "密码过期警告" "PASS" "过期前警告: $pass_warn_age 天"
else
print_result "LOW" "密码过期警告" "WARN" "建议设置密码过期前7天警告"
fi
fi
# 检查PAM密码复杂度
if [ -f "$common_password" ]; then
if grep -q "pam_pwquality.so" "$common_password"; then
print_result "HIGH" "密码复杂度检查" "PASS" "已启用密码复杂度检查"
# 检查具体复杂度设置
if grep -q "minlen=12" "$common_password" || grep -q "minlen=14" "$common_password"; then
print_result "HIGH" "密码最小长度" "PASS" "密码最小长度12+字符"
else
print_result "HIGH" "密码最小长度" "WARN" "建议密码最小长度12字符"
fi
else
print_result "HIGH" "密码复杂度检查" "FAIL" "未启用密码复杂度检查"
fi
fi
# 检查失败登录锁定
if [ -f "$common_auth" ]; then
if grep -q "pam_tally2.so" "$common_auth" || grep -q "pam_faillock.so" "$common_auth"; then
print_result "HIGH" "失败登录锁定" "PASS" "已启用失败登录锁定"
else
print_result "HIGH" "失败登录锁定" "WARN" "建议启用失败登录锁定机制"
fi
fi
}
# 4. 检查用户和权限
check_users_permissions() {
show_section "用户和权限检查"
# 检查空密码账户
local empty_passwords=$(awk -F: '($2 == "" ) {print $1}' /etc/shadow 2>/dev/null)
if [ -z "$empty_passwords" ]; then
print_result "CRITICAL" "空密码账户" "PASS" "没有空密码账户"
else
print_result "CRITICAL" "空密码账户" "FAIL" "发现空密码账户: $empty_passwords"
fi
# 检查UID为0的用户
local uid0_users=$(awk -F: '($3 == 0) {print $1}' /etc/passwd)
local uid0_count=$(echo "$uid0_users" | wc -l)
if [ "$uid0_count" -eq 1 ] && echo "$uid0_users" | grep -q "^root$"; then
print_result "CRITICAL" "UID 0用户检查" "PASS" "只有root用户UID为0"
else
print_result "CRITICAL" "UID 0用户检查" "FAIL" "多个用户UID为0: $uid0_users"
fi
# 检查sudo权限
local sudo_users=$(grep -E "^[^#].*ALL.*NOPASSWD" /etc/sudoers /etc/sudoers.d/* 2>/dev/null | wc -l)
if [ "$sudo_users" -eq 0 ]; then
print_result "HIGH" "无密码sudo" "PASS" "没有配置无密码sudo"
else
print_result "HIGH" "无密码sudo" "WARN" "发现无密码sudo配置,建议审查"
fi
# 检查登录shell
local valid_shells="/bin/bash|/bin/sh|/bin/zsh|/bin/tcsh|/bin/csh"
local invalid_shell_users=$(awk -F: -v shells="$valid_shells" '$7 !~ shells && $7 != "/usr/sbin/nologin" && $7 != "/bin/false" && $7 != "/sbin/nologin" {print $1":"$7}' /etc/passwd 2>/dev/null)
if [ -z "$invalid_shell_users" ]; then
print_result "MEDIUM" "无效登录shell" "PASS" "没有无效的登录shell"
else
print_result "MEDIUM" "无效登录shell" "WARN" "发现无效登录shell: $invalid_shell_users"
fi
# 检查umask设置
local umask_global=$(grep -r "^umask" /etc/profile /etc/bash.bashrc /etc/profile.d/* 2>/dev/null | head -1)
if echo "$umask_global" | grep -q "022\|027"; then
print_result "MEDIUM" "全局umask设置" "PASS" "全局umask设置正确"
else
print_result "MEDIUM" "全局umask设置" "WARN" "建议设置全局umask为022或027"
fi
}
# 5. 检查文件系统安全
check_filesystem_security() {
show_section "文件系统安全检查"
# 检查关键目录权限
local critical_dirs=(
"/etc/passwd:644:root:root"
"/etc/shadow:640:root:shadow"
"/etc/group:644:root:root"
"/etc/sudoers:440:root:root"
"/etc/ssh/sshd_config:600:root:root"
"/root:700:root:root"
"/etc/crontab:644:root:root"
)
for dir_info in "${critical_dirs[@]}"; do
IFS=':' read -r file expected_mode expected_owner expected_group <<< "$dir_info" if [ -e "$file" ]; then local actual_mode=$(stat -c "%a" "$file" 2>/dev/null)
local actual_owner=$(stat -c "%U" "$file" 2>/dev/null)
local actual_group=$(stat -c "%G" "$file" 2>/dev/null)
if [ "$actual_mode" = "$expected_mode" ] && [ "$actual_owner" = "$expected_owner" ] && [ "$actual_group" = "$expected_group" ]; then
print_result "HIGH" "文件权限: $file" "PASS" "权限正确"
else
print_result "HIGH" "文件权限: $file" "FAIL" "当前: $actual_mode $actual_owner:$actual_group, 期望: $expected_mode $expected_owner:$expected_group"
fi
fi
done
# 检查SUID/SGID文件
local suid_files=$(find / -xdev -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | head -20)
local suid_count=$(echo "$suid_files" | wc -l)
if [ "$suid_count" -lt 50 ]; then
print_result "MEDIUM" "SUID/SGID文件检查" "PASS" "发现 $suid_count 个SUID/SGID文件"
else
print_result "MEDIUM" "SUID/SGID文件检查" "WARN" "发现较多SUID/SGID文件 ($suid_count),建议审查"
fi
# 检查world-writable文件
local world_writable=$(find / -xdev -type f -perm -0002 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -20)
local ww_count=$(echo "$world_writable" | wc -l)
if [ "$ww_count" -eq 0 ]; then
print_result "HIGH" "全局可写文件" "PASS" "未发现全局可写文件"
else
print_result "HIGH" "全局可写文件" "FAIL" "发现 $ww_count 个全局可写文件,建议审查"
fi
# 检查未授权文件
local no_owner_files=$(find / -xdev -nouser -o -nogroup 2>/dev/null | head -10)
if [ -z "$no_owner_files" ]; then
print_result "MEDIUM" "无属主文件" "PASS" "未发现无属主文件"
else
print_result "MEDIUM" "无属主文件" "WARN" "发现无属主文件,建议清理"
fi
}
# 6. 检查服务安全
check_services_security() {
show_section "服务安全检查"
# 检查不必要的服务
local dangerous_services=(
"telnet" "rsh" "rlogin" "rexec" "ypbind" "ypserv"
"tftp" "chargen" "daytime" "echo" "discard"
"vsftpd" "proftpd" "pure-ftpd"
)
for service in "${dangerous_services[@]}"; do
if systemctl is-enabled "$service" 2>/dev/null | grep -q "enabled"; then
print_result "HIGH" "危险服务: $service" "FAIL" "发现危险服务启用"
elif netstat -tulpn 2>/dev/null | grep -q "$service"; then
print_result "HIGH" "危险服务: $service" "WARN" "发现危险服务运行"
fi
done
# 检查网络服务
local listening_services=$(netstat -tulpn 2>/dev/null | grep "LISTEN" | awk '{print $4, $7}' | head -15)
if [ -n "$listening_services" ]; then
print_result "MEDIUM" "网络监听服务" "INFO" "当前监听服务:\n$listening_services"
fi
# 检查自动启动服务
if command -v systemctl &> /dev/null; then
local enabled_services=$(systemctl list-unit-files --state=enabled 2>/dev/null | grep -E "\.service" | wc -l)
if [ "$enabled_services" -lt 50 ]; then
print_result "LOW" "自动启动服务数量" "PASS" "启用服务数量: $enabled_services"
else
print_result "LOW" "自动启动服务数量" "WARN" "启用服务较多 ($enabled_services),建议优化"
fi
fi
}
# 7. 检查日志配置
check_logging_config() {
show_section "日志配置检查"
# 检查rsyslog
if systemctl is-active rsyslog &> /dev/null; then
print_result "MEDIUM" "rsyslog服务" "PASS" "rsyslog正在运行"
# 检查日志转发
if grep -q "@" /etc/rsyslog.conf 2>/dev/null || grep -r "@" /etc/rsyslog.d/ 2>/dev/null; then
print_result "MEDIUM" "日志远程存储" "PASS" "已配置远程日志"
else
print_result "MEDIUM" "日志远程存储" "WARN" "建议配置远程日志存储"
fi
else
print_result "MEDIUM" "rsyslog服务" "WARN" "rsyslog未运行"
fi
# 检查journald
if command -v journalctl &> /dev/null; then
local journal_size=$(grep "^SystemMaxUse=" /etc/systemd/journald.conf 2>/dev/null | cut -d= -f2)
if [ -n "$journal_size" ]; then
print_result "LOW" "journald日志大小" "PASS" "日志大小限制: $journal_size"
else
print_result "LOW" "journald日志大小" "WARN" "建议设置journald日志大小限制"
fi
fi
# 检查日志轮转
if [ -f "/etc/logrotate.conf" ]; then
print_result "LOW" "日志轮转配置" "PASS" "已配置日志轮转"
fi
# 检查auditd
if command -v auditctl &> /dev/null; then
if systemctl is-active auditd &> /dev/null; then
print_result "HIGH" "auditd审计服务" "PASS" "auditd正在运行"
# 检查审计规则
local audit_rules=$(auditctl -l 2>/dev/null | wc -l)
if [ "$audit_rules" -gt 5 ]; then
print_result "HIGH" "审计规则数量" "PASS" "配置了 $audit_rules 条审计规则"
else
print_result "HIGH" "审计规则数量" "WARN" "审计规则较少,建议增加"
fi
else
print_result "HIGH" "auditd审计服务" "WARN" "auditd未运行"
fi
fi
}
# 8. 检查内核安全参数
check_kernel_security() {
show_section "内核安全参数检查"
local sysctl_conf="/etc/sysctl.conf"
local sysctl_files=("/etc/sysctl.d/*.conf")
backup_config "$sysctl_conf"
# 重要内核参数检查
local kernel_params=(
"net.ipv4.ip_forward:0:IP转发"
"net.ipv4.conf.all.accept_redirects:0:接受重定向"
"net.ipv4.conf.all.send_redirects:0:发送重定向"
"net.ipv4.conf.all.accept_source_route:0:源路由"
"net.ipv4.conf.all.rp_filter:1:反向路径过滤"
"net.ipv4.icmp_echo_ignore_broadcasts:1:忽略广播ping"
"net.ipv4.icmp_ignore_bogus_error_responses:1:忽略错误响应"
"net.ipv4.tcp_syncookies:1:SYN cookies"
"net.ipv4.tcp_max_syn_backlog:4096:SYN队列大小"
"kernel.randomize_va_space:2:地址空间随机化"
)
for param_info in "${kernel_params[@]}"; do
IFS=':' read -r param expected_value description <<< "$param_info" local current_value=$(sysctl -n "$param" 2>/dev/null)
if [ -n "$current_value" ]; then
if [ "$current_value" = "$expected_value" ]; then
print_result "HIGH" "内核参数: $description" "PASS" "$param = $current_value"
else
print_result "HIGH" "内核参数: $description" "FAIL" "当前: $current_value, 期望: $expected_value"
fi
else
print_result "MEDIUM" "内核参数: $description" "WARN" "参数未设置"
fi
done
# 检查YAMA配置(ptrace限制)
if [ -f "/proc/sys/kernel/yama/ptrace_scope" ]; then
local ptrace_scope=$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)
if [ "$ptrace_scope" -ge 1 ]; then
print_result "MEDIUM" "ptrace限制" "PASS" "ptrace_scope = $ptrace_scope"
else
print_result "MEDIUM" "ptrace限制" "WARN" "建议设置ptrace_scope为1或更高"
fi
fi
}
# 9. 检查网络安全
check_network_security() {
show_section "网络安全检查"
# 检查IPv6配置
if ip -6 addr show &> /dev/null; then
local ipv6_enabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null)
if [ "$ipv6_enabled" = "1" ]; then
print_result "MEDIUM" "IPv6支持" "PASS" "IPv6已禁用"
else
print_result "MEDIUM" "IPv6支持" "WARN" "IPv6已启用,如不需要建议禁用"
fi
fi
# 检查TCP时间戳
local tcp_timestamps=$(sysctl -n net.ipv4.tcp_timestamps 2>/dev/null)
if [ "$tcp_timestamps" = "0" ]; then
print_result "LOW" "TCP时间戳" "PASS" "TCP时间戳已禁用"
else
print_result "LOW" "TCP时间戳" "INFO" "TCP时间戳已启用"
fi
# 检查SYN flood防护
local tcp_syncookies=$(sysctl -n net.ipv4.tcp_syncookies 2>/dev/null)
if [ "$tcp_syncookies" = "1" ]; then
print_result "MEDIUM" "SYN flood防护" "PASS" "已启用SYN cookies"
fi
# 检查ICMP响应
local icmp_echo=$(sysctl -n net.ipv4.icmp_echo_ignore_all 2>/dev/null)
if [ "$icmp_echo" = "1" ]; then
print_result "LOW" "ICMP响应" "PASS" "已禁用ICMP响应"
fi
}
# 10. 检查恶意软件和Rootkit
check_malware_rootkit() {
show_section "恶意软件和Rootkit检查"
# 检查常见rootkit检测工具
local rootkit_tools=("rkhunter" "chkrootkit" "lynis")
local installed_tools=()
for tool in "${rootkit_tools[@]}"; do
if command -v "$tool" &> /dev/null; then
installed_tools+=("$tool")
fi
done
if [ ${#installed_tools[@]} -gt 0 ]; then
print_result "HIGH" "Rootkit检测工具" "PASS" "已安装: ${installed_tools[*]}"
# 建议运行检测
for tool in "${installed_tools[@]}"; do
case $tool in
"rkhunter")
print_result "INFO" "安全扫描建议" "INFO" "运行: sudo rkhunter --check --skip-keypress"
;;
"chkrootkit")
print_result "INFO" "安全扫描建议" "INFO" "运行: sudo chkrootkit"
;;
"lynis")
print_result "INFO" "安全扫描建议" "INFO" "运行: sudo lynis audit system"
;;
esac
done
else
print_result "HIGH" "Rootkit检测工具" "FAIL" "未安装Rootkit检测工具"
print_result "INFO" "安全工具安装" "INFO" "建议安装: sudo apt install rkhunter chkrootkit lynis"
fi
# 检查可疑进程
local suspicious_procs=$(ps aux 2>/dev/null | grep -E "(nc |telnet |nmap |nessus|metasploit|john |hashcat)" | grep -v grep)
if [ -z "$suspicious_procs" ]; then
print_result "HIGH" "可疑进程检查" "PASS" "未发现可疑进程"
else
print_result "HIGH" "可疑进程检查" "FAIL" "发现可疑进程: $suspicious_procs"
fi
# 检查隐藏文件
local hidden_files=$(find / -name ".*" -type f 2>/dev/null | grep -E "\.(bash_history|ssh|mysql_history)$" | head -10)
if [ -n "$hidden_files" ]; then
print_result "MEDIUM" "敏感隐藏文件" "INFO" "发现敏感隐藏文件"
fi
}
# 11. 检查Docker安全(如果安装)
check_docker_security() {
if command -v docker &> /dev/null; then
show_section "Docker安全配置检查"
# 检查Docker守护进程配置
local docker_config="/etc/docker/daemon.json"
if [ -f "$docker_config" ]; then
print_result "MEDIUM" "Docker配置文件" "PASS" "已配置Docker守护进程"
# 检查是否启用用户命名空间
if grep -q "userns-remap" "$docker_config"; then
print_result "HIGH" "Docker用户命名空间" "PASS" "已启用用户命名空间"
else
print_result "HIGH" "Docker用户命名空间" "WARN" "建议启用用户命名空间"
fi
# 检查是否启用seccomp
if grep -q "seccomp" "$docker_config" && ! grep -q '"seccomp": "unconfined"' "$docker_config"; then
print_result "HIGH" "Docker seccomp配置" "PASS" "已启用seccomp"
else
print_result "HIGH" "Docker seccomp配置" "WARN" "建议启用seccomp"
fi
else
print_result "MEDIUM" "Docker配置文件" "WARN" "未找到Docker配置文件"
fi
# 检查容器运行状态
local running_containers=$(docker ps -q 2>/dev/null | wc -l)
if [ "$running_containers" -gt 0 ]; then
print_result "MEDIUM" "运行中的容器" "INFO" "有 $running_containers 个容器正在运行"
fi
# 检查特权容器
local privileged_containers=$(docker ps --filter "ancestor=privileged" -q 2>/dev/null | wc -l)
if [ "$privileged_containers" -eq 0 ]; then
print_result "HIGH" "特权容器检查" "PASS" "未发现特权容器"
else
print_result "HIGH" "特权容器检查" "FAIL" "发现特权容器,建议审查"
fi
fi
}
# 12. 检查Cron作业和定时任务
check_cron_jobs() {
show_section "Cron作业检查"
# 检查系统cron
local cron_files=("/etc/crontab" "/etc/cron.d/*" "/etc/cron.hourly/*" "/etc/cron.daily/*" "/etc/cron.weekly/*" "/etc/cron.monthly/*")
local suspicious_cron=()
for file in ${cron_files[@]}; do
if [ -f "$file" ]; then
local file_perm=$(stat -c "%a" "$file" 2>/dev/null)
local file_owner=$(stat -c "%U" "$file" 2>/dev/null)
if [ "$file_owner" != "root" ] || [ "$file_perm" -gt "644" ]; then
suspicious_cron+=("$file (权限: $file_perm, 属主: $file_owner)")
fi
fi
done
if [ ${#suspicious_cron[@]} -eq 0 ]; then
print_result "HIGH" "系统cron作业" "PASS" "系统cron配置正常"
else
print_result "HIGH" "系统cron作业" "FAIL" "发现可疑cron配置: ${suspicious_cron[*]}"
fi
# 检查用户cron
local users_with_cron=$(cut -d: -f1 /etc/passwd)
for user in $users_with_cron; do
local user_cron=$(crontab -l -u "$user" 2>/dev/null)
if [ -n "$user_cron" ]; then
print_result "MEDIUM" "用户cron作业: $user" "INFO" "用户 $user 有cron作业"
fi
done
}
# 13. 生成安全加固建议
generate_hardening_suggestions() {
show_section "安全加固建议"
local suggestions=()
# 收集失败和建议项
if [ $FAIL_COUNT -gt 0 ]; then
suggestions+=("发现 $FAIL_COUNT 个严重问题,建议立即修复")
fi
if [ $WARN_COUNT -gt 0 ]; then
suggestions+=("发现 $WARN_COUNT 个警告项,建议尽快处理")
fi
# 具体建议
if ! command -v fail2ban &> /dev/null; then
suggestions+=("安装fail2ban防止暴力破解: sudo apt install fail2ban")
fi
if ! grep -q "pam_tally2.so" /etc/pam.d/common-auth 2>/dev/null; then
suggestions+=("配置登录失败锁定: 在/etc/pam.d/common-auth添加 pam_tally2.so")
fi
if ! sysctl -n net.ipv4.tcp_syncookies 2>/dev/null | grep -q "1"; then
suggestions+=("启用SYN cookies防护: echo 'net.ipv4.tcp_syncookies = 1' >> /etc/sysctl.conf")
fi
if [ ! -f "/etc/ssh/sshd_config.d/99-hardening.conf" ]; then
suggestions+=("创建SSH加固配置: /etc/ssh/sshd_config.d/99-hardening.conf")
fi
# 显示建议
if [ ${#suggestions[@]} -eq 0 ]; then
print_result "INFO" "安全状况" "PASS" "系统安全状况良好"
else
for ((i=0; i<${#suggestions[@]}; i++)); do print_result "INFO" "建议 $((i+1))" "INFO" "${suggestions[$i]}" done fi } # 14. 生成审计报告 generate_audit_report() { show_section "审计报告生成" # 计算安全评分 local total_possible=$((CHECK_COUNT * 2)) local security_score=0 if [ $total_possible -gt 0 ]; then security_score=$((AUDIT_SCORE * 100 / total_possible)) fi print_color "$CYAN" "正在生成详细审计报告..." # 报告摘要 { echo "安全审计报告摘要" echo "==================" echo "审计时间: $(date)" echo "主机名: $(hostname)" echo "总检查项: $CHECK_COUNT" echo "通过: $PASS_COUNT" echo "失败: $FAIL_COUNT" echo "警告: $WARN_COUNT" echo "安全评分: ${security_score}/100" echo "" if [ "$security_score" -ge 80 ]; then echo "安全评级: 优秀" elif [ "$security_score" -ge 60 ]; then echo "安全评级: 良好" elif [ "$security_score" -ge 40 ]; then echo "安全评级: 一般" else echo "安全评级: 危险" fi echo "" echo "关键问题汇总:" echo "-------------" grep "FAIL" "$LOG_FILE" | tail -10 echo "" echo "加固建议:" echo "---------" echo "1. 立即修复所有FAIL级别的问题" echo "2. 审查并处理WARN级别的问题" echo "3. 定期运行此审计脚本" echo "4. 启用系统自动更新" echo "5. 配置定期安全扫描" } > "$REPORT_FILE"
print_result "INFO" "报告生成" "PASS" "审计报告已保存到: $REPORT_FILE"
print_result "INFO" "备份文件" "INFO" "配置文件备份在: $BACKUP_DIR"
# 显示报告位置
echo ""
print_color "$PURPLE" "================================================"
print_color "$GREEN" "✅ 安全审计完成!"
print_color "$CYAN" "📋 详细报告: $REPORT_FILE"
print_color "$CYAN" "📝 操作日志: $LOG_FILE"
print_color "$CYAN" "💾 配置备份: $BACKUP_DIR"
print_color "$CYAN" "📊 安全评分: $security_score/100"
if [ "$security_score" -lt 60 ]; then
print_color "$RED" "⚠️ 警告:系统存在严重安全问题,建议立即修复!"
fi
print_color "$PURPLE" "================================================"
}
# 主函数:运行所有安全检查
run_security_audit() {
print_color "$BLUE" "🔒 Linux系统安全审计与加固脚本"
print_color "$CYAN" "开始时间: $(date)"
print_color "$PURPLE" "================================================"
# 检查root权限
check_root
# 创建日志和报告文件
touch "$LOG_FILE"
report_header
# 备份重要配置文件
mkdir -p "$BACKUP_DIR"
# 执行所有安全检查
local checks=(
check_ssh_security
check_firewall
check_password_policy
check_users_permissions
check_filesystem_security
check_services_security
check_logging_config
check_kernel_security
check_network_security
check_malware_rootkit
check_docker_security
check_cron_jobs
)
local total_checks=${#checks[@]}
local current_check=0
for check_func in "${checks[@]}"; do
current_check=$((current_check + 1))
show_progress $current_check $total_checks
$check_func
sleep 0.5 # 短暂延迟,让用户看到进度
done
echo "" # 换行
# 生成建议和报告
generate_hardening_suggestions
generate_audit_report
log_message "审计完成 - 总检查: $CHECK_COUNT, 通过: $PASS_COUNT, 失败: $FAIL_COUNT, 警告: $WARN_COUNT"
}
# 交互式菜单
show_menu() {
while true; do
clear
print_color "$PURPLE" "┌──────────────────────────────────────────────────────┐"
print_color "$PURPLE" "│ Linux安全审计与加固工具 │"
print_color "$PURPLE" "└──────────────────────────────────────────────────────┘"
echo ""
print_color "$CYAN" "1. 运行完整安全审计"
print_color "$CYAN" "2. 仅运行SSH安全配置检查"
print_color "$CYAN" "3. 仅运行防火墙配置检查"
print_color "$CYAN" "4. 仅运行密码策略检查"
print_color "$CYAN" "5. 仅运行文件权限检查"
print_color "$CYAN" "6. 查看最近审计报告"
print_color "$CYAN" "7. 应用基本安全加固"
print_color "$CYAN" "8. 查看系统安全状态"
print_color "$CYAN" "9. 退出"
echo ""
print_color "$YELLOW" "选择操作 [1-9]: "
read -n 1 choice
echo ""
case $choice in
1)
run_security_audit
pause
;;
2)
show_section "SSH安全配置检查"
check_ssh_security
pause
;;
3)
show_section "防火墙配置检查"
check_firewall
pause
;;
4)
show_section "密码策略检查"
check_password_policy
pause
;;
5)
show_section "文件权限检查"
check_filesystem_security
pause
;;
6)
if [ -f "$REPORT_FILE" ]; then
less "$REPORT_FILE"
else
print_color "$RED" "未找到审计报告"
sleep 2
fi
;;
7)
apply_basic_hardening
;;
8)
show_system_security_status
;;
9)
print_color "$GREEN" "感谢使用安全审计工具!"
exit 0
;;
*)
print_color "$RED" "无效选择"
sleep 1
;;
esac
done
}
# 应用基本安全加固
apply_basic_hardening() {
show_section "应用基本安全加固"
print_color "$RED" "警告:此操作将修改系统配置!"
read -p "确定要继续吗?(y/N): " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
print_color "$YELLOW" "操作已取消"
return
fi
# 备份当前配置
mkdir -p "$BACKUP_DIR"
# 1. 加固SSH
print_color "$CYAN" "加固SSH配置..."
backup_config "/etc/ssh/sshd_config"
# 禁用root登录
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config 2>/dev/null
# 禁用密码认证
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config 2>/dev/null
# 使用SSH协议2
sed -i 's/^#*Protocol.*/Protocol 2/' /etc/ssh/sshd_config 2>/dev/null
# 2. 配置防火墙基本规则
print_color "$CYAN" "配置防火墙..."
if command -v ufw &> /dev/null; then
ufw --force enable
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw reload
fi
# 3. 配置密码策略
print_color "$CYAN" "配置密码策略..."
backup_config "/etc/login.defs"
sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs 2>/dev/null
sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' /etc/login.defs 2>/dev/null
sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE 7/' /etc/login.defs 2>/dev/null
# 4. 配置内核参数
print_color "$CYAN" "配置内核安全参数..."
backup_config "/etc/sysctl.conf"
cat >> /etc/sysctl.conf << EOF # 安全加固配置 net.ipv4.ip_forward = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 net.ipv4.tcp_syncookies = 1 kernel.randomize_va_space = 2 fs.suid_dumpable = 0 EOF sysctl -p print_color "$GREEN" "✅ 基本安全加固完成!" print_color "$CYAN" "建议重启系统以使所有更改生效" log_message "应用基本安全加固" } # 显示系统安全状态 show_system_security_status() { clear print_color "$PURPLE" "系统安全状态概览" echo "========================================" echo "" print_color "$CYAN" "🔐 认证安全:" echo " - 空密码用户: $(awk -F: '($2 == "" ) {print $1}' /etc/shadow 2>/dev/null | wc -l)"
echo " - UID 0用户: $(awk -F: '($3 == 0) {print $1}' /etc/passwd | wc -l)"
echo ""
print_color "$CYAN" "🛡️ 网络安全:"
echo " - 开放端口: $(netstat -tulpn 2>/dev/null | grep LISTEN | wc -l)"
echo " - SSH连接: $(ss -tun 2>/dev/null | grep :22 | wc -l)"
echo ""
print_color "$CYAN" "📁 文件安全:"
echo " - SUID文件: $(find / -type f -perm -4000 2>/dev/null | wc -l)"
echo " - 全局可写文件: $(find / -type f -perm -0002 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | wc -l)"
echo ""
print_color "$CYAN" "⚙️ 服务安全:"
echo " - 运行中服务: $(systemctl list-units --state=running 2>/dev/null | grep service | wc -l)"
echo " - 失败的服务: $(systemctl list-units --state=failed 2>/dev/null | wc -l)"
echo ""
print_color "$CYAN" "📊 资源监控:"
echo " - 内存使用: $(free -h | awk '/^Mem:/ {print $3 "/" $2}')"
echo " - 磁盘使用: $(df -h / | awk 'NR==2 {print $5}')"
echo "========================================"
print_color "$CYAN" "按回车键继续..."
read -n 1
}
# 启动脚本
if [ "$#" -eq 0 ]; then
show_menu
else
case $1 in
"--audit"|"-a")
run_security_audit
;;
"--harden"|"-h")
apply_basic_hardening
;;
"--status"|"-s")
show_system_security_status
;;
"--help"|"-?")
print_color "$CYAN" "使用说明:"
echo " $0 显示交互式菜单"
echo " $0 --audit | -a 运行完整安全审计"
echo " $0 --harden | -h 应用基本安全加固"
echo " $0 --status | -s 显示系统安全状态"
echo " $0 --help | -? 显示帮助信息"
;;
*)
print_color "$RED" "未知选项: $1"
print_color "$CYAN" "使用 $0 --help 查看帮助"
;;
esac
fi