<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    protobuf生成Go代碼插件gogo/protobuf

    VSole2022-08-01 11:01:00

    從 JSON 開始

    談到序列化,大家最先想到的可能是 JSON 或者 XML,這兩種序列化協議都是基于文本的編碼方式進行數據傳輸。類似的還有 YAML 等。

    JSON 擁有許多優點,使之成為最廣泛使用的序列化協議之一。如 JSON 協議簡單,人眼可讀,序列化后十分簡潔且解析速度快。此外,JSON 具備 JavaScript 的先天性支持,被廣泛應用于 Web Browser 的應用場景中,并且是 Ajax 的事實標準協議。

    JSON 的適用場景比較多,典型應用場景包括:

    • 公司外部之間傳輸數據量相對較小,實時性要求相對低的服務
    • 基于 Web browser 的 Ajax 請求
    • 接口經常發生變化,并對可調式性要求較高的場景,例如移動 App 與服務端的通信

    然而,由于 JSON 本身的設計的一些特點,在一些場景下使用 JSON 仍然不是最優解。如:

    • 需要標準的 IDL ,增強參與各方業務約束的場景。由于 JSON 協議往往只能使用文檔的方式來進行約定,這可能會給調試帶來一些不便與不明確
    • 對性能和簡潔性有較高要求的場景。JSON 在一些語言中的序列化和反序列化需要采用反射機制,所以在性能要求特別高場景下可能不是最優解
    • 對于大數據量服務或持久化場景。JSON 進行序列化的額外空間開銷比較大,這也意味著較大的內存和磁盤開銷

    對于以上場景, 使用一些基于 IDL ,存儲方案為二進制存儲的序列化方案則更為合適, 如 ProtoBuf、Thrift、avro等。

    IDL: 參與通訊的各方需要對通訊的內容需要做相關的約定。為了建立一個與語言和平臺無關的約定,這個約定需要采用與具體開發語言、平臺無關的語言來進行描述。這種語言被稱為接口描述語言(IDL),采用IDL撰寫的協議約定稱之為IDL文件。

    什么是 Protobuf

    ProtoBuf 是 Protocol Buffers 的簡稱 ,是 Google 公司開源的一種語言無關、平臺無關、可擴展的序列化結構數據的方案,它可用于(數據)通信協議、數據存儲等。

    ProtoBuf 是上述場景中比較適用的序列化方案之一。ProtoBuf 非常靈活,高效,我們可以通過定義 IDL (在這里是proto)文件,然后使用生成的源代碼輕松的在各種數據流中使用各種語言進行編寫和讀取結構數據。甚至可以更新數據結構,而不破壞由舊數據結構編譯的已部署程序。

    上文提到,同類型的序列化方案還有 Thrift 和 Avro。其中 Thrift 并不僅僅是序列化協議,他被嵌入到 Thrift 框架中,這導致其很難和其他傳輸層協議共同使用。Avro 由于沒有成熟的 JS 實現,不適合 Web 環境, 也 導致其使用場景也比較有限。

    目前 gRPC 默認的序列化方式是 ProtoBuf。

    ProtoBuf 包含序列化格式的定義、各種語言的庫以及一個 IDL 編譯器。正常情況下需要我們定義 proto 文件,然后使用IDL 編譯器編譯成需要的語言。

    一個簡單的 proto 例子 

    syntax = "proto3";                // proto 版本,建議使用 proto3
    option go_package = "main/proto"; // 包名聲明符
    message SearchRequestParam {      // message 類型
      enum Type {                     // 枚舉類型
        PC = 0;
        Mobile = 1;
      }
      string query_text = 1;          // 字符串類型 | 后面的「1」為數字標識符,在消息定義中需要唯一
      int32 limit = 3;                // 整型
      Type type = 4;                  // 枚舉類型
    }
    message SearchResultPage {
      repeated string result = 1;     // 「repeated」表示字段可以重復任意多次(包括0次)
      int32 num_results = 2;
    }
    // test.proto
    

    代碼中的只是一些比較普通的字段定義,還有一些復雜的一些字段定義,如OneofMapReserved等可以參考官方文檔。

    生成 Go 代碼

    在 .proto 文件中定義好需要處理的結構化數據后,可以通過 protoc 工具,將 .proto 文件轉換為 C、C++、Golang、Java、Python 等多種語言的代碼。我們這里嘗試一下生成 Golang 語言代碼。

    首先需要安裝 protoc 工具

    # 下載安裝包 (Mac)
    $ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-osx-x86_64.zip
    # 解壓到 /usr/local 目錄下
    $ unzip protoc-3.15.6-osx-x86_64.zip -d protoc-3.15.6-osx-x86_64
    $ mv protoc-3.5.0-osx-x86_64/bin/protoc /usr/local/bin/protoc
    # 執行如下表示成功:
    $ protoc --version
    libprotoc 3.15.6
    

    然后安裝一個官方的生成 Golang 代碼的插件 protoc-gen-go

    $ go get -u github.com/golang/protobuf/protoc-gen-go
    

    現在在 proto文件所在目錄下執行以下命令以生成go文件

    $ protoc --go_out=. test.proto
    

    protoc 命令還可以使用-I參數指定搜索 import 的 proto 的文件夾。其他參數詳情可以參考官方文檔。

    我們可以在目錄下看到一個 test.pb.go 文件。其中主要結構體如下:

    type SearchRequestParam struct {
     state         protoimpl.MessageState
     sizeCache     protoimpl.SizeCache
     unknownFields protoimpl.UnknownFields
     QueryText string                  `protobuf:"bytes,1,opt,name=query_text..."`    
     Limit     int32                   `protobuf:"varint,3,opt,name=limit,proto3"...."`                           
     Type      SearchRequestParam_Type `protobuf:"varint,4,opt,name=type,proto3..."`
    }
    type SearchResultPage struct {
     state         protoimpl.MessageState
     sizeCache     protoimpl.SizeCache
     unknownFields protoimpl.UnknownFields
     Result     []string `protobuf:"bytes,1,rep,name=result,proto3...."`
     NumResults int32    `protobuf:"varint,2,opt,name=num_results,json=numResults,proto3..."`
    

    接下來,就可以在項目代碼中直接使用了。

    gogo/protobuf 是什么

    在上文中,我們安裝了一個「生成 Golang 代碼的插件 protoc-gen-go」,這個插件其實是 golang 官方提供的 一個Protobuf api 實現。而我們的主角gogo/protobuf是基于 golang/protobuf 的一個增強版實現。

    gogo 庫基于官方庫開發,增加了很多的功能,包括:

    • 快速的序列化和反序列化
    • 更規范的Go數據結構
    • goprotobuf 兼容
    • 可選擇的產生一些輔助方法,減少使用中的代碼輸入
    • 可以選擇產生測試代碼和 benchmark 代碼
    • 其它序列化格式

    目前很多知名的項目都在使用該庫,如 etcd、k8s、tidb、docker swarmkit 等。

    gogo/protobuf 如何使用

    https://github.com/gogo/protobuf 根目錄下我們可以看到有很多文件夾,其中「protoc-gen」為前綴的為生成代碼的插件,其他「proto」、「protobuf」、「gogoproto」等為庫文件。

    gogo 庫目前有三種生成代碼的方式

    • gofast: 速度優先,但此方式不支持其它 gogoprotobuf 的擴展選項。
    $ go get github.com/gogo/protobuf/protoc-gen-gofast
    $ protoc --gofast_out=. myproto.proto
    
    • gogofastgogofastergogoslick: 更快的速度、會生成更多的代碼。
    $ go get github.com/gogo/protobuf/proto
    $ go get github.com/gogo/protobuf/{binary} //protoc-gen-gogofast、protoc-gen-gogofaster 、protoc-gen-gogoslick 
    $ go get github.com/gogo/protobuf/gogoproto
    $ protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --{binary}_out=. myproto.proto // 這里的{binary}不包含「protoc-gen」前綴
    
    • gogofast類似gofast,但是會引入 gogoprotobuf 庫。
    • gogofaster類似gogofast,但是不會產生XXX_unrecognized類的指針字段,可以減少垃圾回收時間。
    • gogoslick類似gogofaster,但是會增加一些額外的stringgostringequal method等。
    • protoc-gen-gogo: 最快的速度,最多的可定制化
    $ go get github.com/gogo/protobuf/proto
    $ go get github.com/gogo/protobuf/jsonpb
    $ go get github.com/gogo/protobuf/protoc-gen-gogo
    $ go get github.com/gogo/protobuf/gogoproto
    
    • 可以通過擴展選項高度定制序列化。

    gogo/protobuf 提供了非常多的擴展選項,以便在產生代碼的時候進行更多的控制。上文提到的擴展選項這里有一個全面的介紹:extensions,擴展選項里主要包含一些生成快速序列化反序列化代碼的可選項、生成更規范的Golang 數據結構的可選項、goprotobuf 兼容的可選項,一些產生輔助方法的可選項、產生測試代碼和benchmark 的可選項,還可以增加 jsontag 等。

    有同學對以上多個生成方式的序列化性能做了一些壓測,在一般需求下,性能差距并不是很大,protoc-gen-gofast方式基本可以滿足大多數場景。

    最后,生成的 go 語言代碼在項目中使用就非常簡單了,一般只需要使用proto.Marshal,proto.Unmarshal 方法就可以了,下面是一個例子:

    package main
    import (
     "fmt"
     "log"
     zaproto "git.xxxxx.com/data/za-proto/proto"
     "github.com/gogo/protobuf/proto"
    )
    func main() {
     req := &zaproto.SearchRequestParam{
      QueryText: "xxxxxx",
      Limit:     10,
      Type:      zaproto.SearchRequestParam_PC,
     }
     data, err := proto.Marshal(req)
     if err != nil {
      log.Fatal("Marshal err : err")
     }
     // send data
     fmt.Println(string(data))
     var respData []byte
     var result = zaproto.SearchResultPage{}
     if err = proto.Unmarshal(respData, &result); err == nil {
      fmt.Println(result)
     } else {
      log.Fatal("Unmarshal err : err")
     }
    }
    
    序列化protobuf
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    protobuf協議逆向解析
    2021-09-23 18:43:30
    在app抓包的過程中,我們會發現有些app的數據也是存在加密的,抓到的數據是一堆亂碼。無法來解析數據。
    0x0概述 近年來,老式勒索病毒依舊活躍,而新型勒索病毒花樣百出,深信服安全云腦就捕獲到一款具有“地方特色”的勒索病毒,其加密后綴為.beijing。及lock_XXX文件; 勒索提示文檔: 遍歷目錄下所有文件; 打開待加密文件; 重命名為*.beijing; 使用AES算法加密; 文件末尾寫入二次加密后的AES密鑰 完成加密后自刪除。
    JSON 擁有許多優點,使之成為最廣泛使用的序列化協議之一。此外,JSON 具備 JavaScript 的先天性支持,被廣泛應用于 Web Browser 的應用場景中,并且是 Ajax 的事實標準協議。這種語言被稱為接口描述語言,采用IDL撰寫的協議約定稱之為IDL文件。
    近日有研究人員發現,MMRat新型安卓銀行惡意軟件利用protobuf 數據序列化這種罕見的通信方法入侵設備竊取數據。
    Dubbo Kryo & FST RCE
    2022-11-25 15:31:47
    影響版本Dubbo 2.7.0 to 2.7.8Dubbo 2.6.0 to 2.6.9Dubbo all 2.5.x versions 環境復現 安裝zookeeper和dubbo-samples,用idea打開dubbo-samples-api,然后修改其中的pom.xml如下: 注意,dubbo-common必須 ≤2.7.3版本。在Dubbo<=2.7.3中fastjson的版本≤1.2.46 ,這也是我們這個洞的利用點,不過這里復現使用的更高版本所以需要添加依賴, com.alibabagroupId> fastjsonartifactId> 1.2.46version>dependency>. 案例漏洞分析 FTS反序列化FTS反序列化發生在RPC協議反序列化
    隨著企業云原生化進程的推進,系統架構也開始從傳統架構向微服務架構轉型。服務之間的API調用也從RESTful接口轉向gRPC、GraphQL等新型的更高效的協議接口。新技術帶來便利的同時,也為內存馬攻擊技術帶來了新的攻擊面。
    GraphFuzz是一個用于構建結構感知、庫API模糊器的實驗性框架。
    最近在學習Android APP客戶端漏洞挖掘過程中,對Android APP端漏洞挖掘做了一個基本的梳理總結本節主要是在介紹Android APP漏洞挖掘過程中,使用常見的Android漏洞挖掘工具的安裝和使用辦法,幫助Android漏洞挖掘人員提供便利。本文里面一部分的介紹采摘與網絡博客,大家可以點擊對應的網址進行查看。
    Java安全中Groovy組件從反序列化到命令注入及繞過和在白盒中的排查方法
    最近兩個月我一直在做拒絕服務漏洞相關的時間,并收獲了Spring和Weblogic的兩個CVE但DoS漏洞終歸是雞肋洞,并沒有太大的意義,比如之前有人說我只會水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd師傅聊天
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类