🆕 blog! “I made a mistake in verifying HTTP Message Signatures”
It's never great to find out you're wrong, but that's how learning and personal growth happens. HTTP Message Signatures are hard1. There are lots of complex parts and getting any aspect wrong means certain death2. In a previous post, I wrote A simple(ish) guide to verifying …
#HTTP content negotiation has some unwritten rules for images. Accept: image/png, */* technically allows image/avif, but that’s not a wise interpretation.
Except what a caching proxy is supposed to do when the origin only sends AVIF?
New PC who this! Gave the @reactphp#HTTP Hello World a quick benchmark, clocks in at nearly 70K requests per second with 100 concurrent keep alive connections on a single #PHP process:
Une explication détaillée de HTTP3. La principale différence est qu'il utilise UDP + QUIC + TLS au lieu de TCP + TLS.
QUIC vise à moderniser et remplacer TLS, mais pour garder une compatibilité maximale avec les équipements réseau (routeurs, firewalls, etc.) UDP est nécessaire.
It’s bloody 2024, think we can agree on either wget or curl being installed by default on every freaking operating system by now so shell scripts can have a guaranteed way of carrying out http requests?
I mean it’s been about 35 years. I think it’s about time.
🆕 blog! “A simple(ish) guide to verifying HTTP Message Signatures in PHP”
Mastodon makes heavy use of HTTP Message Signatures. They're a newish almost-standard which allows a server to verify that a request made to it came from the person who sent it. This is a quick example to show how to verify these signatures using P…
I'm trying to get my head round HTTP Signatures as they're used extensively in the Fediverse. Conceptually, they're relatively straightforward. You send me a normal HTTP request. For example, you want to POST something to https://example.com/data You send me these headers: POST /data Host: example.com Date: Sa…
I'm trying to get my head round HTTP Signatures as they're used extensively in the Fediverse.
Conceptually, they're relatively straightforward.
You send me a normal HTTP request. For example, you want to POST something to https://example.com/data
You send me these headers:
POST /dataHost: example.comDate: Sat, 24 Feb 2024 14:43:48 GMTAccept-Encoding: gzipDigest: SHA-256=aaC57TDzM0Wq+50We2TkCsdMDvdqON92edg7KI+Hk8M=Content-Type: application/activity+jsonSignature: keyId="https://your_website.biz/publicKey",algorithm="rsa-sha256",headers="(request-target) host date digest content-type",signature="JGQ53kEoIiMWRp9By9jajVGCOCu4n7XBeiA1uY5xLcnAxL2Y1GIgU/...=="Connection: Keep-AliveContent-Length: 751
In order to verify the contents of the message, I need to do three things:
Check the SHA-256 hash of the message matches the content of the "Digest" header.
Check the timestamp is somewhat fresh.
Check the signature matches.
The first is simple: base64_encode( hash( "sha256", $request_body, true ) ).
The second is a matter of opinion. I might be happy to receive messages from the distant past or far in the future. For the sake of a little clock drift, let's allow 60 seconds either way.
The third gets complicated.
First, I need to get the public key published at keyId="https://your_website.biz/publicKey".
Next, I need to know which algorithm is being used to sign the headers: algorithm="rsa-sha256"
Then, I need to know which headers - and in what order - are being signed: headers="(request-target) host date digest content-type"
So I create a string using the received details which matches those headers in that specific order:
(request-target) POST /dataHost: example.comDate: Sat, 24 Feb 2024 14:43:48 GMTDigest: SHA-256=aaC57TDzM0Wq+50We2TkCsdMDvdqON92edg7KI+Hk8M=Content-Type: application/activity+json
I can verify if the signature - signature="JGQ53kEoIiMWRp9By9jajVGCOCu4n7XBeiA1uY5xLcnAxL2Y1GIgU/...==" matches by:
Which means your server will need to validate my signature by obtaining my public key. Which it will get by signing a request and sending it to me. Which, before I return my public key, I will need to validate your signature by obtaining your public key. Which I will get by signing a request... and so on.
This deadlock loop is documented. The usual way around it is either for the sending server to use an instance-specific signature which can be retrieved by an unsigned request, or to allow any unsigned request to access a user's public key.
I get why things happen this way - I just wish it were easier to implement!
“This document describes a mechanism for creating, encoding, and verifying digital signatures or message authentication codes over components of an #HTTP message”
Dopo aver perso altre incalcolabili quantità di tempo oggi, alla fine, finalmente ho finito quel #programma malefico… circa, perché ha un #problema di cui ora non ho proprio manco la voglia di venire a capo: quando prova a convertire #foto che (a quanto pare) sono corrotte, manda in crash tutto il sistema. #Pazienza, questo ed altri brutti dettagli li lascio ai posteri. 😇️
La scelta un po’ bizantina di usare un #server per l’effettiva #conversione delle #immagini si è rivelata vincente (anche perché davvero ero a corto di soluzioni…), e sorprendentemente non è nemmeno troppo lento, impiega in media 1 secondo per file (nonostante il WiFi sulla #console faccia pena, ma al netto dell’avere il server in LAN). Creare lo script PHP è stato facilissimo, ovviamente, non è mica quello che mi ha fatto perdere il pomeriggio sano… è stato il fatto che c’è un #bug, da qualche parte in quella #monnezza di httpc (il servizio per le cose #HTTP) dentro libctru (la libreria per gli #homebrew del 3DS), se non direttamente nello stack di #rete di #HorizonOS, che faceva fallire il trasferimento di dati via #HTTPS verso o da il mio server, nonostante la connessione in sé avvenisse, e con altri server non ci fossero #problemi di alcun tipo. Io ovviamente ho provato tremila cose, e solo alla fine ho tentato di collegarmi senza cifratura, e ho visto tutto funzionare. 😤️
Ora quindi posso catturare #screenshot in qualunque gioco usando il menù Rosalina, poi avviare la mia #applicazione per avere tutto quanto convertito in #JPEG e messo nell’album di sistema in #automatico (non devo premere nulla), quindi tutto visibile dal selettore #media del browser web… e a quel punto posso pubblicare qui sopra direttamente da lì, per qualsiasi titolo. Forse però dovrei espandere il codice #ServerSide, facendogli scrivere le date delle foto nei parametri EXIF, altrimenti il #Nintendo3DS vede tutto come datato 01/01/1900… nulla di grave eh, ma un po’ scomodo per navigare nella galleria. 💀️
Part 3 of "A Guide to Implementing ActivityPub in a Static Site (or Any Website)" is just out the oven!
In this blog post, I explain how to make your blog discoverable in the Fediverse as an account, and also address some of the annoying pitfalls I encountered.
La dualità del fixare #bug (o, in generale, far funzionare il #software?):
Perdi almeno 1 ora buona appresso ad un #glitch oscurissimo (spoiler: la codifica del testo centra sempre in tutti questi bug, in realtà estremamente stupidi), facendo svariati test e tentando varie opzioni prima sensate, e poi senza senso perché altrimenti non sai nemmeno come continuare. 🤥️
Nel frattempo si è fatto #tardi in culo, ti prepari per andare a #dormire e nel frattempo pensi, ma niente… a metà spegni ormai il PC, finisci di prepararti, e continui a #pensare, e solo a quel punto un’idea ovvia viene in testa. Troppo tardi ormai. 💀️
E poi ancora, perché le #incoerenze non sono mai abbastanza:
Giustamente nel letto ti irrequieti e non prendi #sonno, perché il cervello non prende pace senza vedere il #problema finalmente risolto dopo tutta la #pazzia passata, anche scommettendo che l’#idea appena venuta è giusta al 100%. 🥴
Però prima o poi il sonno lo prendi, e dopo ore arriva la #mattina dopo, in cui la sveglia suona e… pensi “zzzzzzz voglio stare nel lettino ancora, tanto la #rogna in mente l’ho risolta, chi me lo fa fare di ammazzarmi a prima mattina [prima mattina: le 9:30, ndr.]”. 🥹
Insomma, è una #condanna. Non se ne esce. Comunque si, il mio #errore era #stupido: stavo cercando di caricare #file nella galleria cloud di #WordPress tramite la #API REST, ma ricevevo sempre un rest_upload_sideload_error… controllo gli header, tutti giusti; cerco in giro, poca roba che non mi aiuta; provo #minuzie come mettere gli header lowercase, ancora niente; tento di settare a mano content-type parziali o estensioni file arbitrarie, e ovviamente non risolvo. 🤯️
Però, noto che un caricamento da curl, anziché dal mio #codice JS, va a buon fine. Allora, provo a caricare verso un server netcat in entrambi i modi, così da poter vedere al volo i dati della trasmissione #HTTP, e noto una differenza stronzetta: il corpo generato dal mio #server è molto più grosso del peso normale del file… quindi qualcosa lo sta corrompendo E qui, però, mi sono ribloccata. 🤔️
Solo poi, quando ormai avevo chiuso tutto come ho detto, ci ho pensato: ma io, nella parte del #programma che legge i #dati trasmessi dal client, vado a castare tutto ad una stringa; sarà questa la causa? …E, ricordandomi di altri #incidenti simili capitati in #NodeJS, capisco subito che è così. Detto in breve: la #codifica del testo centra sempre e rovina ogni cosa. Se esistesse solo l’ASCII, ecco che castare dati binari a stringhe non causerebbe alcun danno. E invece abbiamo deciso che i #computer devono supportare nella loro codifica migliaia di #caratteri discutibili, come tutti quelli emoji. E io, dopo aver apportato questo #fix, devo ora continuare a programmare. Non. Se. Ne. Esce. 😭️
I had occasion to revisit one of the earliest presentations on REST (May 1998) by Roy Fielding. Seen from 25 years away, this material still strikes me as clear-headed and, in many cases, prescient.
For those who utter the word "REST", this is a bit of history i recommend you should check out.
The #HTTP Garden is a collection of HTTP #servers and #proxies configured to be composable, along with scripts to interact with them in a way that makes finding #vulnerabilities much much easier.
@georgengelmann Sorry I didn't follow-up right away, I was kinda busy. I don't think this is my issue. I do have quic enabled, but only one the default server block in Nginx (listen 443 quic reuseport default_server;). For all my other domains I use: http2 on; http3 on;, which should go to HTTP/3 when possible. Yet, in all cases it uses HTTP/2 for all my resources :(... #http3#quic#nginx
@georgengelmann@debounced Ow.. one more thing, adding a add_header to location, will REMOVE all existing headers from the server section. I know, it's insane right? Docs says (and read carefully): There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level. #nginx#quic#header#headers#http#http3