text协议易被超长行攻击导致oom,因其不校验单行长度且不限缓冲区上限;必须显式设置max_package_size和strict_mode启用防护,否则默认无保护。

Text协议为什么容易被恶意超长行打崩
Workerman 的 TextProtocol 默认用 \n 或 \r\n 做分隔,内部靠不断扫描缓冲区找换行符。它不校验单行长度,也不限制缓冲区上限——如果客户端发一个 500MB 且不含换行的字符串,TextProtocol 会一直缓存、持续扩容内存,直到 OOM 或触发 PHP 内存限制崩溃。
必须设置 max_package_size 并启用 strict_mode
TextProtocol 支持两个关键配置项,但默认都不生效,必须显式传入:
-
max_package_size:单条消息最大允许字节数,超限直接丢弃连接(推荐设为1024 * 1024即 1MB) -
strict_mode:设为true后,协议解析器会在每次 recv 后立即检查是否已收到完整行;若缓冲区超过max_package_size仍无换行,直接断连
示例写法:
$worker = new Worker('text://0.0.0.0:1234');
$worker->protocol = \Workerman\Protocols\TextProtocol::class;
$worker->transport = 'tcp';
// 必须这样传参,不能只 new TextProtocol()
$worker->onMessage = function ($connection, $data) {
// $data 已是完整一行(不含\n)
$connection->send("echo: " . $data);
};
// 关键:通过 protocol_args 注入配置
$worker->protocol_args = [
'max_package_size' => 1024 * 1024,
'strict_mode' => true,
];
比 TextProtocol 更安全的替代方案
如果你控制得了客户端,强烈建议放弃 TextProtocol,改用带长度头的协议:
- 用
FrameProtocol:内置包头(4 字节网络序长度),天然防粘包+防超长,无需手动解析 - 自定义二进制协议:用
pack('N', $len)+unpack('N', $header),长度字段本身就能做第一道校验 - JSON over TCP:自己实现 input() 方法,先读固定长度头,再按长度读 body,再
json_decode(),全程可控
注意:TextProtocol 的“简单”是假象——它省掉的解析逻辑,全在内存和稳定性上还了债。
生产环境必须配合系统级防护
仅靠协议层还不够,得叠加防御:
- 在
onConnect中记录连接时间,并用Worker::addTimer()定期清理空闲连接(比如 60 秒无数据就 close) - 用 Nginx 或 HAProxy 做前置代理,配置
client_max_body_size和proxy_read_timeout,提前拦截异常流量 - Linux 层面限制单进程打开文件数:
ulimit -n 65535,防止恶意建大量连接耗尽句柄 - 日志中监控
"package too big"或"connection closed by protocol"类错误,这是攻击发生的信号
真正危险的不是超长字符串本身,而是你没意识到 TextProtocol 默认根本不拦它。











