pfsockopen本身非漏洞但属高危函数,易被用于SSRF、端口扫描等攻击;修复需限制调用条件、替换为stream_socket_client、严格过滤用户输入。

pfsockopen 本身不是漏洞,但它是高危函数,常被用于 SSRF、端口扫描、PHPDDoS 攻击等场景。当参数(尤其是 host、port)由用户可控输入直接传入时,就构成可利用的风险点。修复核心是:**限制调用条件 + 替换为更安全的替代方案 + 全面过滤输入**。
确认是否真在用 pfsockopen
很多程序实际用的是 fsockopen,而配置中禁用了 fsockopen 却没禁用 pfsockopen,导致绕过。先检查 php.ini 中的 disable_functions 是否已包含:
- pfsockopen
- fsockopen
- stream_socket_client(若不需要网络请求,也建议禁用)
修改后务必重启 Web 服务(Apache/Nginx + PHP-FPM)。
替换危险调用为 stream_socket_client
stream_socket_client 更可控、支持超时与上下文选项,且不维持持久连接,天然规避部分攻击面。替换要点:
立即学习“PHP免费学习笔记(深入)”;
- 原写法:
$fp = pfsockopen($host, $port, $errno, $errstr, $timeout); - 新写法:
$fp = @stream_socket_client("tcp://$host:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context); - 注意:必须校验 $host 和 $port 是否符合白名单规则(如仅允许内网 IP 或特定域名),不能直接拼接
- 建议配合
stream_set_timeout($fp, 5)设置读写超时
从源头堵住用户可控输入
即使函数本身安全,若 host 来自 $_GET['url'] 或 $_POST['target'],仍可能触发 SSRF。需做三重过滤:
-
协议限制:只允许
tcp://,拒绝file://、gopher://、dict://等 -
IP 范围白名单:用
filter_var($ip, FILTER_VALIDATE_IP)验证后,再用ip2long()判断是否属于 127.0.0.1/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 -
域名解析控制:避免 DNS 重绑定,禁止使用短域名或含 @ 符号的 URL(如
attacker.com@victim.com)
禁用不必要功能并加固环境
很多场景其实根本不需要 pfsockopen —— 比如发邮件可用 SMTP 扩展,调用接口可用 cURL(配合 CURLOPT_SAFE_UPLOAD 和 CURLOPT_FORBID_REUSE)。
- 在 php.ini 中关闭远程文件加载:
allow_url_fopen = Off、allow_url_include = Off - 设置 open_basedir 限制脚本可访问路径,防止恶意读取系统文件
- Web 目录权限设为 755(目录)/644(文件),运行用户(如 www-data)不可写入代码目录



















