使用 Bash /dev/tcp 在不使用 Curl 的情况下发起 HTTP 请求
使用 Bash /dev/tcp 进行网络连接
Bash 可以直接打开 TCP 套接字,使您能够在不依赖 curl 或 wget 等外部工具的情况下通过网络发送和接收数据。这在精简的 Docker 容器或最小化环境中尤为有用,因为这些环境往往限制安装新软件包。
要执行一个基本的 HTTP GET 请求,请使用以下命令序列:
exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3
在此示例中,service 是主机名,8642 是端口。exec 3<> 命令打开到指定主机和端口的套接字,并将其分配给文件描述符 3。printf 命令发送原始 HTTP 请求,cat <&3 则读取套接字的响应,直到连接关闭为止。
处理头部和身份验证
若要添加额外的头部(例如 Authorization 令牌),请在结束 HTTP 请求的空行之前插入相应的头部行:
exec 3<>/dev/tcp/service/8642
printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3
cat <&3
技术实现与局限性
/dev/tcp 的本质
表面上看,/dev/tcp 并不是磁盘上的真实设备文件。它是 Bash 内部处理的重定向。当 Bash 遇到匹配 /dev/tcp/host/port 的路径时,会尝试使用 connect(2) 系统调用打开相应的 TCP 套接字。之所以采用这种设计,是因为没有标准的 Unix 系统拥有 /dev/tcp 或 /dev/udp 层级,避免与实际文件产生冲突。
关键限制
虽然在调试时非常强大,但与完整的 HTTP 客户端相比,此方法存在显著局限:
- 不支持 TLS/SSL:
/dev/tcp打开的是原始套接字,无法处理 HTTPS。要进行加密通信,需要使用openssl s_client等工具。 - **不进行 HTTP 解析:**Bash 不会解析 HTTP 协议,无法处理重定向、分块传输编码、压缩或重试等功能。它仅仅是发送和接收原始字节流。
- 连接管理:
Connection: close头部至关重要。若省略此头部,服务器可能会保持连接打开(HTTP/1.1 的默认行为),导致cat在等待更多数据时无限挂起。 - **Shell 兼容性:**这是 Bash 专有的特性,不符合 POSIX 标准。它在
dash(Debian 默认的/bin/sh)或zsh中不可用。使用此特性的脚本必须显式使用bash执行。 - **编译时要求:**该特性需要在 Bash 编译时通过
--enable-net-redirections标志启用。虽然大多数主流发行版默认包含,但某些极简或较旧的构建(包括部分历史 Debian 版本)可能未启用。
实际使用场景与替代方案
调试与安全
该技巧常用于环境受限的场景:
- **极简容器:**在剔除所有非必要二进制文件的镜像中检查健康端点。
- **渗透测试:**在 CTF 或安全审计中,当
curl与nc不可用时,用于建立初始 shell 或与本地 Web 服务器交互。 - **规避限制:**在安全策略禁止安装网络工具时,仍能与服务进行交互。
替代方法
根据可用工具的不同,其他方案可能更可靠:
- **Netcat (nc):**更强大的原始套接字交互工具。
- **Perl/Python:**使用 Perl 的
IO::Socket或 Python 的socket模块以编程方式处理网络请求。 - **nsenter:**如果宿主机上已安装
curl,可以使用nsenter进入容器的网络命名空间,从宿主机上下文执行curl。
"这就是我们在 2026 年都应该得到的内容,这也是我在面试时仍会让候选人解释 cookie 在 HTTP 协议中是如何表示的原因。" — @dennis16384