Files
laoyang 5006d54be3 附件读取统一走 media.php 代理,真实地址不再暴露
无论附件存在本机 uploads/ 还是 OSS 私有桶,前台给浏览器的地址现在完全一致:
media.php?k=<对象键>。界面上不再出现 uploads/ 真实路径,也不出现任何 bucket /
endpoint / 签名痕迹。

- lib/attach.php:新增 fb_attach_proxy_url(),fb_attach_url() 与
  fb_attach_thumb_url() 的本机分支一并改走代理(地址不落库、渲染现算,
  对历史附件立即生效,无需迁移)。
- uploads/ 整目录禁止 Web 直读:附件只能经 media.php 出,真实物理路径
  即便被猜到也取不到,同时绕不开 media.php 的可见性鉴权。
- 规则版本化自动升级:.htaccess 内埋 `# fb-local-guard: vN`,
  旧版规则在任意请求时由 PHP(目录属主)整份重写。之所以不能靠部署覆盖:
  部署账号对 uploads/ 无写权限,只有程序自己能改。
- 随包 uploads/.htaccess 改为程序产出的逐字节副本,并加断言防漂移
  (否则线上会被自动升级覆盖,随包那份形同虚设)。
- 顺带修复真实源码泄漏:config.php.bak_<时间戳> 这类「非 .php 结尾、
  但含源码」的备份文件此前可被公开下载。加固根 .htaccess:
  去掉正则结尾锚点、补 .php[.\-_] 兜底、点名拒绝 config.php / oss.sts.php。
- media.php / upload.php / admin.php / README.md:文档与响应头同步。

验证:php -l 19 文件 0 失败;主回归 25/25、附件专项 22/22、安装向导 60/60、
统一代理渲染 7/7、反向验证 V1-V4 全被抓住;线上冒烟 30/30、
线上统一代理真机 13/13(OSS 私有桶 + 内网 endpoint 下上传→代理读回→
Range 206→伪造键 403)。
2026-09-28 23:33:45 +08:00

61 lines
2.5 KiB
ApacheConf

# FeedLite —— 安全与整洁(Apache 规则)
#
# 作用:禁用目录列表;阻止对数据库 / 配置文件 / 备份文件 / 文档的直接下载。
# ⚠️ 这些规则只拦「静态直读」。.php 文件本身仍是「被 PHP 执行」而非下载,
# 所以拦截的重点是「非 .php 后缀但内容敏感」的文件 —— 例如手工或工具产生的
# config.php.bak_20260928_193339(名字以数字结尾!旧写法的 \.bak$ 匹配不到它,
# 于是它被当作静态文件原样吐出,等于公开了管理员口令与接口令牌)。
# 因此后缀匹配一律放宽为「后缀出现在文件名任意位置」,而不是只匹配结尾。
Options -Indexes
# —— 数据库 / 日志 / 文档 / 配置与备份(含任意后缀形式)——
# 关键点:不写 $ 结尾锚点,避免 config.php.bak_20260928_193339 这类名字漏网。
<FilesMatch "(?i)\.(db|sqlite|sqlite3|log|md|ini|bak|old|orig|save|swp|swo|tmp|temp|copy|dist|example\.php\.|php\.(bak|old|orig|save|txt|swp|tmp))">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
</FilesMatch>
# —— 兜底:任何「含 .php 且后面还跟着别的东西」的文件一律拒绝 ——
# 正常 PHP 入口都是 xxx.php 结尾,会被 PHP 执行;
# 而 config.php.bak_20260928、config.php.txt、admin.php.old 这类
# 不会被执行、只会被当文本下载 —— 全部拒掉。
<FilesMatch "(?i)\.php[.\-_]">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
</FilesMatch>
# —— 隐藏文件(.env / .git 之类)——
<FilesMatch "^\.">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
</FilesMatch>
# —— 点名拒绝:只含真实凭据的配置文件(正常请求永远不会直接访问它们)——
# 它们通常会被 PHP 执行(返回空 body)而不泄漏,但显式拒绝可以防「PHP 处理器被改
# 成静态输出」「服务器换了不支持的执行配置」这类意外,属于纵深防御。
# 注意:文件系统层面的 require 不受影响,程序读配置照常工作。
<FilesMatch "(?i)^(config|config\.local|oss\.sts)\.php$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
</FilesMatch>