测试环境Linux主机安全自查:低误报脚本与配置审计实践

1. 项目概述:为什么我们需要一份“低误报”的测试环境安全自查清单?

在测试环境里搞安全排查,很多运维和开发同学的第一反应可能是:“测个试而已,又不是生产,搞那么严干嘛?” 这话对了一半。测试环境确实不需要像生产环境那样部署层层堡垒、严苛的访问控制,但它恰恰是安全风险最容易滋生的“灰色地带”。因为“不重要”,所以大家往往随手设置弱密码、开放不必要的端口、使用带已知漏洞的组件版本。更关键的是,测试环境通常与生产环境网络互通,或者共享部分中间件、数据库实例。一旦测试机被攻破,攻击者很容易以此为跳板,横向移动到核心业务区。

我见过太多因为测试环境一个弱口令的Redis或Nacos,导致整个内网沦陷的案例。所以,定期对测试环境的Linux主机进行“轻量级但有效”的安全自查,不是小题大做,而是成本最低的主动防御。这份清单的目标很明确: 用一系列可直接在Linux终端执行的命令和脚本,快速定位常见的配置型弱密码和漏洞,同时通过精细化的规则和上下文判断,尽可能降低误报,让你把精力集中在真正的风险上。 它特别覆盖了Nacos、各类应用配置文件和数据库连接配置这些在测试环境里“重灾区”中的“重灾区”。

2. 整体设计思路:精准打击,而非火力覆盖

传统的漏洞扫描器在测试环境里往往“水土不服”。它们会报出一大堆“理论上”的漏洞,比如一个仅在内网监听、版本稍旧的Nginx,可能被标记为高危,但实际上并无直接风险。这种“噪音”会严重消耗排查精力。因此,我们的设计遵循几个核心原则:

2.1 上下文感知,减少误报 我们不单纯依赖版本号匹配CVE。例如,对于Nacos的未授权访问漏洞,我们会先检查其监听地址(是 0.0.0.0 还是 127.0.0.1 ),再结合防火墙规则或网络策略判断其实际暴露面。对于数据库弱密码,我们会先确认该数据库服务是否正在运行、是否被业务应用实际使用,而不是扫描出一个陈旧的、已停用的MySQL实例的弱口令就报警。

2.2 聚焦配置与弱口令 在测试环境,0day漏洞不是最高频的风险, 错误的配置和弱密码才是 。我们将重点放在:

  1. 系统层面 :检查SSH、FTP等服务的弱密码或空密码。
  2. 应用层面 :排查Web应用配置文件(如 application.properties application.yml )、中间件配置文件中的明文密码、默认密码。
  3. 特定组件 :针对Nacos、Redis、MySQL等常见组件,进行专项弱密码和配置漏洞检查。

2.3 脚本化、可重复 所有步骤都通过Shell脚本或一行命令完成,方便集成到CICD流水线或定时任务中。脚本会输出结构化的结果(例如JSON或清晰的文本日志),便于后续分析和归档。

2.4 非侵入性与安全性 检查命令尽可能只读,避免修改系统配置或影响正常服务。用于密码爆破的字典是内置的、极小的、针对常见弱口令的,防止对账户造成锁定或产生大量无效流量。

3. 核心检查项与实操命令详解

下面我们分模块,逐一拆解检查命令及其背后的原理。你可以直接在测试环境的Linux主机上root或sudo权限执行。

3.1 系统级弱密码与基础安全

这一部分检查的是操作系统层面的常见安全问题。

3.1.1 检查SSH弱密码或空密码 SSH是进入Linux服务器的首要通道,其安全性至关重要。

# 检查是否允许密码登录(如果只允许密钥登录则风险较低)
grep -E \"^PasswordAuthentication\\s+(yes|no)\" /etc/ssh/sshd_config

# 检查是否有空密码账户
awk -F: '($2 == \"\") {print $1}' /etc/shadow

