3 Punkte von GN⁺ 2024-11-25 | 1 Kommentare | Auf WhatsApp teilen
  • Daniel Mangum zeigt, dass sich mithilfe des Blob-Uploads und der Record-Referenzstruktur des AT Protocol auf einen Bluesky-PDS hochgeladene text/html-Dateien wie im Browser geöffnete Webseiten bereitstellen lassen
  • Der zentrale Mechanismus ist, dass ein hochgeladener Blob nicht sofort öffentlich ist; erst wenn ein Record den Blob referenziert, macht der PDS ihn öffentlich zugänglich
  • Normale Bluesky-Image-Embeds erlauben nur MIME-Typen image/*, aber Records unbekannter Lexicons oder Custom Embeds auf Basis von Open Unions können Referenzen auf text/html-Blobs speichern
  • getBlob ist ohne Authentifizierung erreichbar, und Anfragen an bsky.social werden zum tatsächlichen PDS porcini.us-east.host.bsky.network weitergeleitet, der das HTML zurückliefert
  • Bluesky setzt für getBlob CSP-Header und nosniff ein und begrenzt normale Blob-Uploads auf 5 MB, aber für PDS-Betreiber bleiben die Belastungen durch Hosting beliebiger Dateien sowie Speicher- und Transferkosten bestehen

Wie man mit AT-Protocol-Blobs eine Website hochlädt

  • Dieses Beispiel basiert weniger auf normalen Funktionen der Bluesky-App als auf der Funktionsweise des AT Protocol und der PDS-API
  • Bluesky stellt einen PDS Entryway bereit, über den auf den PDS eines Nutzers zugegriffen wird, und exponiert mehrere PDS-Instanzen über die Domain bsky.social
  • Einzelne PDS-Instanzen können auch direkt angesprochen werden; die Beispiel-Website öffnet sich am Endpoint com.atproto.sync.getBlob von porcini.us-east.host.bsky.network
  • Vor der Veröffentlichung des Beitrags gab es Austausch mit dem Bluesky-Team; dieses Verhalten ist keine beabsichtigte Nutzung der Anwendung, aber ein bekanntes Verhalten und kein Verfahren zur Offenlegung einer Sicherheitslücke

Warum Records und Blobs getrennt sind

  • Im AT Protocol werden Anwendungsdaten grob in Records und Blobs unterteilt
    • Records sind die zentralen, von Nutzern erstellten Entitäten und können Struktur sowie Metadaten enthalten
    • Blobs sind größere unstrukturierte Daten wie Bilder und werden normalerweise erst sichtbar, wenn ein Record sie referenziert
  • Wenn man in Bluesky einen Post mit Bild erstellt, wirkt das für Nutzer wie ein einzelner Vorgang, auf API-Ebene sind Blob-Upload und Record-Erstellung jedoch getrennt
  • Laut Blob Specification muss ein Blob zuerst auf den PDS hochgeladen werden, bevor ein Record ihn referenziert
  • Da der Server beim Upload nicht wissen kann, in welchem Lexicon der Blob verwendet wird, gelten beim initialen Upload nur allgemeine Blob-Beschränkungen; Lexicon-basierte Beschränkungen werden erst beim Erstellen des Records angewendet
  • Erfolgreich hochgeladene Blobs landen in einem temporären Speicher; in diesem Zustand können sie nicht heruntergeladen oder verteilt werden und erscheinen auch nicht in der Ausgabe von listBlobs
  • Wenn die Record-Erstellung erfolgreich ist und dieser Record den Blob referenziert, schaltet der Server den Blob in einen öffentlich zugänglichen Zustand um

HTML-Blob hochladen und öffentlich machen

  • Ein Authentifizierungstoken erhält man, indem man über die XRPC-Methode com.atproto.server.createSession Nutzer-Anmeldedaten austauscht
  • Im Beispiel wurde mit com.atproto.sync.listBlobs die vorhandene Zahl der Blobs geprüft; vor dem Upload lag sie bei 391
  • Der Website-Inhalt ist eine einfache index.html-Datei und wird mit com.atproto.repo.uploadBlob hochgeladen
    • Content-Type ist text/html
    • Die zurückgegebenen Blob-Metadaten enthalten die CID bafkreic5fmelmhqoqxfjz2siw5ey43ixwlzg5gvv2pkkz7o25ikepv4zeq, mimeType: text/html und size: 268
  • Direkt nach dem Upload war der Abruf über com.atproto.sync.getBlob nicht möglich, und die Zahl in listBlobs blieb ebenfalls bei 391
  • Wenn man den HTML-Blob als Image Embed in einem Bluesky-Post referenziert, schlägt dies fehl, weil das Schema app.bsky.embed.image den MIME-Typ image/* verlangt
    • Belässt man text/html, tritt der Fehler Wrong type of file. It is text/html but it must match image/*. auf
    • Ändert man mimeType in image/jpeg, tritt ein Fehler auf, weil der gespeicherte Blob-MIME-Typ und der referenzierte MIME-Typ unterschiedlich sind

Blob über einen unbekannten Lexicon-Record veröffentlichen

  • Der Blob-Typ ist nicht Bluesky-spezifisch, sondern Teil des AT-Protocol-Datenmodells
  • Die Bluesky-PDS-Implementierung ist Open Source, und findBlobRefs durchsucht LexValue rekursiv nach Referenzen mit $type: blob
  • Da PDS mit der Zeit neue Lexicons unterstützen müssen, müssen sie auch Lexicons verarbeiten können, die sie selbst nicht kennen
  • Als ein Record vom Typ com.danielmangum.hack.website erstellt und der HTML-Blob referenziert wurde, speicherte der PDS den Record
    • Die Antwort enthielt validationStatus: unknown
    • Weil der PDS das Lexicon com.danielmangum.hack.* nicht kannte, konnte er es nicht validieren, erlaubte aber das Speichern des Records
  • Danach stieg die Zahl in listBlobs auf 392, was bestätigte, dass der Blob dauerhaft gespeichert wurde
  • getBlob kann ohne Authentifizierungstoken aufgerufen werden, weil auch nicht authentifizierte Akteure, die Records zusammen mit Blobs verarbeiten müssen, den Blob abrufen können müssen
  • Der getBlob-Aufruf auf bsky.social lieferte per 302-Redirect die tatsächliche PDS-URL zurück; folgt man dem Redirect mit -L, wird der HTML-Inhalt unverändert zurückgegeben

Sicherheits-Header, CDN und die Last direkter Zugriffe

  • Die Security Considerations der AT-Protocol-Blob-Spezifikation behandeln Content-Sicherheitsrisiken, die entstehen, wenn beliebige von Nutzern hochgeladene Dateien von einem Webserver ausgeliefert werden
    • Ein typisches Beispiel sind XSS-Probleme, bei denen Skripte oder SVG-Inhalte im selben Origin ausgeführt werden
    • Für den Endpoint getBlob ist der Einsatz einer Content Security Policy praktisch unverzichtbar
    • Die direkte Bereitstellung von Blob-Speichern für Browser und Web-Agents wird faktisch nicht unterstützt; Anwendungen sollten stattdessen über ein unabhängiges CDN, einen Proxy, Webservices usw. gehen
  • Der getBlob-Handler des Bluesky-PDS setzt die empfohlenen Sicherheits-Header
    • x-content-type-options: nosniff
    • content-security-policy: default-src 'none'; sandbox
  • Die Standardgrenze für Blob-Uploads liegt bei 5 MB
  • Normale Image-Blobs der Bluesky-Anwendung werden nicht direkt vom PDS bereitgestellt, sondern als CDN-URLs von cdn.bsky.app
    • Es gibt getrennte URLs für Feed-Thumbnails und Full-Size-Versionen
    • Der Post-Record enthält die Bild-CID, und die Anwendung muss wissen, wie die Bereitstellung über das CDN funktioniert
  • Direkter Zugriff über getBlob bleibt laut GitHub-Issue wegen Image-Labeling, Export von Nutzerinhalten und künftiger Use Cases bestehen
    • In derselben Diskussion wird auch die Möglichkeit erwähnt, dass Nutzer Inhalte hotlinken oder Bluesky wie kostenloses Hosting verwenden
    • Der ursprünglichen Implementierung fehlten Sicherheits-Header; diese wurden später hinzugefügt
  • Klassische soziale Plattformen können Blobs beim Upload stärker einschränken, weil die zulässigen Content-Typen begrenzt sind; die Erweiterbarkeit von Bluesky und AT Protocol erfordert jedoch eine komplexere Verarbeitung

Custom Embed per Open Union in einen Post einfügen

  • Der Typ app.bsky.feed.post definiert die Liste gültiger Embeds als Union
  • Im AT-Protocol-Lexicon sind Unions standardmäßig open, sofern sie nicht ausdrücklich closed sind
    • Da bei künftigen Schema-Revisionen Typen hinzukommen können, sollten Implementierungen bei der Validierung tolerant sein
    • Ist das Flag closed gesetzt, ist die Typmenge fixiert
  • Die Embed-Union eines Bluesky-Posts ist nicht als closed markiert
  • Daher lassen sich Posts auch mit einem nicht aufgezählten Embed-$type erstellen
  • Im Beispiel wurde in einen app.bsky.feed.post-Record ein Embed com.danielmangum.hack.sites eingefügt, der wiederum den HTML-Blob referenziert
    • validationStatus der Antwort ist valid
    • In der Bluesky-Anwendung wird dieses Embed stillschweigend ignoriert
    • Der Inhalt und die Referenz bleiben im Record dauerhaft gespeichert, sodass andere Anwendungen dieses Embed rendern können
  • Solche Lexicon-Eigenschaften können genutzt werden, um kleine Erweiterungen auf bestehende Use Cases aufzusetzen; als Beispiel wird die Möglichkeit genannt, kleine Code-Snippets innerhalb eines Posts in einer WebAssembly-Sandbox auszuführen

1 Kommentare

 
GN⁺ 2024-11-25
Meinungen auf Hacker News
  • Ich fand es gut, dass Daniel direkt beim Team nachgefragt hat, und Blob-Hosting ist ein Bereich, der zwangsläufig weiter angepasst werden muss, während man die Missbrauchswege besser versteht.
    Im Moment ist es spannend zu sehen, dass solche Nutzungen tatsächlich funktionieren, und PDS ist von der Struktur her so gedacht, dass es zu einem Datenbank-Host wird, so wie ein Webserver Websites hostet.

    • Ich frage mich, ob es Pläne gibt, den Beaker Browser wiederzubeleben.
      Früher war er toll zum Herumspielen, und ich wusste nicht, dass er zu Bluesky gewechselt ist; das ist ziemlich interessant.
    • Wenn Inhalte nicht über eine bestimmte App-View wie bsky laufen, sondern mit der eigenen Domain der Nutzer verknüpft werden, könnte das die Missbrauchsmöglichkeiten verringern.
      Bsky unterstützt bereits die Methode, Nutzer-Domains per ALIAS an redirect.bsky.com anzubinden: https://bsky.app/profile/jacob.gold/post/3kh6rnpdzmp2v
    • Beaker war ein wirklich spannendes Projekt zum Mitverfolgen, und diese Erfahrung dürfte bei Bluesky ziemlich nützlich sein.
    • Dieser Ansatz bedeutet, sich frontal in die Grube der Content-Moderation rund um Urheberrecht, CSAM und Pornografie zu stürzen.
  • Ich war neugierig, in welchem Sicherheitskontext das läuft, und habe mir die PDS-Blob-URL mit curl angesehen; in den Response-Headern standen unter anderem access-control-allow-origin: *, content-security-policy: default-src 'none'; sandbox und x-content-type-options: nosniff.
    access-control-allow-origin: * ist interessant, weil es bedeutet, dass JavaScript auf Webseiten beliebiger Domains mit fetch() auf diese Inhalte zugreifen kann, und default-src 'none'; sandbox ist gut, weil es eine sehr restriktive Einstellung ist, die das Laden zusätzlicher Skripte oder Bilder verhindert und auch die Ausführung von JavaScript blockiert: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Co...
    ratelimit-limit: 3000 scheint vermutlich ein IP-basiertes Limit zu sein.

    • JavaScript komplett zu blockieren oder auf eine Allowlist zu beschränken, ist wohl nahezu die einzige Möglichkeit, eine App per CSP vollständig einzusperren und Datenabfluss zu verhindern; mit Prefetch reicht selbst das möglicherweise nicht aus.
      Der Vorschlag am Ende des Artikels, WebAssembly zu verwenden, geht in die richtige Richtung, und das Problem mit Link-Klicks ließe sich begrenzen, indem man nicht vertrauenswürdigen Code in ein iframe legt und im Parent per child-src nur bestimmte Domains oder data: erlaubt.
      https://github.com/w3c/webappsec/issues/656#issuecomment-246...
      https://www.w3.org/TR/CSP3/#exfiltration
    • Ich frage mich, ob man bei der Verwendung von sandbox trotzdem default-src braucht oder ob das eine redundante Einstellung ist.
  • Ich bin ziemlich gespannt auf die Möglichkeit, Bluesky als Blob-Datenspeicher zu verwenden.
    Zusammen mit einem Freund habe ich überlegt, DOOM-WADs in Bluesky zu speichern und „Map Packs“ wie Posts zu teilen; wenn man Accounts, Listen oder Starter Packs folgt, könnte man Clients wie GZDoom so anpassen, dass sie die von diesen Accounts hochgeladenen WADs suchen und anzeigen können.
    Das wäre ähnlich wie der Steam Workshop, nur eben über Bluesky.

    • Coole Idee, aber ich frage mich, ob du das selbst hosten oder auf Bluesky-Servern ablegen willst.
      Ich weiß auch nicht, ob Bluesky jemals Richtlinien für die Nutzung als Blob-Speicher erwähnt hat; DOOM-Dateien sind klein und daher ein gutes Beispiel, aber ich frage mich, ob das missbraucht werden könnte, um großen Server-Speicherbedarf auszulagern.
    • Am Ende nutzt man Bluesky damit doch im Grunde wie einen RSS-Feed für beliebige Daten, oder?
  • Ich habe diese konkrete Ära zwar nicht miterlebt, aber wie BlueSky-Nutzer in technisch tiefes Wasser springen, erinnert mich an die Zeit, als Leute auf MySpace zum ersten Mal HTML gelernt haben.
    Der Social-Media-Markt ist heute viel stärker gesättigt, aber ich frage mich, ob aus BlueSky eine neue Generation von Programmierern hervorgehen kann.

    • MySpace und alte Foren boten eine Abstraktionsleiter: Man begann damit, Text in ein Feld zu schreiben, der dann auf einer Webseite erschien, und ging weiter zu Bildern, BBCode/Markup, HTML und CSS bis hin zu vollständigem Scripting.
      Bluesky bietet nur die erste Stufe; alles danach wirkt wie ein ziemlich großer Sprung.
    • Es heißt zwar „14 Minuten“, aber ich sehe etwa ein Dutzend Links, die man offenbar zwingend lesen muss, um eine neue Idee auszuprobieren.
      Mit HTTP/HTML kann man selbst jemandem, der nur grundlegendes Python oder eine andere Programmiersprache kennt, in 14 Minuten zeigen, wie man einen Server von Grund auf baut.
      Ich denke zwar, dass man ein hashadressiertes Kommunikationsprotokoll braucht, um zu verhindern, dass Tech-Giganten Communities ausbeuten, aber ich bin nicht sicher, ob das AT Protocol seine Ziele gut genug trifft, um eine Revolution wie HTTP auszulösen.
  • Einer der Kernpunkte ist, dass der hier behandelte PDS nicht das Bluesky-Produkt selbst ist, sondern Teil des Personal Data Server, wodurch er am Ende wie ein unbegrenzter kostenloser Datenspeicher wirken kann.
    Der Abo-Dienst, den das Bluesky-Team gelegentlich erwähnt hat, könnte mit solchen Dingen zusammenhängen, und Hosting, das auf dem PDS mehr Speicherplatz, Bandbreite oder hochauflösende Videos bietet, scheint sich gut als Premium-Tier verkaufen zu lassen.

    • Wenn ich es richtig verstanden habe, wurde dieser PDS von Bluesky gehostet.
      Man dürfte ihn auch anderswo hosten können, daher scheint die Aussage zu stimmen, dass man über die Bluesky-App hinaus damit interagieren kann.
  • Das Phänomen, dass, sobald man es möglich macht, irgendetwas ins Internet zu stellen, am Ende irgendjemand darauf beliebiges File-Hosting versucht, braucht offenbar einen Namen.

    • Das dürfte auch ein wichtiger Grund dafür sein, dass Google-Konten inzwischen bis zur nächsten kostenpflichtigen Erweiterung auf 15 GB begrenzt sind.
      In der Zeit der unbegrenzten Nutzung gab es mehrere Open-Source-Projekte, die versuchten, Dateisysteme in Gmail und Ähnlichem zu sichern; nach dem Start von Drive wurde es noch schlimmer.
      Kostenlose Dienste müssen solche Probleme vorhersehen und standardmäßig Limits setzen.
    • Da es bereits den Begriff „parasitic computation“ gibt, könnte man es wohl „parasitic data storage“ nennen.
    • Johnsons Gesetz: Je mehr Aufmerksamkeit etwas bekommt, desto größer wird auch sein Wirkungsbereich.
    • Es kommt dem Inner Platform effect nahe.
      https://en.wikipedia.org/wiki/Inner-platform_effect
  • Wenn solche Themen interessant sind, lohnt sich auch ein Blick auf atfile: https://github.com/electricduck/atfile

  • Ziemlich cool, und man kann sich direkt das interessante GitHub-Issue ansehen, das unten im Beitrag verlinkt ist.
    Auch die bekannte Bluesky-Person pfrazee taucht dort auf: https://github.com/bluesky-social/atproto/issues/523
    Ich setze große Hoffnungen in AT, und im Fediverse gibt es sicher viele kluge Leute, die großartige Arbeit geleistet haben, aber dieses Paradigma wirkt nachhaltiger und realistischer.
    Der Grundansatz ist, es zentralisiert bereitzustellen, aber bei Bedarf oder für Power-User echte Unterstützung für Dezentralisierung zu bieten.

    • In Sachen Nachhaltigkeit hoffe ich auf ein Geschäftsmodell, das besser ist als „Geld von Blockchain Capital bekommen“.
      Es braucht einen Weg, aus dem Firehose-Mirroring eine Rendite zu erzielen; denkbar wären etwa eine Discord-Alternative, bei der einige Nutzer für das Hosting längerer Videos zahlen, eine Patreon-artige Struktur, bei der Relays Zugriffs- und Entschlüsselungsschlüssel verwalten und dafür Gebühren nehmen, oder ein sozialer Marktplatz wie Bandcamp.
      Jedenfalls ist es eine offene Plattform, also gibt es schon jetzt keinen Grund, warum man das nicht tun könnte.
      https://www.blockchaincapital.com/blog/bluesky-13m-users-and...
      https://bsky.social/about/blog/09-11-2024-video
  • Ich habe das Gefühl, dass diese Methode für Phishing oder die Verbreitung von Malware missbraucht werden könnte.

    • Gibt es überhaupt eine Hosting-Seite, die nicht missbraucht wird?
      Wenn man eine Hosting-Seite baut, scheint es fast ein Gesetz der Informatik zu sein, dass irgendjemand sie für bösartige Zwecke nutzen will.
    • Genau das wird tatsächlich passieren.
      Bei Matrix-Anhängen gab es dasselbe Problem.
    • Nach etwa fünf Minuten dürfte *.bsky.network von Google Safe Browsing, Palo Alto, Bluecoat und anderen blockiert werden.
    • Ich bin mir nicht sicher.
      Das ist ein direkter Link zum Bluesky-Server des Autors, also zum PDS, und damit natürlich unter Kontrolle des Autors.
  • Die jüngsten API-Änderungen bei Strava haben mich daran erinnert, wie eingeschränkt der Zugriff auf die auf ihrer Plattform gespeicherten Daten ist.
    Als dominierender Dienst im Fitnessbereich könnten sie Funktionen nach und nach hinter eine Abo-Schranke verschieben.
    Auch wenn es Datenschutz- oder Sicherheitsbedenken gibt, frage ich mich, ob das AT Protocol als Speicherplattform für GPX- oder FIT-Dateien geeignet sein könnte.

    • Eine föderierte Strava-Alternative wäre schön.
      Allerdings unterstützt das AT Protocol meines Wissens noch keine privaten oder eingeschränkt öffentlichen Beiträge, und für Strava-Zwecke halte ich diese Funktion für ziemlich zentral.