
摘要:Shell脚本作为Linux系统管理的重要工具,能够将重复性操作固化为可执行的命令序列,大幅提升运维效率。然而,脚本编写不当会引入安全风险,如密码明文存储、输入验证缺失、权限控制松懈等问题。本文旨在系统性地讲解如何通过Shell脚本对Linux系统进行安全加固,涵盖账号策略、密码复杂度、文件权限、服务管理、端口管控等核心环节,并提供经过实战检验的脚本示例,帮助读者构建一套完整的安全加固方案。
详细内容请参考下文。
在开始编写加固脚本之前,首先需要确认当前操作环境。通过SSH登录Linux服务器后,建议先查看系统版本和Shell环境信息:

良好的编码规范是脚本安全可靠的基础。以下是三条核心规范:
每个Shell脚本的第一行必须指定解释器路径,确保系统使用正确的Shell执行脚本:
# 一般写法#!/bin/bash# 或使用更通用的写法#!/usr/bin/env bash
单行注释使用#符号,多行注释建议使用以下格式:
# 这是单行注释,用于说明某行代码的作用: <这是注释可以写很多行! # ← 必须顶格,否则注释不会结束echo "这行会执行"
备注:参数说明如下
: 是 Shell 的内置空命令(什么都不做),<<! 将后面的内容作为输入重定向给它,从而实现了“吞掉”注释的效果。
在脚本开头添加以下配置,可在遇到错误时立即终止执行,避免连锁反应:
set -e# 命令执行失败时退出set -u# 使用未定义变量时退出set -o pipefail# 管道命令中任一子命令失败则整体失败
账号安全是系统安全的第一道防线。本章通过脚本实现对密码有效期、密码复杂度、登录失败锁定、历史命令优化等策略的自动化配置。
通过修改/etc/login.defs文件,可以统一控制全局密码策略。以下脚本以交互方式让管理员设置关键参数,并自动备份原配置文件:
#!/bin/bash# 账号安全加固脚本# 功能:配置密码有效期、最小长度、过期提醒# 备份原始配置文件cp /etc/login.defs /etc/login.defs.bakecho "===== 密码安全策略配置 ====="read -p "请输入密码有效天数(建议90天): " PASS_MAX_DAYSread -p "请输入密码最小长度(建议8位): " PASS_MIN_LENread -p "请输入密码过期提醒天数(建议15天): " PASS_WARN_AGE# 修改配置sed -i "/^PASS_MAX_DAYS/c\PASS_MAX_DAYS $PASS_MAX_DAYS" /etc/login.defssed -i "/^PASS_MIN_LEN/c\PASS_MIN_LEN $PASS_MIN_LEN" /etc/login.defssed -i "/^PASS_WARN_AGE/c\PASS_WARN_AGE $PASS_WARN_AGE" /etc/login.defsecho "✅密码策略加固完成!"
备注:参数说明如下
PASS_MAX_DAYS:密码最大有效期,超过后强制修改
PASS_MIN_LEN:密码最小长度,低于该值不允许设置
PASS_WARN_AGE:过期前提醒天数,便于用户提前修改
仅限制长度和有效期是不够的,还需强制密码包含大写字母、小写字母、数字和特殊字符。通过配置/etc/pam.d/system-auth中的pam_pwquality.so模块实现:
#!/bin/bash# 密码复杂度加固脚本# 备份原文件cp /etc/pam.d/system-auth /etc/pam.d/system-auth.bakecho "===== 密码复杂度策略配置 ====="echo "要求:新密码必须同时包含大写字母、小写字母、数字,且不能与旧密码相同"sed -i '/pam_pwquality.so/c\password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= difok=1 minlen=8 ucredit=-1 lcredit=-1 dcredit=-1' /etc/pam.d/system-authecho "✅密码复杂度加固完成!"# 备注:参数含义如下difok=1新密码与旧密码至少1个字符不同minlen=8密码最小长度8位ucredit=-1至少包含1个大写字母lcredit=-1至少包含1个小写字母dcredit=-1至少包含1个数字retry=3允许重试3次
为防止暴力破解,应配置账户在多次登录失败后自动锁定:
#!/bin/bash# 登录失败锁定脚本echo "===== 登录失败锁定策略 ====="echo "配置:连续10次登录失败后锁定账户300秒"# 在system-auth中插入pam_tally.so模块sed -i '/^auth required pam_deny.so/i\auth required pam_tally.so onerr=fail deny=10 unlock_time=300' /etc/pam.d/system-authecho "✅登录锁定策略加固完成!"echo "💡手动解锁命令: faillog -u 用户名 -r"
备注:faillog -u 用户名 -r 是一个用于重置用户登录失败记录的系统管理命令,可用于解锁用户。常用相关命令
faillog -u 用户名查看指定用户的失败登录记录
faillog -u 用户名 -r重置指定用户的失败计数
faillog -a 显示所有用户的失败登录记录
faillog -m 3 设置最大失败次数为 3
合理配置/etc/profile中的历史命令记录数和终端超时时间,既能提高审计效率,又能防止闲置会话被滥用:
#!/bin/bash# 历史命令和超时优化echo "===== Shell环境优化 ====="read -p "设置历史命令保存条数(建议1000): " HISTSIZEread -p "设置终端自动注销超时秒数(建议300): " TMOUT# 修改历史命令条数sed -i "/^HISTSIZE/c\HISTSIZE=$HISTSIZE" /etc/profile# 如果TMOUT已存在则修改,否则追加if grep -q "^TMOUT" /etc/profile; thensed-i "/^TMOUT/c\TMOUT=$TMOUT" /etc/profileelseecho"TMOUT=$TMOUT" >> /etc/profilefiecho "✅Shell环境优化完成!"echo "💡请执行 source /etc/profile 使配置生效"
umask决定了新创建文件和目录的默认权限。将umask设置为077,可确保新文件仅对所有者可读写,其他用户无任何权限:
#!/bin/bash# 设置默认umaskecho "===== 设置umask值为077 ====="sed -i "/^UMASK/c\UMASK 077" /etc/login.defsecho "✅umask加固完成!"
建议在加固脚本中增加对关键系统文件权限的检查和修正:
# 关键文件权限加固chmod 644 /etc/passwdchmod 600 /etc/shadowchmod 644 /etc/groupchmod 600 /etc/gshadowchmod 644 /etc/hosts.allowchmod 644 /etc/hosts.deny
系统默认启用了许多非必需服务,关闭它们可以减小攻击面:
#!/bin/bash# 禁用不需要的服务echo "===== 禁用非必要服务 ====="# 关闭IPv6防火墙(如未使用IPv6)/sbin/chkconfig ip6tables off 2>/dev/null# 关闭组播DNS服务/sbin/chkconfig avahi-daemon off 2>/dev/null/sbin/chkconfig avahi-dnsconfd off 2>/dev/null# 关闭蓝牙服务/sbin/chkconfig bluetooth off 2>/dev/null# 停止当前运行的服务/sbin/service ip6tables stop 2>/dev/null/sbin/service avahi-daemon stop 2>/dev/nullecho "✅非必要服务已禁用!"
备注:在生产环境执行前,请确认已安装并配置了firewalld或iptables作为替代防火墙。
使用firewalld管理防火墙,仅开放业务必需的端口:
#!/bin/bash# 防火墙端口管理脚本echo "===== 配置防火墙开放端口 ====="# 安装firewalld(如未安装)yum install -y firewalld firewalld-config# 启动防火墙并设置开机自启systemctl start firewalldsystemctl enable firewalld# 开放常用端口firewall-cmd --zone=public --add-port=80/tcp --permanent # HTTPfirewall-cmd --zone=public --add-port=443/tcp --permanent # HTTPSfirewall-cmd --zone=public --add-port=22/tcp --permanent # SSHfirewall-cmd --zone=public --add-port=21/tcp --permanent # FTPfirewall-cmd --zone=public --add-port=53/udp --permanent # DNS# 重新加载防火墙规则firewall-cmd --reloadecho "✅端口配置完成!当前开放端口如下:"firewall-cmd --list-ports
SSH是服务器最常用的远程管理通道,建议额外进行加固:
#!/bin/bash# SSH安全加固echo "===== SSH安全加固 ====="cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak# 禁止root直接登录(建议使用普通用户+sudo)sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config# 禁用密码登录(仅使用密钥认证,需谨慎)sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config# 修改默认端口(取消注释并修改)sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_configsystemctl restart sshdecho "✅SSH加固完成!"
防止日志文件无限增长撑爆磁盘:
#!/bin/bash# 配置日志轮转cat > /etc/logrotate.d/system_audit </var/log/messages/var/log/secure/var/log/maillog/var/log/cron{weeklyrotate12compressmissingoknotifemptycreate0640 root root}EOFecho "✅日志轮转配置完成!"
# 安装并启用auditdyum install -y auditsystemctl enable auditd#开机自启动审计服务systemctl start auditd#启动审计服务
将以上各章节的加固模块整合为一个完整的脚本,方便一次性执行全部加固操作:
#!/bin/bash============================================# Linux系统安全加固一键执行脚本# 适用系统:CentOS 7/8# 功能:账号安全、密码策略、文件权限、# 服务管理、防火墙配置、日志审计============================================set -eLOG_FILE="/var/log/security_hardening.log"log_info() {echo"[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"}log_info "========== 开始执行系统安全加固 =========="# 1. 账号安全加固log_info "执行账号安全加固..."# 此处调用2.1节代码#!/bin/bash# 账号安全加固脚本# 功能:配置密码有效期、最小长度、过期提醒# 备份原始配置文件cp /etc/login.defs /etc/login.defs.bakecho "===== 密码安全策略配置 ====="read -p "请输入密码有效天数(建议90天): " PASS_MAX_DAYSread -p "请输入密码最小长度(建议8位): " PASS_MIN_LENread -p "请输入密码过期提醒天数(建议15天): " PASS_WARN_AGE# 修改配置sed -i "/^PASS_MAX_DAYS/c\PASS_MAX_DAYS $PASS_MAX_DAYS" /etc/login.defssed -i "/^PASS_MIN_LEN/c\PASS_MIN_LEN $PASS_MIN_LEN" /etc/login.defssed -i "/^PASS_WARN_AGE/c\PASS_WARN_AGE $PASS_WARN_AGE" /etc/login.defsecho "✅密码策略加固完成!"# 2. 密码策略加固log_info "执行密码策略加固..."# 此处调用2.2节代码#!/bin/bash# 密码复杂度加固脚本# 备份原文件cp /etc/pam.d/system-auth /etc/pam.d/system-auth.bakecho "===== 密码复杂度策略配置 ====="echo "要求:新密码必须同时包含大写字母、小写字母、数字,且不能与旧密码相同"sed -i '/pam_pwquality.so/c\password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= difok=1 minlen=8 ucredit=-1 lcredit=-1 dcredit=-1' /etc/pam.d/system-authecho "✅密码复杂度加固完成!"# 3. 登录锁定策略log_info "执行登录锁定配置..."# 此处调用2.3节代码#!/bin/bash# 登录失败锁定脚本echo "===== 登录失败锁定策略 ====="echo "配置:连续10次登录失败后锁定账户300秒"# 在system-auth中插入pam_tally.so模块sed -i '/^auth required pam_deny.so/i\auth required pam_tally.so onerr=fail deny=10 unlock_time=300' /etc/pam.d/system-authecho "✅登录锁定策略加固完成!"echo "💡手动解锁命令: faillog -u 用户名 -r"# 4. umask设置log_info "设置umask..."# 此处调用3.1节代码#!/bin/bash# 设置默认umaskecho "===== 设置umask值为077 ====="sed -i "/^UMASK/c\UMASK 077" /etc/login.defsecho "✅umask加固完成!"# 5. 服务禁用log_info "禁用非必要服务..."# 此处调用4.1节代码#!/bin/bash# 禁用不需要的服务echo "===== 禁用非必要服务 ====="# 关闭IPv6防火墙(如未使用IPv6)/sbin/chkconfig ip6tables off 2>/dev/null# 关闭组播DNS服务/sbin/chkconfig avahi-daemon off 2>/dev/null/sbin/chkconfig avahi-dnsconfd off 2>/dev/null# 关闭蓝牙服务/sbin/chkconfig bluetooth off 2>/dev/null# 停止当前运行的服务/sbin/service ip6tables stop 2>/dev/null/sbin/service avahi-daemon stop 2>/dev/nullecho "✅非必要服务已禁用!"# 6. 防火墙配置log_info "配置防火墙端口..."# 此处调用4.2节代码#!/bin/bash# 防火墙端口管理脚本echo "===== 配置防火墙开放端口 ====="# 安装firewalld(如未安装)yum install -y firewalld firewalld-config# 启动防火墙并设置开机自启systemctl start firewalldsystemctl enable firewalld# 开放常用端口firewall-cmd --zone=public --add-port=80/tcp --permanent# HTTPfirewall-cmd --zone=public --add-port=443/tcp --permanent# HTTPSfirewall-cmd --zone=public --add-port=22/tcp --permanent# SSHfirewall-cmd --zone=public --add-port=21/tcp --permanent# FTPfirewall-cmd --zone=public --add-port=53/udp --permanent# DNS# 重新加载防火墙规则firewall-cmd --reloadecho "✅端口配置完成!当前开放端口如下:"firewall-cmd --list-ports# 7. SSH加固log_info "执行SSH安全加固..."# 此处调用4.3节代码#!/bin/bash# SSH安全加固echo "===== SSH安全加固 ====="cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak# 禁止root直接登录(建议使用普通用户+sudo)sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config# 禁用密码登录(仅使用密钥认证,需谨慎)sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config# 修改默认端口(取消注释并修改)sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_configsystemctl restart sshdecho "✅SSH加固完成!"log_info "========== 系统安全加固全部完成!=========="log_info "详细日志请查看: $LOG_FILE"
每次修改前先备份:所有配置文件的修改都应有对应的.bak备份文件,便于回滚。
避免硬编码敏感信息:密码、密钥等敏感数据不应直接写入脚本,应通过环境变量或交互式输入传递。
测试环境先行:任何加固脚本都应在测试环境验证后再应用于生产服务器。
保留操作日志:所有加固操作应记录日志,便于审计和问题追溯。
