GoSuda

Jak naučit váš program v Go mluvit jako Chrome

By Lemon Mint views ...

Pokud jste kdy cestovali do zahraničí a objednali kávu frází, která vypadala jako z učebnice, znáte ten pohled, jakým na vás barista shlédne. Vaše gramatika je v pořádku. Každé slovo se nachází ve slovníku. A přesto během půl sekundy všichni v kavárně poznají, že jste z jiného města.

Standardní HTTP klient v Go má trochu podobný problém. Je to výborná výchozí volba: spolehlivý, čistý a připravený na vážnou práci hned po instalaci. Když ale váš program naváže spojení se serverem, nepochybně připomíná program napsaný v Go. Většinou to nikomu nevadí. Některé webové stránky, CDN a testovací prostředí však pozorně sledují, kdo jim klepe na dveře, a chovají se výrazně odlišně podle toho, jakého klienta si myslí, že mají před sebou.

Proto jsme vytvořili gosuda.org/chromenet. Místo toho, aby se standardní klient v Go učil věrohodně napodobovat prohlížeč, umožňuje chromenet programu v Go komunikovat s webem pomocí stejného síťového jádra, jaké používá Google Chrome, tedy vlastního síťového kódu projektu Chromium. Ať už ověřujete, jak vaše testovací prostředí zachází s provozem z prohlížeče, nebo komunikujete s webem za náročným CDN, komunikace přes jádro Chrome odstraní celou vrstvu nejistoty.

Pro použití nemusíte přepisovat svou aplikaci. Ve vašem kódu funguje jako přímá náhrada za http.Transport. Nadále používáte http.Client stejně jako dosud a chromenet se postará o komunikaci na nižší úrovni.

Chcete-li vyzkoušet nejnovější verzi, nainstalujte ji pomocí go get:

1go get gosuda.org/chromenet@v0.2.10157081033800

Poté předejte jeho transport svému klientovi:

1client := http.Client{
2	Transport: chromenet.NewTransport(chromenet.Options{}),
3}

S touto verzí prochází celá škála moderního webového provozu jádrem Chrome. Nyní zahrnuje běžné webové požadavky, WebSocket a WebTransport. Dřívější verze zpracovávaly správně pouze běžné požadavky, zatímco WebSocket a WebTransport byly pouze náhradní řešení. To znamenalo, že vaše úvodní pozdrav u vchodu zněl jako Chrome, ale pokud jste přešli na jiný způsob komunikace, vaše převlek mohl prasknout. Tato verze tato náhradní řešení nahrazuje skutečnými implementacemi.

Počkejte, pokud používáme vlastní síťový kód projektu Chromium, znamená to, že se váš tichý build v Go promění v rozsáhlý problém s C kompilátorem? Naštěstí ne. Váš kód v Go zůstává čistým Go, bez cgo a bez potřeby C kompilátoru.

Místo toho, aby chromenet vkládal kód prohlížeče přímo do vaší binárky, spouští jádro jako malý samostatný program vedle vašeho programu v Go. Představte si to jako najmutí plynule mluvícího místního tlumočníka, který kráčí vedle vás, místo abyste se pokoušeli přestavět vlastní hlasivky. Protože jádro běží v tomto samostatném programu, pád uvnitř něj nemůže shodit vaši službu.

Jak funguje chromenet: váš program v Go požádá malý pomocný program, který spouští síťové jádro Chromia a komunikuje s webem

Váš program v Go zůstává čistým Go, zatímco malý pomocný program přenáší provoz přes síťové jádro Chromia.

Ani na vaší pracovní stanici, ani na serverech nemusíte nic dalšího instalovat. Binárky jádra pro Linux, macOS a Windows, a to jak pro architekturu Intel/AMD, tak pro ARM, jsou přímo součástí modulu Go a před spuštěním se ověřují.

Distribuce binárních souborů uvnitř modulu logicky vyvolává otázku pro každého, komu záleží na důvěryhodnosti, a chtěli jsme na ni dát jednoduchou odpověď. Binárky jsou sestavovány reprodukovatelným způsobem z konkrétního vydání Chromia, aktuálně Chromium 157, takže je kdokoli může znovu sestavit a získat přesně stejné bajty, a každé vydání je ověřeno službou GitHub. Aby byl projekt v krocích s vývojem prohlížečů bez ruční práce, plánovaná úloha sleduje stabilní kanál Chromia a při vydání nového Chrome automaticky aktualizuje verzi.

Co je uTLS?

Pokud jste se dříve pokoušeli, aby váš klient v Go vypadal jako prohlížeč, pravděpodobně jste narazili na uTLS. Je to pěkné dílo: knihovna v Go, která umožňuje upravit úplně první zprávu zabezpečeného spojení tak, aby připomínala Chrome, Firefox nebo cokoli jiného, co si zvolíte. Je malá, čistě v Go a vedle vašeho programu neběží nic dalšího.

Háček spočívá v tom, jak daleko sahá tento převlek. uTLS pokrývá handshake, tedy prvních několik vět konverzace. Vše ostatní si stále musíte vybudovat sami: vrstvu HTTP/2 je nutné ručně zapojit a vyladit, HTTP/3 je samostatné dobrodružství a WebSocket nebo WebTransport vyžadují ještě více lepení. Presety Chrome jsou navíc kopie, takže je někdo musí udržovat aktuální pokaždé, když Chrome změní své zvyklosti. Je to trochu jako napodobit něčí přízvuk, zatímco zbytek jeho řeči těla vás stále prozrazuje.

chromenet jde opačnou cestou. Chrome nenapodobuje, ale nechá jeho vlastní jádro, aby mluvilo za něj, takže handshake, způsob opětovného použití spojení, přechody protokolů i transporty pocházejí z jednoho místa a mění se společně, když se mění Chromium.

Kompromis je otevřeně přiznán. uTLS je lehčí a umožňuje vytvořit jakýkoli pozdrav, který si dokážete představit, zatímco chromenet přináší pomocný program o velikosti 25 MB a poskytuje chování Chrome namísto vlastního. Pokud chcete minimální závislost a plnou kontrolu nad handshake, uTLS je stále skvělou volbou.

Každý návrh má své kompromisy a chceme zde být otevření ohledně limitů. Zabalit skutečné síťové jádro prohlížeče není nic malého: každá binárka jádra má přibližně 25 MB. Na macOS nejsou binárky notarizovány. A na Linuxu váš systém potřebuje glibc 2.31 nebo novější. Pokud těmto hranicím vaše prostředí vyhovuje, získáte skutečnou síťovou komunikaci Chrome výměnou jediného pole transportu.

Projekt najdete na adrese github.com/gosuda/chromenet. Pokud znáte jeho sesterské projekty v open source rodině gosuda, gosuda.org/hqq a gosuda.org/sqlite3, bude vám jejich duch povědomý: převzít schopné a těžké nástroje z širšího softwarového světa a učinit je plně domácími v čistém Go.

Pokud tedy sáhnete po uTLS, protože potřebujete, aby váš program v Go zněl jako prohlížeč, zkuste chromenet. Může být dobrou alternativou k uTLS, zejména když potřebujete více než požadavky HTTPS: HTTP/2, HTTP/3, WebSocket i WebTransport procházejí stejným jádrem Chrome, bez lepicího kódu na vaší straně.