Um site hospedado no Bluesky
(danielmangum.com)- Daniel Mangum mostra que, usando a estrutura de upload de blobs e referência de records do AT Protocol, é possível servir um arquivo
text/htmlenviado para um PDS do Bluesky como se fosse uma página web aberta no navegador - O ponto central é que um blob enviado não se torna público imediatamente; o PDS só o coloca em um estado com acesso público quando algum record referencia o blob
- O embed de imagem comum do Bluesky só permite MIME type
image/*, mas um record com lexicon desconhecido ou um embed customizado baseado em open union pode armazenar uma referência a um blobtext/html getBlobpode ser acessado sem autenticação, e uma requisição parabsky.socialé redirecionada para o PDS real,porcini.us-east.host.bsky.network, que retorna o HTML- O Bluesky aplica headers de CSP e
nosniffaogetBlob, e limita o upload padrão de blobs a 5 MB, mas o serviço que opera o PDS ainda fica com o ônus de hospedar arquivos arbitrários e arcar com custos de armazenamento e tráfego
Como publicar um site com blobs do AT Protocol
- Este caso se baseia mais no funcionamento do AT Protocol e da API de PDS do que em recursos normais do app Bluesky
- O Bluesky fornece um PDS entryway para acessar o PDS do usuário, expondo várias instâncias de PDS sob o domínio
bsky.social - Também é possível acessar diretamente cada instância de PDS, e o site de exemplo abre no endpoint
com.atproto.sync.getBlobdeporcini.us-east.host.bsky.network - O autor se comunicou com a equipe do Bluesky antes da publicação, e esse comportamento, embora não seja a forma pretendida de uso do aplicativo, já era conhecido e não se trata de um processo de divulgação de vulnerabilidade
Por que records e blobs são separados
- No AT Protocol, os dados da aplicação se dividem em records e blobs
- records são as entidades principais criadas pelo usuário, podendo ter estrutura e metadados
- blobs são dados maiores e não estruturados, como imagens, e normalmente só ficam expostos quando um record os referencia
- Ao criar uma postagem com imagem no Bluesky, isso parece uma única ação para o usuário, mas no nível da API o upload do blob e a criação do record são separados
- Segundo a especificação de blobs, o blob precisa primeiro ser enviado ao PDS antes que um record possa referenciá-lo
- No momento do upload, o servidor ainda não sabe em qual Lexicon o blob será usado, então aplica apenas restrições genéricas; as restrições baseadas em Lexicon são aplicadas na criação do record
- Um blob enviado com sucesso vai para um armazenamento temporário e, nesse estado, não pode ser baixado nem distribuído, além de não aparecer na saída de
listBlobs - Quando a criação do record é bem-sucedida e esse record referencia o blob, o servidor o move para um estado com acesso público
Upload de blob HTML e transição para público
- O token de autenticação é obtido trocando as credenciais do usuário pelo método XRPC
com.atproto.server.createSession - No exemplo,
com.atproto.sync.listBlobsfoi usado para verificar a quantidade de blobs existentes, que era391antes do upload - O conteúdo do site era um arquivo
index.htmlsimples, enviado porcom.atproto.repo.uploadBlob- O
Content-Typeeratext/html - Os metadados retornados do blob incluíam o CID
bafkreic5fmelmhqoqxfjz2siw5ey43ixwlzg5gvv2pkkz7o25ikepv4zeq,mimeType: text/htmlesize: 268
- O
- Logo após o upload, uma tentativa de buscá-lo com
com.atproto.sync.getBlobfalhou, e a contagem delistBlobstambém permaneceu em391 - Ao tentar referenciar o blob HTML como embed de imagem em uma postagem do Bluesky, a validação falha porque o schema
app.bsky.embed.imageexige MIME typeimage/*- Se
text/htmlfor mantido, ocorre o erroWrong type of file. It is text/html but it must match image/*. - Se o
mimeTypefor alterado paraimage/jpeg, ocorre um erro dizendo que o MIME type do blob armazenado e o MIME type da referência não coincidem
- Se
Tornando o blob público com um record de lexicon desconhecido
- O tipo blob não é algo exclusivo do Bluesky; ele faz parte do modelo de dados do AT Protocol
- A implementação do PDS do Bluesky é open source, e
findBlobRefspercorre recursivamenteLexValueem busca de referências com$type: blob - Como o PDS precisa suportar novos lexicons ao longo do tempo, ele também deve conseguir processar lexicons que ainda não conhece
- Ao criar um record do tipo
com.danielmangum.hack.websitee fazer referência ao blob HTML, o PDS armazenou o record- A resposta incluía
validationStatus: unknown - Como o PDS não conhecia o lexicon
com.danielmangum.hack.*, não pôde validá-lo, mas ainda assim permitiu armazenar o record
- A resposta incluía
- Depois disso, a contagem em
listBlobssubiu para392, confirmando que o blob foi persistido getBlobpode ser chamado sem token de autenticação, porque entidades não autenticadas que precisam lidar com records também precisam poder obter blobs- A chamada
getBlobembsky.socialretornou um redirecionamento 302 para a URL do PDS real, e ao seguir o redirecionamento com-L, o conteúdo HTML foi retornado normalmente
Headers de segurança, CDN e o custo do acesso direto
- As Considerações de Segurança da especificação de blobs do AT Protocol tratam dos riscos de segurança de conteúdo ao servir arquivos arbitrários enviados por usuários a partir de um servidor web
- Um exemplo clássico é o problema de XSS quando scripts ou conteúdo SVG são executados na mesma origin
- Aplicar Content Security Policy ao endpoint
getBlobé, na prática, obrigatório - Fornecer diretamente o armazenamento de blobs para navegadores e agentes web praticamente não é suportado; as aplicações devem passar por uma CDN separada, proxy ou outro serviço web
- O handler
getBlobdo PDS do Bluesky aplica os headers de segurança recomendadosx-content-type-options: nosniffcontent-security-policy: default-src 'none'; sandbox
- O limite padrão de upload de blobs é de 5 MB
- Os blobs de imagem normais do aplicativo Bluesky não são servidos diretamente pelo PDS, e sim por URLs de CDN em
cdn.bsky.app- Existem URLs separadas para thumbnail no feed e para tamanho completo
- O record da postagem inclui o CID da imagem, e a aplicação precisa saber como usar o esquema de entrega via CDN
- O acesso direto via
getBlobcontinua existindo por causa de casos como rotulagem de imagens, exportação de conteúdo do usuário e usos futuros, segundo discussões em issues do GitHub- Nessas mesmas discussões também aparece a possibilidade de usuários fazerem hotlink de conteúdo ou usarem o Bluesky como hospedagem gratuita
- Na implementação inicial não havia headers de segurança, que foram adicionados depois
- Em plataformas sociais tradicionais, os tipos de conteúdo válidos são mais limitados, então é possível impor restrições mais rígidas aos blobs já no momento do upload; no Bluesky e no AT Protocol, a extensibilidade exige um tratamento mais complexo
Inserindo um embed customizado em postagens com open union
- O tipo
app.bsky.feed.postdefine a lista de embeds válidos como uma union - No lexicon do AT Protocol, uma union é open por padrão, a menos que seja explicitamente marcada como
closed- Como novos tipos podem ser adicionados em revisões futuras do schema, as implementações devem ser flexíveis na validação
- Com a flag
closed, o conjunto de tipos fica fixo
- A union de embeds das postagens do Bluesky não está marcada como
closed - Por isso, é possível criar uma postagem mesmo com um
$typede embed não enumerado - No exemplo, foi inserido um embed
com.danielmangum.hack.sitesdentro de um recordapp.bsky.feed.post, e esse embed referenciava o blob HTML- O
validationStatusda resposta foivalid - No aplicativo Bluesky, esse embed é simplesmente ignorado em silêncio
- Como o conteúdo e a referência permanecem armazenados no record, outros aplicativos podem renderizar esse embed
- O
- Essa característica do lexicon pode ser usada para adicionar pequenas extensões sobre casos de uso já existentes; um exemplo citado é executar pequenos trechos de código dentro de uma postagem em um sandbox WebAssembly
1 comentários
Comentários no Hacker News
Foi legal o Daniel ter entrado em contato diretamente com a equipe, e hospedagem de blobs é uma área que inevitavelmente vai continuar sendo ajustada à medida que se entende melhor os caminhos de abuso
Por enquanto, é divertido ver esse tipo de uso funcionando de verdade, e a arquitetura pretendida é que o PDS seja um host de banco de dados, assim como um servidor web hospeda um site
Ele era divertido de brincar no passado, e eu não sabia que tinha migrado para o Bluesky; é bem interessante
O Bsky já oferece suporte a associar domínios de usuários como ALIAS para redirect.bsky.com: https://bsky.app/profile/jacob.gold/post/3kh6rnpdzmp2v
Fiquei curioso sobre em qual contexto de segurança isso é executado, então verifiquei uma URL de blob do PDS com
curl, e os cabeçalhos de resposta incluíamaccess-control-allow-origin: *,content-security-policy: default-src 'none'; sandbox,x-content-type-options: nosniff, entre outrosaccess-control-allow-origin: *é interessante porque significa que JavaScript de uma página web em qualquer domínio pode acessar esse conteúdo comfetch(), edefault-src 'none'; sandboxé uma configuração muito restritiva, o que é bom: impede o carregamento de scripts ou imagens adicionais e também bloqueia a execução de JavaScript: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Co...ratelimit-limit: 3000provavelmente parece ser um limite por IPA sugestão no fim do texto de usar WebAssembly está na direção certa, e o problema dos cliques em links pode ser limitado colocando código não confiável em um iframe e permitindo, pelo pai com
child-src, apenas domínios específicos oudata:https://github.com/w3c/webappsec/issues/656#issuecomment-246...
https://www.w3.org/TR/CSP3/#exfiltration
sandbox,default-srcainda é necessário, ou se isso é uma configuração redundanteEstou bem animado com a possibilidade de usar o Bluesky como repositório de dados blob
Pensei, junto com um amigo, em armazenar WADs de DOOM no Bluesky e compartilhar “map packs” como se fossem posts; se você seguir contas, listas e starter packs, daria para modificar um cliente como o GZDoom para pesquisar e ver os WADs enviados por essas contas
Seria parecido com o Steam Workshop, mas passando pelo Bluesky
Também não sei se o Bluesky já mencionou diretrizes para uso como armazenamento de blobs; arquivos de DOOM são pequenos, então são um bom exemplo, mas fico me perguntando se isso poderia ser abusado como forma de externalizar espaço de servidor em grande escala
Não vivi essa época específica, mas ver usuários do BlueSky se jogando em águas técnicas mais profundas me lembra os tempos em que as pessoas aprendiam HTML pela primeira vez no MySpace
O mercado de redes sociais está muito mais saturado do que antes, mas fico curioso se uma nova geração de programadores pode surgir do BlueSky
O Bluesky oferece só o primeiro degrau, e a partir daí parece haver um salto bem grande
Com HTTP/HTML, dá para mostrar a alguém que só conhece Python básico ou outra linguagem de programação como criar um servidor do zero em 14 minutos
Acho que precisamos de um protocolo de comunicação com endereçamento por hash para impedir que grandes empresas de tecnologia explorem comunidades, mas não tenho certeza de que o AT Protocol tenha acertado o alvo o bastante para desencadear uma revolução como o HTTP
Um dos pontos principais aqui é que o PDS em questão não é o produto Bluesky em si, mas parte de um Personal Data Server, então o resultado pode parecer um armazenamento de dados gratuito e infinito
O serviço de assinatura que a equipe do Bluesky mencionou algumas vezes parece poder estar ligado a isso, e uma hospedagem que ofereça mais espaço, largura de banda e vídeo em alta qualidade no PDS parece adequada para ser vendida como um nível premium
Deve ser possível hospedá-lo em outros lugares também, então parece correto dizer que dá para interagir para além do app do Bluesky
Parece que precisamos de um nome para o fenômeno em que, se você cria um jeito de colocar algo na internet, eventualmente alguém vai tentar fazer hospedagem arbitrária de arquivos em cima disso
Na época em que era ilimitado, surgiram vários projetos open source para fazer backup de sistemas de arquivos no Gmail etc.; depois que o Drive apareceu, ficou ainda pior
Serviços gratuitos precisam impor limites básicos já prevendo que esse tipo de problema vai surgir
https://en.wikipedia.org/wiki/Inner-platform_effect
Se esse tema parecer interessante, vale ver também o atfile: https://github.com/electricduck/atfile
É bem legal, e dá para ver direto uma issue interessante do GitHub linkada no fim do texto
A figura conhecida do Bluesky, pfrazee, também aparece: https://github.com/bluesky-social/atproto/issues/523
Tenho grandes expectativas para o AT, e certamente há muitas pessoas inteligentes que fizeram um excelente trabalho no Fediverse, mas esse paradigma parece mais sustentável e realista
A ideia é oferecer uma base centralizada, mas dar suporte real à descentralização quando necessário ou para usuários avançados
É preciso haver uma forma de gerar retorno sobre o investimento com o espelhamento do firehose; por exemplo, uma alternativa ao Discord em que alguns usuários paguem pelo custo de hospedar vídeos mais longos, uma estrutura no estilo Patreon em que relays gerenciem chaves de acesso e descriptografia e cobrem uma taxa, ou até um marketplace social como o Bandcamp
De todo modo, como é uma plataforma aberta, não há motivo para que isso já não possa ser feito
https://www.blockchaincapital.com/blog/bluesky-13m-users-and...
https://bsky.social/about/blog/09-11-2024-video
Fico com a impressão de que esse método pode ser abusado para phishing ou distribuição de malware
Parece quase uma lei da computação: se você cria um site de hospedagem, alguém vai tentar usá-lo para fins maliciosos
O mesmo problema já existiu com anexos no Matrix
*.bsky.networkdeve começar a ser bloqueado pelo Google Safe Browsing, Palo Alto, Bluecoat etc.Isso é um link direto para o servidor Bluesky do autor, ou seja, para o PDS, então naturalmente está sob controle do autor
As mudanças recentes na API do Strava me fizeram lembrar o quanto o acesso aos dados armazenados na plataforma deles é restrito
Como é o serviço dominante na área de fitness, eles também poderiam colocar recursos gradualmente atrás de uma assinatura
Pode haver preocupações de privacidade ou segurança, mas fico me perguntando se o AT Protocol poderia servir como uma plataforma de armazenamento para arquivos GPX ou FIT
Mas, até onde sei, o AT Protocol ainda não oferece suporte a postagens privadas ou com visibilidade limitada, e vejo isso como algo bastante essencial para o uso no estilo Strava