Go a ignorování HTTP_PROXY

Go, Bezpečnost

Standardní HTTP knihovna v Go čte environment variables HTTP_PROXY či HTTPS_PROXY a NO_PROXY. Jsou ale případy, kdy se správně nastavena hodnota ignoruje. Někdy zase není žádoucí, aby si uživatel mohl proxy nastavit a tyto hodnoty by se měly ignorovat.

Go a ignorování HTTP_PROXY

Article in English can be found on dev.to/arxeiss/ignoring-httpproxy-environment-vars-in-go-53bn

Pomocí proxy lze obejít ochranu firewallu, pokud je z vnitřní sítě omezen přístup na některé služby. Proxy se ale také často využívá pro inspekci provozu při vývoji. Například při použití nástroje HTTP Toolkit je vytvořen lokální proxy server. Veškerý provoz přes něj lze poté prohlížet.

Pokud program napsaný v Go používá standardní knihovnu net/http, budou automaticky přečteny proměnné HTTP(S)_PROXY a NO_PROXY a podle toho bude komunikace probíhat napřímo, nebo přes zmíněný server. Co když ale vývojář chce, aby si uživatel nemohl vůbec proxy nastavit?
Níže je ukázkový kód, který provádí GET požadavek a lze si na něm vše jednoduše nasimulovat.

func main() {
	fmt.Println(os.Getenv("HTTP_PROXY"))
	client := &http.Client{}
	resp, err := client.Get("http://localhost:8090/vm/1")
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(body))
}

Hodnota v proměnné HTTP_PROXY je ignorována

V kódu výše je prvně vypsán obsah proměnné HTTP_PROXY a následně zavolán GET požadavek. Pokud ale někdo používá například dříve zmíněný HTTP Toolkit a proxy nastavil správně, nic se nestane. A to i přesto, že první výpis proměnnou vypíše správně. Hlavní důvodem je použití domény localhost nebo 127.x.x.x. Naštěstí je toto chování možné velmi jednoduše obejít.

Stačí si nastavit v /etc/hosts nebo C:\Windows\System32\drivers\etc\hosts přesměrování další domény na localhost přidáním záznamu 127.0.0.1 localserver.loc a poté změnit kód výše. Více o souboru hosts je v článku Jak využít soubor hosts.

resp, err := client.Get("http://localserver.loc:8090/vm/1")

Jedná se o zdokumentované chování, jenže trochu hlouběji v kódu. Konkrétně v souboru opensource.google/x/net/http/httpproxy/proxy.go řádek 118.

HTTPS_PROXY funguje pro šifrované HTTPS spojení. Jenže poté kód může vracet chybu, že nebylo možné ověřit certifikát. V takovém případě je buď nutné upravit kód nebo si přidat HTTPS certifikát dané proxy tak, aby bylo možné jej ověřit.

Jak zakázat čtení PROXY proměnných

Pomocí proměnné NO_PROXY lze nastavit, pro které domény se má HTTP_PROXY či HTTPS_PROXY ignorovat. Může jich být více oddělených čárkou, nebo lze použít NO_PROXY=* pro všechny. Jenže co když vývojář chce, aby proxy nešlo vůbec nastavit? Pak se musí vytvořit vlastní Transport pro HTTP klienta. A to buď specifikovat vlastní atributy, nebo použít defaultní a vymazat proxy.

transport := http.DefaultTransport
transport.(*http.Transport).Proxy = nil
client := &http.Client{
	Transport: transport,
}

Vlastní zkušenosti s Go, proxy a standardní knihovnou net/http můžete sdílet v komentářích.

K tomuto článku již není možné přidávat další komentáře