暴露的 .git 目录:藏在眼皮底下的源代码泄露
当 Web 服务器在提供应用文件的同时也提供 .git 目录时,攻击者可以下载足够多的对象来重建你的完整源代码——包括曾经提交过的每一个密钥,即使它在后来的提交中已被删除。AppSafe 将此标记为严重问题。
这是什么
Git 将完整的仓库——每个文件、每次提交、每个分支的最新提交——存储在项目根目录下隐藏的 .git 目录中。如果该目录最终位于 Web 根目录内,而服务器又没有阻止对它的访问,那么 /.git/config、/.git/HEAD 以及 /.git/objects/ 下的对象存储都可以被公开下载。
从泄露的 .git 目录重建完整源代码非常简单。git-dumper 等工具会先获取索引,再拉取所有被引用的对象,最终得到一个完全可用的工作副本。攻击者不需要 shell 访问权限——只需要一个浏览器。
为什么重要
你的源代码几乎肯定包含会增加风险的信息:硬编码的 API key(通常在较早的提交中)、数据库结构、内部端点路径、业务逻辑和认证流程。即使当前没有提交任何密钥,历史记录中也充满了攻击者可以利用的材料。
Git 历史在设计上就是永久的。多年前提交、随后被删除的密钥仍然存在于对象存储中,并会与其他所有内容一起被下载。轮换密钥是消除其威胁的唯一方法。
如何修复
拒绝所有路径以 /.git/ 开头的请求。返回 404 而不是 403,以免确认该目录存在。
location ~ /\.git {
deny all;
return 404;
}最可靠的修复方法是从一开始就不要把 .git 目录部署到文档根目录中。调整构建流程,让编译产物输出到单独的 public/ 目录,并且只部署该目录,而不是项目根目录。
部署修复后,在浏览器中请求 https://yourdomain.com/.git/config。它应该返回 404,而不是你的 Git 配置内容。AppSafe 会在每次扫描时重新检查这一点。
如果该目录曾经可访问,请将任何提交中出现过的每一个 API key、密码和令牌都视为已泄露,并进行轮换——仅删除提交是不够的,因为该对象仍然存在于攻击者可能已经下载的 pack 文件中。
常见问题
我部署在托管平台上(Vercel、Netlify、Fly.io)——我有风险吗?
从源代码构建的托管平台通常只部署构建产物,因此不会提供 .git 目录。风险更高的是 VPS 部署、从项目根目录构建的 Docker 容器,或者复制整个工作树的静态站点导出。
AppSafe 实际检查的是什么?
AppSafe 会请求 /.git/config 和 /.git/HEAD,并检查响应正文是否像真正的 Git 文件(匹配 [core] 或 ref: 模式)。不是 Git 内容的通用 200 页面不会被标记。
我可以直接删除服务器上的 .git 目录吗?
可以,如果你只需要部署的文件来运行应用。但要确保你的部署流程不会在下次推送时把它复制回来。在 Web 服务器层面阻止访问是一种双重保险,可以应对部署脚本不一致的情况。
博客文章
冒充 AI 爬虫的机器人正在搜寻你的 .env 文件:教你自查
凭证扫描器借用 AI 爬虫的名字绕过白名单,而它们专找一个文件:你的 .env。如何检查它能否被访问,以及如何把它锁好。
Railway 遭入侵:如何在不停机的情况下轮换应用密钥
攻击者盯上了 AI 和平台的 API 密钥,Railway 随即要求所有用户轮换环境变量。如何评估你的暴露程度、在不让应用宕机的前提下轮换全部密钥,并让下一次泄露的伤害更小。
PHP2Shell 正被利用:如何检查你的应用是否暴露
PHP 本身的两个严重漏洞在短短几天内就从“补丁已发布”变成了“已被在野利用”。如何查明你托管的任何东西是否运行受影响的版本,以及今天该怎么做。