# 使用hydra进行极简、低速的本地SSH弱密码检测(谨慎使用,避免锁定账户)
# 首先,我们创建一个仅包含最常见弱密码的微字典
echo -e \"root\\nadmin\\n123456\\npassword\\n`hostname`\" > /tmp/weak_ssh_pass.txt
# 仅针对root用户和当前系统上的一个已知低权限用户进行测试,目标为本地环回地址,速率限制为每秒1次
# 注意:此命令仅作为示例,在实际无人值守脚本中应极其谨慎,或改用其他方法。
# hydra -l root -P /tmp/weak_ssh_pass.txt -t 1 -vV -o /tmp/ssh_scan_result.txt ssh://127.0.0.1

注意 :直接在生产或测试环境对SSH进行密码爆破是高风险操作,可能触发安全告警或锁定账户。上述 hydra 命令仅为思路展示。更稳妥的做法是 审计 /etc/shadow 文件的密码哈希强度 ,或者使用像 john --test 这样的工具来评估现有密码哈希的破解难度,而非主动爆破。

3.1.2 检查sudo权限配置不当 错误的sudo配置可能导致普通用户提权。

# 查看所有被授予sudo权限的用户和命令
visudo -c /etc/sudoers  # 先检查语法
grep -v \"^#\\|^$\" /etc/sudoers
ls -la /etc/sudoers.d/ 2>/dev/null && cat /etc/sudoers.d/* 2>/dev/null | grep -v \"^#\"

# 特别关注是否有用户被授予了ALL权限且不需要密码
# grep \"NOPASSWD.*ALL\" /etc/sudoers /etc/sudoers.d/*

3.1.3 检查世界可写文件与SUID/SGID文件 这些文件可能被利用进行权限提升。

# 查找危险的全局可写文件(排除常见的/tmp, /proc等)
find / -xdev -type f -perm -0002 -exec ls -la {} \\; 2>/dev/null | grep -vE \"^/tmp|^/proc|^/dev|^/run\"

# 查找SUID/SGID二进制文件
find / -xdev -type f \\( -perm -4000 -o -perm -2000 \\) -exec ls -la {} \\; 2>/dev/null
# 然后需要人工审查列表,常见的如`/bin/passwd`, `/bin/su`是正常的,陌生的需要警惕。

3.2 应用与中间件配置泄露排查

测试环境的配置文件里常常躺着明文密码。

3.2.1 全局扫描Java应用配置文件 Spring Boot等Java应用的配置文件是重灾区。

# 查找项目中常见的配置文件,并搜索密码关键词
find /home /opt /app -type f \\( -name \"application*.yml\" -o -name \"application*.properties\" -o -name \"bootstrap*.yml\" -o -name \"*.conf\" \\) 2>/dev/null | \\
xargs grep -l -i \"password\\|pwd\\|secret\\|key\\|token\" 2>/dev/null | \\
while read file; do
    echo \"====== 检查文件: $file ======\"
    # 高亮显示包含密码的行,并模糊化显示密码值(示例)
    grep -E -i \"(password|pwd|secret|key|token).*[=:].*\" \"$file\" | sed 's/\\(.*[=:]\\).*/\\1********/i'
    echo
done

