Skip to content

proposal: net/http: omit contents of Authorization / Cookies header in string output #26551

Closed
@adamdecaf

Description

@adamdecaf

Consider the following code:

import (
	"fmt"
	"net/http"
)

func main() {
	req, err := http.NewRequest("GET", "https://example.com", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "secret")
	fmt.Println(req)
}

// Prints
// &{GET https://example.com HTTP/1.1 %!s(int=1) %!s(int=1) map[Authorization:[secret]] <nil> %!s(func() (io.ReadCloser, error)=<nil>) %!s(int64=0) [] %!s(bool=false) example.com map[] map[] %!s(*multipart.Form=<nil>) map[]   %!s(*tls.ConnectionState=<nil>) %!s(<-chan struct {}=<nil>) %!s(*http.Response=<nil>) <nil>}

This type of code is fairly common, but can lead to exposing the Authorization header (or Cookie). Instead we should opt to not expose these sensitive headers by default. There's similar precedent for masking userinfo passwords from urls in #24572.

We need to keep req.Header.Get("Authorization") unchanged as servers read the auth blob that way. Instead I propose we add:

func (h Header) String() string 

As part of the implementation we might need to specify a format for headers. Looking through various Printf encodings gives us:

verb output
%s map[Authorization:[secret]]
%#v Header:http.Header{"Authorization":[]string{"secret"}}
%+v Header:map[Authorization:[secret]]

With a fixed encoding we are able to write the formatter and always mask these sensitive headers.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions