该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。
该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。
该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。
本文档描述了 FrankenPHP 的信任模型:哪些输入是受信任的,哪些不是,以及它们之间的边界在哪里。它旨在帮助安全审计和自动化扫描器理解 FrankenPHP 本身,而不是它所服务的 PHP 应用程序。
有关此处引用的内部机制(线程、CGO 边界、环境沙盒),请参阅 内部原理。有关长时间运行进程中的状态持久性,请参阅 工作模式。
FrankenPHP 在一个包含四个不同参与者的栈中运行:
| 参与者 | 信任 | 备注 |
|---|---|---|
| 远程客户端 | 不可信 | HTTP 请求(方法、URI、请求头、Cookie、请求体、文件上传)是主要的不受信任输入来源。 |
| 操作员 | 受信任 | 提供部署配置:Caddyfile、环境变量、php.ini、已安装的 PHP 扩展和 Caddy 模块,以及应用程序代码本身。 |
| PHP 应用程序代码 | 源头受信任 | 由操作员部署,因此 FrankenPHP 从不执行攻击者提供的代码,但此代码会消费不受信任的请求数据。 |
| FrankenPHP (Go + C) | 可信计算基 | 嵌入 PHP,进行数据传输,并隔离请求和线程。本文档的范围是其自身的缺陷。 |
这是最重要的区别,它解决了大多数关于“我们是否信任 PHP?”的困惑:
$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER、php://input)都是不可信的,就像任何 PHP SAPI 一样。净化这些数据是应用程序的职责。因此,“我们信任来自 PHP 的东西”对于代码来说是真实的,而“SAPI 携带不可信的输入”对于数据来说是真实的:两者并不冲突。FrankenPHP 的职责是忠实地传输这些不可信的数据,并防止一个请求的数据泄露到另一个请求中。
可信计算基有三项职责。FrankenPHP 中的安全缺陷存在于其中之一:
以下是 FrankenPHP 拥有的攻击面。这里的漏洞是 FrankenPHP 的漏洞:
cgi.go、frankenphp_register_server_vars):从请求构建 $_SERVER、REMOTE_ADDR、SCRIPT_NAME、PATH_INFO 和其他 CGI 变量。split_path(默认为 .php)处被分割为 SCRIPT_NAME / PATH_INFO,然后通过 sanitizedPathJoin(filepath.Join(root, filepath.Clean("/"+reqPath)))与文档根目录连接,这可以防止 SCRIPT_FILENAME 逃逸文档根目录(路径遍历)。php_server 指令还会额外设置一个默认的 try_files 重写规则,将请求路由到现有文件或前端控制器,从而缓解了 PHP-FPM 经典陷阱——执行错误文件的问题。$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER 和 $_REQUEST,显式清除 $_SESSION(否则会在请求之间泄露),以及 error_get_last() 和 libxml_get_errors() 返回的错误,http_get_last_response_headers() 返回的请求头,strtok() 状态,以及 output_add_rewrite_var() 添加的变量,但 $_ENV 不会被重置,并且 putenv() 写入、static 变量、类静态属性、全局变量和运行时引擎设置(ini_set()、默认流上下文、默认时区、工作目录等)会在同一线程的请求之间持久存在。留在该状态中的请求或用户特定数据可能会泄露到后续请求中(参见 工作模式)。frankenphp_putenv() / frankenphp_getenv() 操作的是线程本地的 sandboxed_env。putenv() 写入保留在该沙盒内,绝不会到达进程全局的操作系统环境,因此一个请求设置的秘密不会泄露给子进程(proc_open、exec 等)、Go/Caddy 端或其他请求。必须看到此类变量的子进程必须通过 proc_open() 或 exec() 的环境参数明确地提供给它(参见 内部原理)。C.CString() / free() 在 Go ↔ C 边界上的生命周期。/frankenphp/workers/restart 和 /frankenphp/threads 端点,通过 Caddy 的管理 API(默认监听 localhost:2019)暴露。将该端点暴露到 localhost 之外是操作员的决定。X-Forwarded-* 请求头总是作为不可信的 $_SERVER['HTTP_X_FORWARDED_*'] 值到达 PHP;只有当配置了 trusted_proxies 时,它们才被信任用于推导真实的客户端 IP 和协议。request_body_timeout),并在每次读取前重置截止时间,这样任何大小的稳定上传都能成功,而停滞的上传会被切断并释放线程。有关如何报告影响 FrankenPHP 的安全问题,请参阅 SECURITY.md。