Nacos 登录异常和异常管理员账号清理
这次遇到的问题是:开发环境 Nacos 原来的账号密码突然登录不上,页面提示“用户名或密码错误”,接口返回 user not found!。一开始很容易以为只是密码被人改了,但实际排查下来,问题更接近一次暴露服务被扫描后的异常账号写入。
这篇记录只保留排查和修复方法,不记录真实公网 IP、真实密码、token、数据库密码等敏感信息。
现象
Nacos 控制台登录失败:
用户名或密码错误
用登录接口测试时,返回:
HTTP/1.1 403
user not found!
开发环境里 Nacos 是 Docker 容器运行,鉴权已开启:
docker ps | grep nacos
ps -ef | grep '[n]acos'
可以看到类似参数:
-Dnacos.standalone=true
-Dnacos.core.auth.enabled=true
先确认 Nacos 用的是哪个用户库
先进入服务器看 Nacos 容器的环境变量和配置。
docker exec nacos sh -lc 'env | sort | grep -Ei "MYSQL|NACOS_AUTH|NACOS_CORE"'
docker exec nacos sh -lc 'grep -nE "db\\.|nacos.core.auth" /home/nacos/conf/application.properties'
这次确认 Nacos 使用的是同机 MySQL 容器里的 nacos_config 库,用户表是:
nacos_config.users
nacos_config.roles
nacos_config.permissions
检查用户和角色:
SELECT username, enabled FROM users ORDER BY username;
SELECT username, role FROM roles ORDER BY username, role;
结果发现除了正常的 nacos,还有多个异常账号,并且有异常账号拥有 ROLE_ADMIN。
备份鉴权表
修复前先备份 Nacos 鉴权相关表。
mkdir -p /root/nacos_auth_backup_$(date +%Y%m%d_%H%M%S)
mysqldump nacos_config users roles permissions > nacos_auth_tables.sql
如果 MySQL 跑在 Docker 里,就用容器执行:
docker exec mysql sh -lc 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" nacos_config users roles permissions' > nacos_auth_tables.sql
删除异常账号并还原 nacos 用户
这次保留 nacos 账号,删除异常账号和角色。
START TRANSACTION;
UPDATE users
SET enabled = 1
WHERE username = 'nacos';
DELETE FROM permissions
WHERE role IN (
SELECT role
FROM roles
WHERE username IN (
'hack',
'hacker_admin',
'nv_276a8851',
'nv_54860ba0',
'nv_6eb77951',
'nv_7fbdae4f',
'special'
)
);
DELETE FROM roles
WHERE username IN (
'hack',
'hacker_admin',
'nv_276a8851',
'nv_54860ba0',
'nv_6eb77951',
'nv_7fbdae4f',
'special'
);
DELETE FROM users
WHERE username IN (
'hack',
'hacker_admin',
'nv_276a8851',
'nv_54860ba0',
'nv_6eb77951',
'nv_7fbdae4f',
'special'
);
COMMIT;
修复后应该只剩:
nacos 1
nacos ROLE_ADMIN
BCrypt 的坑
这里踩了一个坑:不能随便用系统工具生成 BCrypt hash 后直接写进 users.password。
第一次用了 htpasswd -B 生成 BCrypt,表面上格式也是 $2a$,长度也是 60,但 Nacos 登录仍然返回:
user not found!
打开 MySQL general log 临时抓一次登录请求,确认 Nacos 确实在查用户表:
SELECT username,password FROM users WHERE username='nacos';
所以问题不是“查不到用户表”,而是密码 hash 没有被 Nacos 正确校验。最终用 Nacos 容器里自带的 spring-security-crypto 生成 BCrypt hash,再写回 users.password 后登录恢复。
生成方式示例:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class NacosHash {
public static void main(String[] args) {
System.out.print(new BCryptPasswordEncoder().encode(System.getenv("NACOS_RESTORE_PASS")));
}
}
从 Nacos jar 里取对应依赖:
jar xf /home/nacos/target/nacos-server.jar \
BOOT-INF/lib/spring-security-crypto-5.7.10.jar \
BOOT-INF/lib/spring-jcl-5.3.29.jar
再编译运行,把生成的 hash 写回:
UPDATE users
SET password = '<Spring Security 生成的 BCrypt hash>',
enabled = 1
WHERE username = 'nacos';
验证
用登录接口验证:
curl -i -X POST 'http://<nacos-host>:8848/nacos/v1/auth/users/login' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=nacos' \
--data-urlencode 'password=<password>'
成功时会返回:
{
"accessToken": "...",
"tokenTtl": 18000,
"globalAdmin": true,
"username": "nacos"
}
再用 token 读取一个配置,确认权限正常:
curl 'http://<nacos-host>:8848/nacos/v1/cs/configs?dataId=xxx.yaml&group=DEFAULT_GROUP&tenant=xxx&accessToken=xxx'
入侵痕迹
MySQL general log 里看到过来自内网地址的 root 连接,查询内容里出现反连 shell 相关字符串,随后又执行了关闭 general log 的操作。
这说明问题不只是 Nacos 密码错误,而是服务器暴露面已经被扫描或尝试利用。
当时还检查了:
crontab -l
grep -RInE 'bash -i|/dev/tcp|curl|wget' /etc/crontab /etc/cron.d /var/spool/cron 2>/dev/null
ss -antp | grep -E ':8848|:3306'
没有发现 cron 里已经落地反连任务,但 MySQL 和 Nacos 端口仍然公网监听,这个风险必须处理。
加固清单
这类问题修完登录只是第一步,后面更重要的是收口暴露面。
必须做:
- Nacos
8848不要直接公网开放,只允许 VPN、内网或固定办公 IP。 - MySQL
3306不要直接公网开放,只允许应用服务器或堡垒机访问。 - 轮换 Nacos 登录密码。
- 轮换 Nacos auth token。
- 轮换 MySQL root 密码。
- 删除所有异常 Nacos 账号和角色。
- 检查
users、roles、permissions是否又被写入异常数据。 - 打开必要的访问日志,但不要长期开启 MySQL general log。
可以定期检查:
SELECT username, enabled FROM nacos_config.users ORDER BY username;
SELECT username, role FROM nacos_config.roles ORDER BY username, role;
总结
Nacos 登录提示 user not found! 不一定是真的没有用户,也可能是密码 hash 校验失败后的泛化提示。遇到这类问题时,不要只在控制台反复试密码,应该先确认 Nacos 实际连接的数据库,再检查 users、roles、permissions。
这次的关键经验有三个:
- 修复前先备份鉴权表。
- Nacos 密码 hash 用它自身依赖的 Spring Security BCrypt 生成,不要随便混用工具。
- 发现异常管理员账号后,要把问题当安全事件处理,重点收口
8848和3306。