簡體   English   中英

如何保護服務免受gzip炸彈的侵害?

[英]How to protect service from gzip bomb?

我有帶json的test.gzip文件

{"events": [
{"uuid":"56c1718c-8eb3-11e9-8157-e4b97a2c93d3",
"timestamp":"2019-06-14 14:47:31 +0000",
"number":732,
"user": {"full_name":"0"*1024*1024*1024}}]}

full_name包含1GB的0 ,壓縮文件大小〜1Mb

打開包裝時如何保護我的服務,以使我的記憶沒有結束?

func ReadGzFile(filename string) ([]byte, error) {
    fi, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer fi.Close()

    fz, err := gzip.NewReader(fi)
    if err != nil {
        return nil, err
    }
    defer fz.Close()

    s, err := ioutil.ReadAll(fz)
    if err != nil {
        return nil, err
    }
    return s, nil
}

func main() {
    b, err := ReadGzFile("test.gzip")
    if err != nil {
        log.Println(err)
    }
    var dat map[string]interface{}
    if err := json.Unmarshal(b, &dat); err != nil {
        panic(err)
    }
    fmt.Println(dat)
}

在這種情況下,輸出可能會破壞OOMKiller的服務

可以欺騙的是,壓縮后的大小可能大大小於允許的大小(您可以或希望處理的大小)。 在您的示例中,輸入約為1 MB,而未壓縮的大小約為1 GB。

在讀取未壓縮的數據時,應在達到合理限制后停止。 為了輕松做到這一點,您可以使用io.LimitReader()來指定希望讀取的最大字節數。 是的,您必須包裝解壓縮的流,而不是原始的壓縮流。

這是一個示例,看起來像:

limited := io.LimitReader(fz, 2*1024*1024)

s, err := ioutil.ReadAll(limited)

上面的示例將可讀數據限制為2 MB。 當解壓縮的數據超過此數量時會發生什么? io.Reader通過返回io.LimitReader()這是由一種方式io.LimitedReader )將報告io.EOF 這樣可以保護您的服務器免受攻擊,但是可能不是處理它的最佳方法。

既然您提到這是針對其余API的,那么更適合的解決方案將是類似的http.MaxBytesReader() 這會將通過的讀取器包裝起來,直到指定的限制為止,如果達到該限制,它將返回錯誤,還將錯誤發送回HTTP客戶端,並關閉基礎的讀取器。 如果http.MaxBytesReader()的默認行為不適合您,請檢查其源代碼,對其進行復制和修改,這相對簡單。 根據您的需要進行調整。

另請注意,您不應將所有內容(未壓縮的數據)讀入內存。 您可以將“受限閱讀器”傳遞給json.NewDecoder() ,在解碼輸入JSON時,該閱讀器將從給定閱讀器讀取。 當然,如果通過的受限閱讀器報告錯誤,則解碼將失敗。

不要將所有內容讀入內存。 如果可能,在流上進行操作。 在您的示例中,這是100%可能的:

func ReadGzFile(filename string) (io.ReadCloser, error) {
    fi, err := os.Open(filename)
    if err != nil {
        return nil, err
    }

    return gzip.NewReader(fi)
}

func main() {
    b, err := ReadGzFile("test.gzip")
    if err != nil {
        log.Println(err)
    }
    defer b.Close()
    var dat map[string]interface{}
    if err := json.NewDecoder(b).Decode(&dat); err != nil {
        panic(err)
    }
    fmt.Println(dat)
}

這種Decode方法具有副作用(可能會或可能不會理想),即忽略第一個有效JSON對象之后的流中的任何垃圾。 對於您而言,這似乎是一種好處。 在某些情況下,可能並非如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM