Un sitio web alojado en Bluesky
(danielmangum.com)- Daniel Mangum muestra que, usando la estructura de carga de blobs y referencias de records del AT Protocol, es posible servir archivos
text/htmlsubidos a un PDS de Bluesky como si fueran páginas web que se abren en el navegador - El punto clave es que un blob subido no se vuelve público de inmediato; el PDS solo lo cambia a un estado de acceso público cuando algún record hace referencia al blob
- Los embeds de imagen normales de Bluesky solo permiten tipos MIME
image/*, pero un record con un lexicon desconocido o un embed personalizado basado en open union puede guardar referencias a blobstext/html getBlobpuede consultarse sin autenticación, y las solicitudes absky.socialse redirigen al PDS real,porcini.us-east.host.bsky.network, que devuelve el HTML- Bluesky aplica encabezados CSP y
nosniffengetBlob, y limita la carga de blobs por defecto a 5 MB, pero para los servicios que operan PDS sigue existiendo la carga de alojar archivos arbitrarios y asumir sus costos de almacenamiento y transferencia
Cómo subir un sitio web con blobs de AT Protocol
- Este caso se basa más en cómo funcionan AT Protocol y la API de PDS que en una función normal de la app de Bluesky
- Bluesky ofrece un PDS entryway para acceder al PDS del usuario, exponiendo varias instancias de PDS bajo el dominio
bsky.social - También se puede acceder directamente a cada instancia de PDS, y el sitio web de ejemplo se abre desde el endpoint
com.atproto.sync.getBlobdeporcini.us-east.host.bsky.network - Antes de publicar el artículo, hubo comunicación con el equipo de Bluesky; este comportamiento no es un uso previsto de la aplicación, pero sí es conocido y no se trató como un proceso de divulgación de vulnerabilidades
Por qué records y blobs están separados
- En AT Protocol, los datos de la aplicación se dividen en dos grandes grupos: records y blobs
- Los records son las entidades principales que crea el usuario y pueden tener estructura y metadatos
- Los blobs son datos no estructurados más grandes, como imágenes, y por lo general deben ser referenciados por un record para quedar expuestos
- Cuando en Bluesky se crea una publicación con imágenes, para el usuario parece una sola acción, pero a nivel de API la carga del blob y la creación del record están separadas
- Según la especificación de blobs, un blob debe subirse primero al PDS antes de que un record pueda referenciarlo
- Como en el momento de la carga el servidor no sabe en qué Lexicon se usará el blob, al inicio solo aplica restricciones generales de blob y deja las restricciones basadas en Lexicon para cuando se crea el record
- Un blob cargado con éxito entra en almacenamiento temporal; en ese estado no puede descargarse ni distribuirse, y tampoco aparece en la salida de
listBlobs - Cuando la creación del record se completa y ese record referencia el blob, el servidor cambia el blob a un estado de acceso público
Carga de un blob HTML y cambio a estado público
- El token de autenticación se obtiene intercambiando credenciales del usuario mediante el método XRPC
com.atproto.server.createSession - En el ejemplo, se verificó la cantidad de blobs existentes con
com.atproto.sync.listBlobs, y antes de la carga había391 - El contenido del sitio web era un archivo
index.htmlsimple y se subió concom.atproto.repo.uploadBlobContent-Typeeratext/html- Los metadatos devueltos del blob incluían el CID
bafkreic5fmelmhqoqxfjz2siw5ey43ixwlzg5gvv2pkkz7o25ikepv4zeq,mimeType: text/html,size: 268
- Justo después de subirlo, intentar obtenerlo con
com.atproto.sync.getBlobno funcionaba, y la cantidad enlistBlobsseguía siendo391 - Si se referencia el blob HTML como embed de imagen en una publicación de Bluesky, falla porque el esquema
app.bsky.embed.imageexige un tipo MIMEimage/*- Si se deja
text/html, aparece el errorWrong type of file. It is text/html but it must match image/*. - Si se cambia
mimeTypeaimage/jpeg, aparece un error indicando que el MIME del blob guardado y el MIME de la referencia no coinciden
- Si se deja
Hacer público el blob con un record de lexicon desconocido
- El tipo blob no es exclusivo de Bluesky, sino parte del modelo de datos de AT Protocol
- La implementación del PDS de Bluesky es open source, y
findBlobRefsrecorre recursivamenteLexValuepara encontrar referencias$type: blob - Como un PDS debe poder soportar nuevos lexicons con el tiempo, también necesita manejar lexicons que todavía no conoce
- Al crear un record de tipo
com.danielmangum.hack.websitey hacer que referenciara el blob HTML, el PDS guardó el record- La respuesta incluía
validationStatus: unknown - Como el PDS no conocía el lexicon
com.danielmangum.hack.*, no podía validarlo, pero aun así permitió guardar el record
- La respuesta incluía
- Después, la cantidad en
listBlobssubió a392, confirmando que el blob había quedado almacenado de forma persistente getBlobpuede invocarse sin token de autenticación, porque incluso entidades no autenticadas que procesan blobs junto con records necesitan poder obtenerlos- La llamada a
getBlobenbsky.socialdevolvió una redirección 302 hacia la URL real del PDS, y al seguir la redirección con-L, el contenido HTML se devolvía tal cual
Encabezados de seguridad, CDN y la carga del acceso directo
- La sección Security Considerations de la especificación de blobs de AT Protocol trata los riesgos de seguridad de servir archivos arbitrarios subidos por usuarios desde un servidor web
- Un ejemplo típico es el problema de XSS cuando se ejecutan scripts o contenido SVG bajo el mismo origin
- Aplicar Content Security Policy al endpoint
getBlobes, en la práctica, imprescindible - Proveer directamente el repositorio de blobs a navegadores y agentes web no está realmente soportado; las aplicaciones deben pasar por un CDN independiente, un proxy u otro servicio web
- El handler
getBlobdel PDS de Bluesky aplica los encabezados de seguridad recomendadosx-content-type-options: nosniffcontent-security-policy: default-src 'none'; sandbox
- El límite predeterminado para subir blobs es de 5 MB
- Los blobs de imagen normales de la aplicación Bluesky no se sirven directamente desde el PDS, sino mediante URLs de CDN de
cdn.bsky.app- Existen por separado la URL del thumbnail del feed y la URL del tamaño completo
- El record de la publicación incluye el CID de la imagen, y la aplicación debe saber cómo resolver la forma en que el CDN la entrega
- El acceso directo a
getBlobsigue existiendo por temas discutidos en issues de GitHub, como el etiquetado de imágenes, la exportación de contenido de usuarios y casos de uso futuros- En esa misma discusión también se contempla la posibilidad de que usuarios hagan hotlinking de contenido o usen Bluesky como hosting gratuito
- La implementación inicial no tenía encabezados de seguridad, y estos se agregaron después
- Las plataformas sociales tradicionales suelen limitar más los tipos de contenido válidos, por lo que pueden aplicar restricciones más fuertes al blob desde el momento de la carga; en cambio, la extensibilidad de Bluesky y AT Protocol exige un tratamiento más complejo
Usar open union para meter un embed personalizado en una publicación
- El tipo
app.bsky.feed.postdefine su lista de embeds válidos como una union - En los lexicons de AT Protocol, una union es open por defecto a menos que esté marcada explícitamente como
closed- Como en futuras revisiones del esquema se pueden añadir tipos, las implementaciones deben ser flexibles al validar
- Si existe la bandera
closed, el conjunto de tipos queda fijo
- La union de embeds de las publicaciones de Bluesky no está marcada como
closed - Por lo tanto, es posible crear publicaciones incluso con un
$typede embed que no esté enumerado - En el ejemplo, dentro de un record
app.bsky.feed.postse añadió un embedcom.danielmangum.hack.sites, y dentro de este se referenciaba el blob HTML- El
validationStatusde la respuesta fuevalid - En la aplicación de Bluesky, ese embed simplemente se ignora en silencio
- Como el contenido y la referencia quedan almacenados de forma persistente en el record, otras aplicaciones sí podrían renderizar ese embed
- El
- Este tipo de propiedad del lexicon puede aprovecharse para añadir pequeñas extensiones sobre casos de uso ya existentes; por ejemplo, se menciona la posibilidad de ejecutar pequeños fragmentos de código dentro de una publicación usando un sandbox de WebAssembly
1 comentarios
Comentarios en Hacker News
Agradecieron que Daniel contactara directamente al equipo, y dijeron que el hosting de blobs es un área que inevitablemente seguirá ajustándose conforme entiendan mejor las vías de abuso
Por ahora les parece divertido ver este tipo de usos funcionando en la práctica, y la PDS está diseñada con la intención de que un host de base de datos cumpla un rol parecido al de un servidor web que aloja sitios web
Antes era muy divertido para experimentar, y no sabía que se habían pasado a Bluesky, lo cual me parece bastante interesante
Bsky ya permite adjuntar dominios de usuario como ALIAS a
redirect.bsky.com: https://bsky.app/profile/jacob.gold/post/3kh6rnpdzmp2vTenía curiosidad por saber en qué contexto de seguridad se ejecuta esto, así que revisé la URL del blob de la PDS con
curl, y en los headers de respuesta aparecían cosas comoaccess-control-allow-origin: *,content-security-policy: default-src 'none'; sandbox,x-content-type-options: nosniff, etc.access-control-allow-origin: *es interesante porque significa que el JavaScript de una página web en cualquier dominio puede acceder a este contenido confetch(), ydefault-src 'none'; sandboxes una configuración muy restrictiva que impide cargar scripts o imágenes adicionales y también bloquea la ejecución de JavaScript, lo cual está bien: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Co...ratelimit-limit: 3000probablemente sea un límite por IPLa sugerencia al final del artículo de usar WebAssembly va en la dirección correcta, y el problema de los clics en enlaces se puede limitar poniendo código no confiable en un iframe y haciendo que el padre permita solo dominios específicos o
data:mediantechild-srchttps://github.com/w3c/webappsec/issues/656#issuecomment-246...
https://www.w3.org/TR/CSP3/#exfiltration
sandbox, sigue siendo necesariodefault-srco si es una configuración redundanteMe entusiasma bastante la posibilidad de usar Bluesky como almacenamiento de datos blob
Pensé con un amigo en guardar WADs de DOOM en Bluesky para compartir “map packs” como si fueran publicaciones, y si sigues cuentas, listas y starter packs, tal vez se podría modificar un cliente como GZDoom para que busque y muestre los WADs subidos por esas cuentas
Sería algo parecido a Steam Workshop, pero pasando por Bluesky
Tampoco sé si Bluesky ha mencionado alguna guía de uso para almacenamiento de blobs, y los archivos de DOOM son un buen ejemplo porque son pequeños, pero también me pregunto si esto podría abusarse para externalizar grandes cantidades de espacio de servidor
No viví esa época en particular, pero ver a los usuarios de BlueSky meterse en aguas técnicas más profundas me recuerda a cuando la gente aprendía HTML por primera vez en MySpace
El mercado de redes sociales está mucho más saturado que antes, pero me pregunto si de BlueSky podría salir una nueva generación de programadores
Bluesky solo ofrece el primer escalón, y a partir de ahí el salto parece bastante grande
Si fuera HTTP/HTML, podrías enseñarle incluso a alguien que solo conoce Python básico u otro lenguaje de programación cómo montar un servidor desde cero en 14 minutos
Creo que hace falta un protocolo de comunicación con direccionamiento por hash para evitar que las grandes tecnológicas exploten a las comunidades, pero no estoy seguro de que AT Protocol haya dado tan bien en el blanco como para detonar una revolución al nivel de HTTP
Uno de los puntos clave aquí es que la PDS de la que se habla no es el producto Bluesky en sí, sino parte de un Personal Data Server, por lo que al final puede parecer almacenamiento de datos gratuito e infinito
El servicio de suscripción que el equipo de Bluesky ha mencionado a veces parece poder conectarse con esto, y ofrecer más espacio, ancho de banda y video en alta calidad desde la PDS suena como algo adecuado para venderse como un nivel premium
Como también podría alojarse en otros lados, parece cierto que se puede interactuar más allá de la app de Bluesky misma
Si haces posible subir cosas a internet, al final alguien va a intentar usarlo para alojar archivos arbitrarios; parece que este fenómeno necesita un nombre
En la época en que era ilimitado, salieron varios proyectos open source que intentaban respaldar sistemas de archivos en Gmail y similares, y después de que apareció Drive se puso todavía peor
Los servicios gratuitos deberían asumir desde el inicio que este problema va a surgir y poner límites por defecto
https://en.wikipedia.org/wiki/Inner-platform_effect
Si este tema te parece interesante, también vale la pena ver atfile: https://github.com/electricduck/atfile
Está bastante genial, y puedes ir directo a ver el interesante issue de GitHub enlazado al final del post
También aparece pfrazee, una figura conocida de Bluesky: https://github.com/bluesky-social/atproto/issues/523
Hay muchas expectativas puestas en AT, y seguramente también hay gente muy capaz que ha hecho un gran trabajo en el Fediverse, pero este paradigma se ve más sostenible y más realista
La base se ofrece de forma centralizada, pero cuando hace falta, o para usuarios avanzados, se da soporte real de descentralización
Hace falta alguna forma de obtener retorno de inversión del mirroring del firehose y, por ejemplo, podría existir una alternativa a Discord donde algunos usuarios paguen por alojar videos más largos, una estructura tipo Patreon donde los relays administren las llaves de acceso y descifrado y cobren una comisión, o incluso un mercado social al estilo Bandcamp
De todos modos, como es una plataforma abierta, tampoco hay ninguna razón por la que no pueda hacerse ya ahora
https://www.blockchaincapital.com/blog/bluesky-13m-users-and...
https://bsky.social/about/blog/09-11-2024-video
Da la impresión de que este método podría usarse mal para phishing o distribución de malware
Parece casi una ley de la computación que, si creas un sitio de hosting, alguien va a querer usarlo con fines maliciosos
Hubo el mismo problema con los archivos adjuntos de Matrix
*.bsky.networkempiece a ser bloqueado por Google Safe Browsing, Palo Alto, Bluecoat y similaresEste es un enlace directo al servidor de Bluesky del autor, es decir, a su PDS, así que naturalmente está bajo el control del autor
Viendo los cambios recientes en la API de Strava, me acordé de lo restringido que es el acceso a los datos almacenados en su plataforma
Como es el servicio dominante en el sector fitness, podrían ir moviendo funciones poco a poco detrás de un muro de suscripción
Puede haber preocupaciones de privacidad o seguridad, pero me pregunto si AT Protocol podría servir como plataforma de almacenamiento para archivos GPX o FIT
Aunque, hasta donde sé, AT Protocol todavía no soporta publicaciones privadas o con visibilidad restringida, y me parece que esa función es bastante clave para un caso de uso como Strava