3.2.2 专项排查Nacos配置漏洞 Nacos既是配置中心,本身也可能存在漏洞。

  • 检查Nacos未授权访问

    # 1. 确定Nacos进程和监听端口
    netstat -tlnp | grep java | grep -E \":8848|:9848\"  # 默认端口8848(HTTP)和9848(gRPC)
    # 或
    ps aux | grep nacos
    
    # 2. 如果发现Nacos服务,检查其是否监听在0.0.0.0
    # 假设端口是8848
    NACOS_PORT=8848
    NACOS_PID=$(netstat -tlnp | grep \":$NACOS_PORT\" | awk '{print $7}' | cut -d'/' -f1)
    if [ ! -z \"$NACOS_PID\" ]; then
        echo \"Nacos进程PID: $NACOS_PID\"
        # 查看启动参数,判断是否有认证相关配置
        cat /proc/$NACOS_PID/cmdline | tr '\\0' ' ' | grep -o \"-D[^ ]*\" | grep -i auth
        # 直接尝试一个无需认证的API调用(谨慎,可能触发日志)
        curl -s \"http://127.0.0.1:$NACOS_PORT/nacos/v1/auth/users?pageNo=1&pageSize=10\" | head -c 200
        echo
    fi
    

    实操心得 :如果 curl 命令返回了用户列表JSON,则基本可判定存在未授权访问漏洞。 但更推荐检查 application.properties cluster.conf 文件 ,查看 nacos.core.auth.enabled nacos.core.auth.server.identity.key 等配置项是否被正确设置。

  • 检查Nacos配置文件中的弱密码

    # 查找Nacos的配置文件,通常在其安装目录的conf下
    find / -name \"application.properties\" -o -name \"cluster.conf\" 2>/dev/null | xargs grep -l \"nacos\" 2>/dev/null | \\
    while read conf; do
        echo \"检查Nacos配置: $conf\"
        grep -E \"(db\\.password|password|pwd)\" \"$conf\" | sed 's/\\(.*=\\).*/\\1********/'
        # 检查MySQL连接配置
        grep -E \"db\\.url|jdbc:mysql\" \"$conf\"
    done
    

3.2.3 排查Redis未授权访问与弱密码 Redis在测试环境经常被“裸奔”。

# 1. 查找Redis进程和配置
REDIS_PORTS=$(netstat -tlnp | grep redis-server | awk '{print $4}' | cut -d':' -f2)
REDIS_CONF=$(ps aux | grep redis-server | grep -v grep | sed -n \"s/.*\\(--configfile\\|\\-c\\) \\([^ ]*\\).*/\\2/p\")

# 2. 检查配置项
for conf in $REDIS_CONF; do
    if [ -f \"$conf\" ]; then
        echo \"=== Redis配置: $conf ===\"
        grep -E \"^(bind|requirepass|protected-mode)\" \"$conf\"
    fi
done

# 3. 如果没有配置密码,且bind了0.0.0.0或外网IP,则风险高
# 4. 使用redis-cli尝试无认证连接(本地)
for port in $REDIS_PORTS; do
    echo \"测试Redis端口 $port ...\"
    timeout 2 redis-cli -p $port info server 2>&1 | grep -q \"redis_version\" && echo \"  [高危] 端口 $port 可能存在Redis未授权访问!\"
done

3.3 数据库配置与弱密码检测

数据库是数据的核心,其连接信息泄露后果严重。

3.3.1 扫描代码与配置文件中的数据库连接串

# 这是一个更全面的搜索模式,寻找常见的数据库连接字符串
PATTERNS=(
    \"jdbc:mysql://\"
    \"jdbc:oracle:thin:@\"
    \"jdbc:postgresql://\"
    \"host=\"
    \"port=\"
    \"database=\"
    \"username=\"
    \"user=\"
    \"password=\"
)
SEARCH_ROOT=\"/home /opt /app /var/www\" # 指定搜索范围

for pattern in \"${PATTERNS[@]}\"; do
    echo \"=== 搜索模式: $pattern ===\"
    find $SEARCH_ROOT -type f \\( -name \"*.java\" -o -name \"*.py\" -o -name \"*.go\" -o -name \"*.yml\" -o -name \"*.yaml\" -o -name \"*.properties\" -o -name \"*.conf\" -o -name \"*.cfg\" -o -name \"*.xml\" -o -name \"*.json\" \\) 2>/dev/null | \\
    xargs grep -l \"$pattern\" 2>/dev/null | head -5 | while read file; do # 限制输出前5个结果
        echo \"  在文件: $file\"
        grep \"$pattern\" \"$file\" | head -2 | sed 's/password[^ ]*/password=********/i; s/pwd[^ ]*/pwd=********/i'
    done
done

3.3.2 检查运行中的数据库服务弱密码 此步骤需要一个小型弱密码字典,并针对发现的数据库服务进行探测。

# 首先,识别本地运行的MySQL/MariaDB和PostgreSQL
DB_SERVICES=\"\"
# MySQL
if netstat -tlnp | grep -q mysqld; then
    DB_SERVICES=\"$DB_SERVICES mysql\"
fi
# PostgreSQL
if netstat -tlnp | grep -q postgres; then
    DB_SERVICES=\"$DB_SERVICES postgres\"
fi

# 创建一个微型的、针对测试环境常见弱密码的字典
cat > /tmp/db_weak_pass.txt << EOF
root
admin
123456
password
test
12345678
1234
${hostname}_db
EOF

# 定义一个函数来测试数据库弱密码
test_db_password() {
    local db_type=$1
    local user=$2
    local host=${3:-127.0.0.1}
    local port=${4:-3306}

    while read pass; do
        echo -n \"尝试 $db_type 用户 $user 密码: $pass ... \"
        case $db_type in
            mysql)
                timeout 2 mysql -h $host -P $port -u $user -p\"$pass\" -e \"select 1\" 2>&1 | grep -q \"ERROR 1045\" || { echo \"[!] 可能成功或其它错误\"; return 1; }
                ;;
            postgres)
                export PGPASSWORD=\"$pass\"
                timeout 2 psql -h $host -p $port -U $user -c \"select 1\" postgres 2>&1 | grep -q \"password authentication failed\" || { echo \"[!] 可能成功或其它错误\"; return 1; }
                unset PGPASSWORD
                ;;
        esac
        echo \"失败\"
    done < /tmp/db_weak_pass.txt
    echo \"对用户 $user 的微型字典测试完成,未发现明显弱密码。\"
}

# 对发现的数据库服务进行测试(这里以MySQL root用户为例,需根据实际情况调整)
for db in $DB_SERVICES; do
    if [ \"$db\" = \"mysql\" ]; then
        echo \"=== 检测MySQL弱密码 ===\"
        test_db_password mysql root 127.0.0.1 3306
    fi
done

重要警告 :此脚本中的数据库密码测试功能( test_db_password 极具侵入性 ,可能触发数据库账户锁定、产生大量错误日志,并违反某些安全策略。 仅适用于你拥有完全控制权、且已做好备份和监控的测试环境。 更推荐的方法是 审计配置文件中的密码强度 ,或使用 mysql_config_editor 等安全工具管理凭证,而不是主动爆破。

4. 整合脚本与自动化执行

将上述检查点整合到一个Shell脚本中,并加入一些逻辑判断来降低误报。

#!/bin/bash
# 文件名:test_env_security_scan.sh
# 描述:测试环境Linux主机安全自查脚本(低误报版)
set -euo pipefail

LOG_FILE=\"/tmp/security_scan_$(date +%Y%m%d_%H%M%S).log"
SUMMARY_FILE=\"/tmp/security_scan_summary_$(date +%Y%m%d_%H%M%S).txt"

echo \"安全扫描开始于: $(date)\" | tee -a \"$LOG_FILE\" \"$SUMMARY_FILE\"
echo \"========================================\" | tee -a \"$LOG_FILE\" \"$SUMMARY_FILE\"

function log_finding() {
    local level=$1
    local component=$2
    local message=$3
    local recommendation=$4
    echo \"[$level] [$component] $message\" | tee -a \"$LOG_FILE\"
    echo \"  建议: $recommendation\" | tee -a \"$LOG_FILE\"
    # 高风险项记录到摘要
    if [[ \"$level\" == \"高危\" || \"$level\" == \"中危\" ]]; then
        echo \"[$level] $component - $message\" >> \"$SUMMARY_FILE\"
    fi
}

# 检查1: 空密码账户
echo \"[信息] 检查空密码账户...\" | tee -a \"$LOG_FILE\"
empty_pass_users=$(awk -F: '($2 == \"\") {print $1}' /etc/shadow 2>/dev/null || true)
if [[ -n \"$empty_pass_users\" ]]; then
    log_finding \"高危\" \"系统账户\" \"发现空密码账户: $empty_pass_users\" \"立即为这些账户设置强密码或禁用。\"
else
    echo \"[通过] 未发现空密码系统账户。\" | tee -a \"$LOG_FILE\"
fi

# 检查2: Nacos未授权访问(简化版,通过进程和端口判断)
echo \"[信息] 检查Nacos服务...\" | tee -a \"$LOG_FILE\"
if netstat -tlnp | grep -q \":8848\"; then
    nacos_listen=$(netstat -tlnp | grep \":8848\" | awk '{print $4}')
    if echo \"$nacos_listen\" | grep -q \"0.0.0.0:8848\"; then
        log_finding \"中危\" \"Nacos\" \"Nacos服务监听在0.0.0.0:8848,存在潜在暴露风险。\" \"确认是否必须监听所有接口。检查`nacos.core.auth.enabled`是否开启认证。\"
    else
        echo \"[信息] Nacos服务运行中,监听地址: $nacos_listen\" | tee -a \"$LOG_FILE\"
    fi
    # 可以在此处添加更精细的API探测,但需考虑误报和干扰。
fi

# 检查3: 配置文件中的明文密码(示例:搜索Java应用配置)
echo \"[信息] 扫描常见配置文件中的密码关键词...\" | tee -a \"$LOG_FILE\"
config_files=$(find /home /opt /app -type f \\( -name \"application*.yml\" -o -name \"application*.properties\" -o -name \"bootstrap*.yml\" \\) 2>/dev/null | head -20) # 限制数量
sensitive_files=\"\"
for file in $config_files; do
    # 使用更精确的正则匹配 password: xxx 或 password=xxx
    if grep -q -E \"(password|pwd|secret)[[:space:]]*[=:][[:space:]]*[^[:space:]]+\" \"$file\" 2>/dev/null; then
        sensitive_files=\"$sensitive_files $file\"
    fi
done
if [[ -n \"$sensitive_files\" ]]; then
    log_finding \"中危\" \"应用配置\" \"以下配置文件可能包含明文密码: $sensitive_files\" \"审查这些文件,将密码移至环境变量或安全的配置中心(如已开启认证的Nacos)。\"
else
    echo \"[通过] 在常见配置文件中未发现明显的明文密码模式。\" | tee -a \"$LOG_FILE\"
fi

# 检查4: Redis配置检查
echo \"[信息] 检查Redis配置...\" | tee -a \"$LOG_FILE\"
redis_conf=$(ps aux | grep redis-server | grep -v grep | head -1 | awk '{for(i=1;i<=NF;i++) if($i==\"-c\" || $i==\"--configfile\") print $(i+1)}')
if [[ -f \"$redis_conf\" ]]; then
    if grep -q \"^bind 0.0.0.0\" \"$redis_conf\" && ! grep -q \"^requirepass\" \"$redis_conf\"; then
        log_finding \"高危\" \"Redis\" \"Redis配置为监听所有接口且未设置密码(requirepass)。\" \"立即设置强密码(requirepass),并考虑将bind改为127.0.0.1或内网IP。\"
    fi
elif pgrep redis-server > /dev/null; then
    echo \"[警告] 发现Redis进程但未找到配置文件,请手动检查其安全配置。\" | tee -a \"$LOG_FILE\"
fi

echo \"========================================\" | tee -a \"$LOG_FILE\" \"$SUMMARY_FILE\"
echo \"安全扫描结束于: $(date)\" | tee -a \"$LOG_FILE\" \"$SUMMARY_FILE\"
echo \"\"
echo \"=== 扫描摘要 (中危及以上) ===\" | tee -a \"$LOG_FILE\"
cat \"$SUMMARY_FILE\" 2>/dev/null || echo \"(未发现中危及以上风险)\" | tee -a \"$LOG_FILE\"

脚本使用说明:

  1. 将脚本保存为 test_env_security_scan.sh
  2. 赋予执行权限: chmod +x test_env_security_scan.sh
  3. 使用 sudo 或以root用户执行: sudo ./test_env_security_scan.sh
  4. 查看 /tmp/security_scan_*.log 获取详细日志,查看 /tmp/security_scan_summary_*.txt 获取风险摘要。

5. 常见问题与排查技巧实录

在实际运行上述检查时,你可能会遇到一些疑问或问题,这里记录一些典型的处理经验。

5.1 误报处理:如何区分“真正的风险”和“噪音”?

  • 场景 :脚本报告“Nacos监听在0.0.0.0:8848”,但该服务器位于严格的内部网络,且有防火墙策略。
    • 排查 :执行 iptables -L -n firewall-cmd --list-all 查看防火墙规则。确认8848端口是否仅对特定IP段开放。同时,检查Nacos的 application.properties ,确认 nacos.core.auth.enabled=true 。如果认证开启且网络隔离良好,风险等级可降为“低”。
  • 场景 :在配置文件中发现 password=${DB_PASSWORD} 这类占位符。
    • 排查 :这是使用环境变量注入密码的良好实践,不是明文密码。我们的简单正则匹配可能会误报。更高级的脚本可以尝试过滤掉 ${} $() 格式的变量。对于这种情况,人工复核是关键。

5.2 检查覆盖不全怎么办?

我们的脚本是一个“基线检查”,不可能覆盖所有情况。你需要根据自己测试环境的 技术栈 进行补充:

  • 如果使用Docker :增加对运行中容器的检查。 docker ps 查看容器, docker exec <container_id> env 查看容器环境变量(可能包含密码), docker inspect 查看容器挂载的卷,里面可能有配置文件。
  • 如果使用Kubernetes :检查Secrets对象是否被不当挂载为环境变量或文件。检查ConfigMap中是否包含敏感信息。
  • 如果有其他中间件 :如Elasticsearch、MongoDB、Kafka等,参照Redis的检查思路,查阅其官方文档,找到对应的“禁用认证”或“绑定地址”配置项进行检查。

5.3 如何将检查自动化并融入流程?

  1. 定时任务 :使用 cron 每周或每月在测试环境非业务高峰时段执行一次扫描脚本,将结果发送到指定邮箱或IM群。
  2. CICD集成 :在部署到测试环境之前或之后,作为一个“安全门禁”步骤执行。如果发现高危风险(如空密码账户、Redis无密码外网监听),可以将构建标记为不稳定甚至失败,阻断部署。
  3. 结果分析 :不要只关注单次结果。将日志收集到ELK或类似平台,进行趋势分析。例如,统计“明文密码配置文件”的数量变化,衡量安全左移的成效。

5.4 最重要的“避坑”技巧

  • 权限最小化 :运行扫描脚本的账户,权限应足以读取配置文件(如 /etc/shadow 需要root),但 绝不能 拥有修改或删除权限。最好使用一个专用的、具有只读权限的账户。
  • 字典的谨慎使用 :主动密码爆破是最后的手段,且必须获得明确授权。在自动化脚本中, 尽量避免包含爆破模块 。我们的重点永远是 配置审计 静态发现
  • 人工复核 :任何自动化工具的输出都必须经过有经验的人员复核。脚本只是帮你缩小范围、提高效率的工具,不能替代人的判断。
  • 环境隔离 :从根本上解决问题,确保测试环境与生产环境之间有严格的网络边界(如通过VPC、防火墙策略隔离)。这样即使测试环境存在漏洞,其影响范围也受到限制。

安全是一个持续的过程,而不是一次性的任务。这份清单和脚本为你提供了一个在测试环境快速启动安全自查的抓手。真正的安全来自于对细节的关注、对流程的遵守,以及整个团队安全意识的提升。每次部署前花几分钟跑一遍这个检查,养成习惯,很多低级但危险的安全漏洞就能被扼杀在萌芽状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值