简单的linux加固脚本
约 2799 字大约 9 分钟
2024-11-16
下面是一个linux安全加固的脚本,这个脚本只对密码策略和Banner信息等进行了加固,其他项有待完善
#!/bin/bash
# 获取主机的第一个IP地址并存储在变量IP中
IP=$(hostname -I | cut -d ' ' -f1)
# 创建一个以IP地址命名的文件
touch $IP
# 日志函数,用于记录信息到指定的日志文件
log() {
# 将第一个参数赋值给变量 level,表示日志级别
local level=$1
# 将第二个参数赋值给变量 message,表示日志消息内容
local message=$2
# 使用变量 IP 作为日志文件名
local log_file="$IP"
# 输出日志消息,包含时间戳、日志级别和消息,并同时追加到日志文件中
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" | tee -a $log_file
}
# 备份指定文件
backup_file() {
# 将第一个参数赋值给变量 file,表示要备份的文件路径
local file=$1
# 生成当前时间戳,格式为 YYYYMMDD_HHMMSS
local timestamp=$(date '+%Y%m%d_%H%M%S')
# 检查文件是否存在
if [ -f "$file" ]; then
# 备份文件,重命名为原文件路径后添加 .bak. 时间戳,并记录日志
cp "$file" "${file}.bak.${timestamp}" && \
log "INFO" "已备份 $file 到 ${file}.bak.${timestamp}" || \
log "ERROR" "备份 $file 失败。"
else
# 如果文件不存在,记录警告日志
log "WARN" "$file 不存在,跳过备份。"
fi
}
# 配置 PAM 模块
configure_faillock() {
# 定义 PAM 配置文件路径
local pam_config_file="/etc/pam.d/password-auth"
# 备份 PAM 配置文件
backup_file "$pam_config_file"
# 定义 faillock 模块的各种配置
local FAILLOCK_AUTHFAIL="auth [default=die] pam_faillock.so authfail audit even_deny_root deny=10 unlock_time=60"
local FAILLOCK_PREAUTH="auth required pam_faillock.so preauth silent audit even_deny_root deny=10 unlock_time=60"
local FAILLOCK_ACCOUNT="account required pam_faillock.so"
# 检查 PAM 配置文件中是否已经包含 faillock 相关配置
if grep -Eq ".*(pam_faillock.so).*" "$pam_config_file"; then
# 如果存在,记录信息并清理旧配置
log "INFO" "登录失败策略配置不正确,正在进行自动修正"
temp_file=$(mktemp) # 创建一个临时文件
grep -Ev ".*(pam_faillock.so).*" "$pam_config_file" > "$temp_file"
mv "$temp_file" "$pam_config_file" # 将临时文件覆盖原文件
else
# 如果不存在,记录信息
log "INFO" "没有配置登录失败策略,正在进行自动修正"
fi
# 将 faillock 模块的新配置添加到 PAM 配置文件中
# 在 pam_env.so 结束后添加 preauth 配置
sed -i '/^auth[[:space:]]*required[[:space:]]*pam_env.so/a\
'"$FAILLOCK_PREAUTH" "$pam_config_file"
# 在 pam_unix.so 结束后添加 authfail 配置
sed -i '/^auth[[:space:]]*sufficient[[:space:]]*pam_unix.so/a\
'"$FAILLOCK_AUTHFAIL" "$pam_config_file"
# 在 pam_unix.so 结束后添加 account 配置
sed -i '/^account[[:space:]]*required[[:space:]]*pam_unix.so/a\
'"$FAILLOCK_ACCOUNT" "$pam_config_file"
# 记录信息,说明 faillock 模块配置已更新
log "INFO" "已更新 faillock 模块配置到 $pam_config_file 文件。"
}
# 检查并设置密码策略,确保密码符合要求
set_compliant_password_policy() {
# 定义密码策略配置文件路径
local pwquality_config="/etc/security/pwquality.conf"
# 备份密码策略配置文件
backup_file "$pwquality_config"
# 调用 modify_config 函数确保 minlen 设置为 8
modify_config "$pwquality_config" "minlen" "minlen = 8"
# 调用 modify_config 函数确保密码至少包含一个数字
modify_config "$pwquality_config" "dcredit" "dcredit = -1"
# 调用 modify_config 函数确保密码至少包含一个特殊字符
modify_config "$pwquality_config" "ocredit" "ocredit = -1"
# 调用 modify_config 函数确保密码至少包含一个大写字母
modify_config "$pwquality_config" "ucredit" "ucredit = -1"
# 调用 modify_config 函数确保密码至少包含一个小写字母
modify_config "$pwquality_config" "lcredit" "lcredit = -1"
}
# 通用函数,用于修改配置文件中的特定配置项
modify_config() {
# 将第一个参数赋值给变量 file,表示要修改的配置文件路径
local file=$1
# 将第二个参数赋值给变量 key,表示要修改的配置项关键字
local key=$2
# 将第三个参数赋值给变量 new_value,表示新的配置项值
local new_value=$3
# 检查配置文件中是否不存在该配置项,如果不存在,则添加
if ! grep -E "^\s*$key\s*=" $file >/dev/null 2>&1; then
echo "$new_value" >> $file # 添加新配置项到文件末尾
log "INFO" "$key 已设置为 $new_value。"
# 如果配置项存在但值不正确,则修正配置项的值
elif ! grep -E "^\s*$key\s*=\s*${new_value#*=}" $file >/dev/null 2>&1; then
# 使用 sed 进行替换,将该配置项替换为新的配置项值
sed -i "s/^$key.*/$new_value/g" $file
log "INFO" "$key 配置不正确,已修正为 $new_value。"
else
# 如果配置项已经符合要求,记录信息
log "INFO" "$key 已符合要求。"
fi
}
# 检查 SSH 和系统登录是否设置了正确的超时时间,以确保终端会话不会无限期保持打开状态
check_login_timeout() {
# 定义检查的多个文件路径( Bash 配置文件)
for file in "/etc/profile" "/etc/bashrc"; do
# 检查该文件中是否设置了 TMOUT=300
if grep -E "^\s*TMOUT\s*=\s*300" $file >/dev/null 2>&1; then
# 如果设置正确,记录信息
log "INFO" "登录超时已设置为 300 秒,检查结果合规。"
else
# 如果设置不正确,记录警告并进行修正
log "WARN" "登录超时未设置或未设置为 300 秒,正在进行自动修正..."
# 备份配置文件
backup_file "$file"
# 使用 sed 删除已有的 TMOUT 设置
sed -i '/^TMOUT/d' $file
echo "TMOUT=300" >> $file # 添加新的 TMOUT 设置
source $file # 使配置立马生效
log "INFO" "$file 登录超时已设置为 300 秒。"
fi
done
}
# 检查系统 Banner 和 SSH Banner 是否设置,以确保合规的登录信息
check_and_set_banner() {
# 定义 Banner 的文本内容
local banner_text="Authorized only. All activity will be monitored and reported."
# 定义 Banner 文件的路径,系统 Banner 和 SSH Banner
local banner_files=("/etc/issue" "/etc/issue.net")
# 循环检查每个 Banner 文件
for file in "${banner_files[@]}"; do
# 检查文件是否存在
if [ -f "$file" ]; then
# 检查文件中是否已经存在正确的 Banner 文本
if grep -Fxq "$banner_text" $file; then
# 如果存在正确的文本,记录信息
log "INFO" "$file 文件 Banner 设置检查通过。"
else
# 如果设置不正确,记录警告并进行修正
log "WARN" "$file 文件 Banner 设置不正确,正在进行自动修正..."
# 备份配置文件
backup_file "$file"
# 将新的 Banner 文本写入文件中并覆盖旧内容
echo "$banner_text" > $file
log "INFO" "$file 文件 Banner 已更新为合规文本。"
fi
else
# 如果文件不存在,记录错误日志
log "ERROR" "$file 文件不存在,无法设置 Banner。"
fi
done
# 检查 SSH 配置文件是否设置了正确的 Banner 格式
if grep -E "^\s*Banner\s+/etc/issue.net" /etc/ssh/sshd_config >/dev/null 2>&1; then
# 如果设置正确,记录信息
log "INFO" "SSH Banner 设置检查通过。"
else
# 如果设置不正确,记录警告日志并进行修正
log "WARN" "SSH Banner 未设置或设置不正确,正在进行自动修正..."
# 备份 SSH 配置文件
backup_file "/etc/ssh/sshd_config"
# 使用 sed 删除已有的 Banner 设置
sed -i '/^Banner/d' /etc/ssh/sshd_config
echo "Banner /etc/issue.net" >> /etc/ssh/sshd_config # 添加新的 Banner 设置
log "INFO" "SSH Banner 已更新为合规文本。"
# 重启 SSH 服务以应用配置更改
if systemctl restart sshd; then
log "INFO" "SSH 服务已重启以应用新的 Banner 设置。"
else
# 如果重启失败,记录错误日志
log "ERROR" "SSH 服务重启失败,请手动检查配置。"
fi
fi
}
# 设置系统日志文件的只可追加属性,防止日志被篡改
check_and_set_append_only() {
# 检查 /var/log/messages 开头的所有文件
for file in /var/log/messages*; do
# 检查文件是否存在
if [ -f "$file" ]; then
# 使用 lsattr 命令和正则表达式检查文件是否具有 'a'(只追加)属性
if lsattr "$file" | cut -d ' ' -f 1 | grep -q 'a'; then
# 如果已设置为只追加,记录信息
log "INFO" "$file 文件属性合规,只可追加内容。"
else
# 如果未设置为只追加,记录警告并进行设置
log "WARN" "$file 文件属性不合规,正在进行自动修正..."
# 使用 chattr 命令为文件添加只追加('a')属性
if chattr +a "$file"; then
log "INFO" "$file 文件属性已成功修改为仅可追加。"
else
# 如果属性修改失败,记录错误日志
log "ERROR" "$file 文件属性修改失败,请手动检查。"
fi
fi
fi
done
}
# 检查是否存在空密码的系统用户
check_empty_password_users() {
# 使用 awk 和正则表达式检查 /etc/shadow 文件中是否存在空密码用户
local empty_password_users=$(awk -F: '( $2 == "" ) { print $1 }' /etc/shadow)
# 使用 [ -z "$empty_password_users" ] 检查结果是否为空
if [ -z "$empty_password_users" ]; then
# 如果为空,记录信息
log "INFO" "未发现空密码用户,检查通过。"
else
# 如果存在空密码用户,使用 for 循环逐一输出并记录警告信息
log "WARN" "警告:发现以下空密码用户,存在安全隐患:"
echo "$empty_password_users" | tee -a $log_file
# 提醒给负责人员设置强密码
echo "请立即为这些用户设置强密码。"
fi
}
# 检查是否存在除了 root 用户之外 UID 为 0 的用户
check_uid_zero_users() {
# 使用 awk 和正则表达式检查 /etc/passwd 文件中是否存在除了 root 之外 UID 为 0 的用户
local uid_zero_users=$(awk -F: '($3 == 0) && ($1 != "root")' /etc/passwd)
# 使用 [ -z "$uid_zero_users" ] 检查结果是否为空
if [ -z "$uid_zero_users" ]; then
# 如果为空,记录信息
log "INFO" "系统合规,没有发现除 root 以外 UID 为 0 的用户。"
else
# 如果存在,输出 users 并记录警告信息
log "WARN" "警告:发现除 root 以外 UID 为 0 的用户:$uid_zero_users"
fi
}
# 检查并禁用不安全的远程登录服务,该函数目前处于注释状态,未启用
# check_insecure_services() {
# 定义需要检查的不安全服务名称数组
# local services=("rlogin" "rsh" "ftp" "telnet")
# 使用 for 循环逐一检查服务是否启用
# for service in "${services[@]}"; do
# 使用 systemctl 检查服务是否启用
# if systemctl is-enabled $service >/dev/null 2>&1; then
# 如果已启用,记录警告信息并禁用服务
# log "WARN" "$service 服务已启用,正在禁用..."
# systemctl disable $service
# systemctl stop $service
# log "INFO" "$service 服务已禁用。"
# else
# 如果未启用,记录信息
# log "INFO" "$service 服务已禁用,符合要求。"
# fi
# done
# }
# 定义主函数,用于按顺序执行多个安全检查和配置操作
main() {
echo "正在执行安全检查..."
# 检查并配置 PAM 来实现登录失败锁定机制
log "INFO" "正在检查账户登录失败锁定策略..."
configure_faillock
# 检查并配置符合要求的密码策略
log "INFO" "正在检查密码策略..."
set_compliant_password_policy
# 检查并设置合理的登录超时值,包括系统登录(Bash)和 SSH 登录
log "INFO" "正在检查登录超时设置..."
check_login_timeout
# 检查并设置系统 Banner 和 SSH Banner 以提醒用户注意安全
log "INFO" "正在检查系统 Banner 和 SSH Banner 设置..."
check_and_set_banner
# 检查系统日志文件属性是否设置为只可追加,以防止日志被篡改
log "INFO" "正在检查 /var/log/messages.* 文件属性..."
check_and_set_append_only
# 检查系统中是否存在空密码用户,存在时提醒消除风险
log "INFO" "正在检查是否存在空密码用户..."
check_empty_password_users
# 检查系统中是否存在除 root 之外 UID 为 0 的用户,这可能是安全问题
log "INFO" "正在检查是否存在除 root 以外 UID 为 0 的用户..."
check_uid_zero_users
# 检查并禁用不安全的远程登录服务,该功能目前被注释掉了,未启用
# log "INFO" "正在检查不安全服务..."
# check_insecure_services
# 记录整个安全检查和配置过程已经完成(该功能目前被注释掉了)
# log "INFO" "安全检查与配置已完成。"
}
# 执行主函数开始安全检查和配置
main