各位观众老爷,大家好!今天咱们来聊聊 gRPC-Web 的那些事儿,尤其是关于如何扒开它的外衣,看看里面到底装了些啥。如果你曾经被 gRPC-Web 搞得头晕脑胀,不知道怎么解密它的流量,逆向它的协议,那这篇文章绝对能帮到你。
前言:啥是 gRPC-Web?
简单来说,gRPC-Web 就是 gRPC 的一个变种,专门为浏览器环境量身定制。由于浏览器天然的限制,无法直接使用标准的 gRPC 协议,所以 Google 大佬们搞出了 gRPC-Web 这么个东西。它通过一个 Envoy 之类的代理服务器,将浏览器发出的 HTTP/1.1 请求转换成标准的 gRPC 请求,然后再发送给后端的 gRPC 服务。
一、为什么要解密 gRPC-Web 流量?
你可能会问,好好的流量,干嘛要解密?原因有很多:
- 调试: 当你的前端和后端联调出现问题时,解密流量可以让你清晰地看到客户端发了什么,服务端回了什么,从而快速定位问题。
- 安全分析: 如果你需要分析 gRPC-Web 应用的安全性,解密流量是必不可少的。你可以检查客户端是否发送了敏感信息,服务端是否返回了不安全的数据等等。
- 协议逆向: 假设你想要开发一个 gRPC-Web 客户端,但没有官方文档,或者官方文档不全,那解密流量就是你了解协议细节的唯一途径。
- 渗透测试: 作为一名光荣的渗透测试工程师,解密 gRPC-Web 流量可以帮助你发现潜在的安全漏洞。
二、gRPC-Web 流量长啥样?
gRPC-Web 流量本质上是 HTTP/1.1 请求,只不过它的 Body 部分是用 Protobuf 编码的。我们可以用 Wireshark、Fiddler 或者 Charles 这些抓包工具来捕获流量。
一个典型的 gRPC-Web 请求看起来大概是这个样子:
POST /your.service.YourMethod HTTP/1.1
Host: your.domain.com
Content-Type: application/grpc-web+proto
Content-Length: 30
x00x00x00x00x0ax0ax08x08x01x10x02x18x03
响应大概是这样:
HTTP/1.1 200 OK
Content-Type: application/grpc-web+proto
Trailer: Grpc-Status, Grpc-Message
x00x00x00x00x08x0ax06x08x04x10x05x18x06
Grpc-Status: 0
注意几个关键点:
- Content-Type: 必须是
application/grpc-web+proto
,或者application/grpc-web-text+proto
(base64 编码)。 - POST 请求: gRPC-Web 通常使用 POST 请求。
- 请求路径: 请求路径通常是
/package.Service/Method
这种形式。 - Body: 请求和响应的 Body 部分都是 Protobuf 编码的数据。
- Trailer: 响应的 Trailer 部分包含 gRPC 的状态码和错误信息。
三、解密 gRPC-Web 流量的步骤
解密 gRPC-Web 流量,主要分两步:
- 找到
.proto
文件: 这是解密的关键,没有.proto
文件,一切都是白搭。.proto
文件定义了 gRPC 服务的接口和消息格式。 - 使用工具解码 Protobuf 数据: 有了
.proto
文件,就可以使用工具将 Protobuf 编码的数据解码成可读的 JSON 格式。
3.1 找到 .proto
文件
找到 .proto
文件,有以下几种方法:
- 询问开发者: 最直接的方法,直接问开发人员要。
- 从源代码中获取: 如果你能拿到 gRPC 服务的源代码,那
.proto
文件肯定就在里面。 - 反编译: 如果服务端是编译型的语言(比如 Go、Java),你可以尝试反编译服务端程序,从中提取
.proto
文件。 - 猜测: 如果以上方法都行不通,那就只能靠猜了。根据接口名称和参数类型,猜测
.proto
文件的内容。这种方法比较困难,但也不是完全不可能。
3.2 解码 Protobuf 数据
有了 .proto
文件,就可以使用工具来解码 Protobuf 数据了。常用的工具有:
protoc
编译器: Google 官方提供的 Protobuf 编译器,可以将.proto
文件编译成各种语言的代码。同时,它也可以用来解码 Protobuf 数据。protoc-gen-decode
插件: 一个protoc
插件,可以将 Protobuf 数据解码成 JSON 格式。比直接用protoc
方便。grpcurl
工具: 一个命令行工具,可以发送 gRPC 请求,并显示响应结果。它也支持解码 Protobuf 数据。- 在线 Protobuf 解码器: 网上有很多在线的 Protobuf 解码器,可以直接将 Protobuf 数据粘贴到网页上,然后解码成 JSON 格式。
四、实战演练:使用 protoc-gen-decode
解码 gRPC-Web 流量
咱们以 protoc-gen-decode
为例,演示如何解码 gRPC-Web 流量。
4.1 安装 protoc
和 protoc-gen-decode
首先,你需要安装 protoc
编译器。安装方法根据你的操作系统而定,可以参考 Protobuf 官方文档。
然后,安装 protoc-gen-decode
插件:
go install github.com/jhump/protoc-gen-decode@latest
确保 $GOPATH/bin
目录在你的 PATH
环境变量中。
4.2 准备 .proto
文件
假设我们有一个简单的 gRPC 服务,定义如下:
syntax = "proto3";
package your.service;
service YourService {
rpc YourMethod (YourRequest) returns (YourResponse);
}
message YourRequest {
int32 id = 1;
string name = 2;
bool enabled = 3;
}
message YourResponse {
int32 code = 1;
string message = 2;
}
将以上内容保存为 your.proto
文件。
4.3 抓取 gRPC-Web 流量
使用 Wireshark 或者 Fiddler 抓取 gRPC-Web 请求和响应的 Body 部分。假设我们抓到的请求 Body 是:
x00x00x00x00x0ax0ax08x08x01x10x02x18x03
响应 Body 是:
x00x00x00x00x08x0ax06x08x04x10x05x18x06
4.4 解码 Protobuf 数据
使用以下命令解码请求 Body:
protoc --decode_json=your.service.YourRequest --proto_path=. your.proto < request.bin
其中,request.bin
文件包含请求 Body 的内容。
使用以下命令解码响应 Body:
protoc --decode_json=your.service.YourResponse --proto_path=. your.proto < response.bin
其中,response.bin
文件包含响应 Body 的内容。
如果一切顺利,你将会看到类似以下的 JSON 输出:
请求:
{
"id": 1,
"name": "2",
"enabled": true
}
响应:
{
"code": 4,
"message": "5"
}
4.5 处理 gRPC-Web 帧格式
gRPC-Web 使用一种特殊的帧格式,需要在解码之前进行处理。每个 gRPC-Web 消息都包含一个或多个帧。每一帧的格式如下:
字段 | 大小 (bytes) | 说明 |
---|---|---|
Compression Flag | 1 | 如果设置为 1,则表示消息体被压缩。通常使用 gzip 压缩。 |
Length | 4 | 消息体的长度 (不包括 Compression Flag 和 Length 字段)。 |
Message | Length | 消息体,通常是 Protobuf 编码的数据。 |
所以,我们需要跳过 Compression Flag 和 Length 字段,才能得到真正的 Protobuf 数据。在上面的例子中,x00x00x00x00x0ax0ax08x08x01x10x02x18x03
这段数据,前 5 个字节 x00x00x00x00x0a
是帧头,后面的 x0ax08x08x01x10x02x18x03
才是真正的 Protobuf 数据。
我们可以使用 dd
命令来提取 Protobuf 数据:
dd if=request.bin bs=1 skip=5 of=protobuf_data.bin
然后再使用 protoc
命令解码 protobuf_data.bin
文件。
五、处理 Base64 编码的 gRPC-Web 流量
如果 gRPC-Web 请求的 Content-Type
是 application/grpc-web-text+proto
,那么请求和响应的 Body 部分会被 Base64 编码。你需要先将 Base64 编码的数据解码,然后再进行 Protobuf 解码。
可以使用 base64
命令来解码 Base64 编码的数据:
base64 -d < base64_data.txt > binary_data.bin
然后再使用 protoc
命令解码 binary_data.bin
文件。
六、代码示例:使用 Python 解码 gRPC-Web 流量
下面是一个使用 Python 解码 gRPC-Web 流量的示例代码:
import base64
import struct
from google.protobuf import json_format
from google.protobuf import descriptor_pb2
from google.protobuf import message_factory
def decode_grpc_web(proto_file, message_type, data):
"""
解码 gRPC-Web 流量。
Args:
proto_file: .proto 文件的路径。
message_type: 消息类型,例如 "your.service.YourRequest"。
data: gRPC-Web 流量的 Body 部分。
Returns:
解码后的 JSON 数据。
"""
# 1. 解析 .proto 文件
with open(proto_file, "rb") as f:
proto_content = f.read()
file_descriptor_set = descriptor_pb2.FileDescriptorSet()
file_descriptor_set.ParseFromString(proto_content)
# 2. 创建 MessageFactory
factory = message_factory.MessageFactory(file_descriptor_set.file)
# 3. 获取消息类
message_class = factory.GetPrototype(message_type)
if message_class is None:
raise ValueError(f"Message type '{message_type}' not found in proto file.")
# 4. 处理 gRPC-Web 帧格式
compression_flag = data[0]
length = struct.unpack(">I", data[1:5])[0]
protobuf_data = data[5: 5 + length]
# 5. 解码 Protobuf 数据
message = message_class()
message.ParseFromString(protobuf_data)
# 6. 转换为 JSON
json_data = json_format.MessageToJson(message)
return json_data
# 示例用法
if __name__ == "__main__":
proto_file = "your.proto"
message_type = "your.service.YourRequest"
grpc_web_data = b"x00x00x00x00x0ax0ax08x08x01x10x02x18x03" # 替换为你的 gRPC-Web 数据
try:
json_data = decode_grpc_web(proto_file, message_type, grpc_web_data)
print(json_data)
except Exception as e:
print(f"Error decoding gRPC-Web data: {e}")
七、总结与注意事项
.proto
文件是关键: 没有.proto
文件,几乎不可能解密 gRPC-Web 流量。- 注意 gRPC-Web 帧格式: 需要跳过帧头才能得到真正的 Protobuf 数据。
- 处理 Base64 编码: 如果
Content-Type
是application/grpc-web-text+proto
,需要先解码 Base64 数据。 - 错误处理: 解码 Protobuf 数据时,可能会出现各种错误,比如
.proto
文件不正确,消息类型不存在等等。需要做好错误处理。 - 加密: 如果 gRPC-Web 使用了 TLS 加密,你需要先解密 TLS 流量,才能看到 gRPC-Web 的内容。可以使用 Wireshark 或者 Fiddler 来解密 TLS 流量。
八、进阶技巧:使用 Burp Suite 插件进行 gRPC-Web 渗透测试
Burp Suite 是一款强大的 Web 应用安全测试工具。有一些 Burp Suite 插件可以帮助你进行 gRPC-Web 渗透测试。
- protobuf-decoder: 可以自动解码 Protobuf 数据,并显示成可读的 JSON 格式。
- grpc-burp-plugin: 可以发送 gRPC 请求,并显示响应结果。
这些插件可以大大提高你的 gRPC-Web 渗透测试效率。
九、实际案例:一个 gRPC-Web 漏洞挖掘的故事
曾经有位安全研究员,通过解密某个 gRPC-Web 应用的流量,发现了一个SQL注入漏洞。这个应用的 .proto
文件中,有一个接口接受用户输入的字符串作为参数,然后直接将这个字符串拼接到 SQL 查询语句中,导致了SQL注入漏洞。
这个案例告诉我们,即使是使用了 gRPC-Web 这种看似复杂的协议,也仍然可能存在传统的 Web 应用安全漏洞。
十、Q&A 环节
现在是大家提问的时间,有什么关于 gRPC-Web 解密和逆向的问题,都可以问我。我会尽力解答。
问: 如果我没有 .proto
文件,就真的没法解密 gRPC-Web 流量了吗?
答: 也不是完全没戏。你可以尝试猜测 .proto
文件的内容,或者使用一些高级的逆向技术来分析 gRPC-Web 应用。但这需要很强的技术功底和大量的耐心。所以,还是尽量找 .proto
文件吧。
问: gRPC-Web 流量解密会不会侵犯用户隐私?
答: 这是一个非常重要的问题。在解密 gRPC-Web 流量之前,一定要确保你获得了用户的授权,并且遵守相关的法律法规。如果你没有获得用户的授权,解密流量是违法的。
问: 除了 protoc-gen-decode
,还有没有其他好用的 Protobuf 解码工具?
答: 当然有。grpcurl
也是一个不错的选择。它是一个命令行工具,可以发送 gRPC 请求,并显示响应结果。它也支持解码 Protobuf 数据。另外,网上也有很多在线的 Protobuf 解码器,可以直接将 Protobuf 数据粘贴到网页上,然后解码成 JSON 格式。
结束语
好了,今天的 gRPC-Web 流量解密与协议逆向讲座就到这里。希望这篇文章能够帮助你更好地理解 gRPC-Web,并在实际工作中应用这些技术。记住,技术是把双刃剑,一定要合理使用,遵守法律法规。
下次有机会,我们再聊聊其他的技术话题。祝大家工作顺利,生活愉快!