Go, в чём суть реализации уязвимости c помощью перестановки `defer response.Body.Close()`?

Есть такой обработчик, как я понимаю реализация уязвимости связана с тем, что тело ответа закрывается до проверки ошибки. Но я не очень понимаю почему это должно работать, ведь тело всё равно закрыто, не зависимо до ли после проверки.

func HandleRequest(client http.Client, request *http.Request)
(*http.Response, error) {
    response, err := client.Do(request)
    defer response.Body.Close()
    if err != nil {
        return nil, err
    }
}

Мне известно, что полное отсутствие строки defer response.Body.Close() приводит к гарантированным проблемам, но не могу придумать как протестировать выше упомянутую уязвимость


Ответы (1 шт):

Автор решения: Pak Uula

defer response.Body.Close() означает, что response.Body.Close() должно быть выполнено в точке выхода из функции. Ни о каком закрытии тела до проверки ошибки речь не идёт.

Проблема здесь в другом - в случае ошибки response может быть nil, и выполнение отложенной инструкции в ветке if err != nil {... return ...} таком случае приведет к панике из-за обращения к нулевому указателю.

panic: runtime error: invalid memory address or nil pointer dereference

Пример: https://go.dev/play/p/vEiUFPgLYxf

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
)

func main() {
    client := http.Client{}
    url, _ := url.Parse("https://no.such.host")
    request := &http.Request{
        Method: "GET",
        URL:    url,
    }

    response, err := client.Do(request)
    defer response.Body.Close()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Request failed: %s\n", err.Error())
    }

    io.Copy(os.Stdout, response.Body)

}
→ Ссылка