O blog da AWS
Protegendo URLs pré-assinadas do HAQM S3 para aplicativos Serverless
Por Raaga N.G, Arquiteta de soluções senior na HAQM Web Services (AWS) e Ryan Hillard, Arquiteto de soluções na HAQM Web Services (AWS).
Os aplicativos modernos Serverless devem ser capazes de lidar perfeitamente com carregamentos de arquivos grandes. Esta postagem demonstra como aproveitar as URLs pré-assinadas do HAQM Simple Storage Service (HAQM S3) para permitir que seus usuários façam upload de arquivos com segurança para o S3 sem exigir permissões explícitas na conta da AWS. Esta postagem se concentra especificamente nas ramificações de segurança do uso de URLs pré-assinadas do S3 e explica as etapas de mitigação que os desenvolvedores Serverless podem adotar para melhorar a segurança de seus sistemas usando URLs pré-assinadas do S3. Além disso, a postagem também mostra uma função do AWS Lambda que segue as recomendações sugeridas, garantindo uma abordagem robusta e segura para lidar com URLs pré-assinadas do S3. Para obter mais informações sobre URLs pré-assinadas do S3, consulte Como trabalhar com URLs pré-assinadas.
Fluxo de trabalho de URL pré-assinada para aplicativos Serverless
O diagrama de arquitetura a seguir mostra um aplicativo Serverless que gera uma URL pré-assinada do S3. Ao usar URLs pré-assinadas do S3, os aplicativos Serverless podem transferir para o S3 a responsabilidade necessária para receber arquivos. O diagrama captura um processo de sete etapas entre o cliente, o HAQM API Gateway, a função Lambda e o S3.
Um fluxo de trabalho típico para carregar um arquivo em um aplicativo Serverless hospedado no S3 inclui as seguintes etapas:
- O cliente envia uma solicitação para fazer o upload de um arquivo.
- O API Gateway recebe a solicitação do cliente e invoca uma função Lambda que, em seguida, gera a URL pré-assinada do S3.
- A função Lambda faz uma chamada de API getSignedURL para o S3.
- O S3 retorna a URL pré-assinada do objeto a ser carregado.
- A função Lambda retorna uma URL pré-assinada para a API.
- O cliente recebe a URL pré-assinada do S3 para carregar o arquivo.
- O cliente carrega o arquivo diretamente no S3 usando a URL pré-assinada.
Como proteger URLs pré-assinados
Ao projetar um aplicativo Serverless que utiliza URLs pré-assinados do S3 para armazenar dados no S3, o desenvolvedor deve considerar vários aspectos principais de segurança. As URLs pré-assinadas do S3 são recursos públicos que não autenticam usuários, e qualquer pessoa que possua uma URL pré-assinada do S3 válido pode acessar o recurso associado. Consequentemente, é importante implementar medidas de segurança adicionais para garantir que essas URLs não sejam usadas indevidamente ou acessados por partes não autorizadas. O conteúdo a seguir contém técnicas que você pode usar para tornar seus URLs pré-assinados mais seguros.
1. Adicionar um checksum Content-MD5 usando o cabeçalho X-Amz-Signed
Ao fazer upload de um objeto para o S3, você pode incluir um checksum pré-calculado do objeto como parte da sua solicitação. O S3 executará uma verificação de integridade e verificará se o objeto enviado é igual ao objeto recebido. O S3 suporta o uso de checksums de verificação MD5 para verificar a integridade dos objetos carregados. Você fornece o digest MD5 incluindo um cabeçalho Content-MD5 na solicitação PUT inicial. Ao receber o objeto, o S3 calculará o digest MD5 e o comparará com o que você forneceu originalmente. A operação de upload será bem-sucedida somente se os dois resumos MD5 corresponderem, garantindo a integridade dos dados de ponta a ponta. Se uma pessoa não intencional colocar as mãos na URL pré-assinada do S3, ela não poderá usá-la sem possuir o mesmo objeto. Isso fornece proteção contra carregamentos arbitrários de arquivos.
O elemento-chave que um desenvolvedor deve lembrar é que, quando o cliente carrega o arquivo na URL pré-assinada do S3, ele deve fornecer o MD5 correto em Base64 usando o cabeçalho Content-MD5. Os desenvolvedores podem ver um exemplo de aplicativo Serverless com código do lado do cliente para extrair o digest MD5, solicitar uma URL pré-assinada do S3 e fazer upload de um arquivo neste repositório do GitHub. Esse aplicativo de exemplo usa o NodeJS v20 na função Lambda.
2. Expirar as URLs pré-assinadas do S3
Uma URL pré-assinada do S3 permanece válida pelo período de tempo especificado quando a URL é gerada. É importante garantir que a URL pré-assinada do S3 não permaneça acessível por mais tempo do que o necessário, pois ela pode ser reutilizada quando ainda é válida. Você pode definir o tempo de expiração da URL pré-assinada do S3 passando X-Amz-Expires como parâmetro de consulta ou definindo o parâmetro expiresIn ao usar o SDK da AWS para JavaScript.
O S3 valida a data e a hora de expiração no momento da solicitação HTTP inicial. No entanto, para suportar situações em que a conexão é interrompida e o cliente precisa reiniciar o upload de um arquivo, convém que sua URL pré-assinada do S3 permaneça válida por todo o tempo previsto necessário para carregar o arquivo no S3. O desafio é gerar uma URL pré-assinada do S3 que seja válida por tempo suficiente para acomodar o upload do arquivo, mas ainda curta o suficiente para evitar a reutilização.
Uma solução que propomos para superar esses desafios é definir dinamicamente o tempo de expiração da URL pré-assinada do S3 usando a API de informações de rede do navegador. Usando essa nova API, quando o navegador do cliente faz a solicitação inicial de uma URL pré-assinada do S3, o cliente também transmite o tamanho do arquivo e o tipo de rede, para que a função Lambda possa calcular o tempo de transferência previsto.
Na função Lambda, agora podemos estimar o tempo de transferência desse tamanho de arquivo nesse tipo de rede, usando o código de exemplo apresentado neste repositório do GitHub.
Com o tempo estimado de transferência calculado, a função Lambda agora pode solicitar a URL pré-assinada do S3 e definir o parâmetro expireSin para o tempo de transferência, resultando em uma URL pré-assinada do S3 que só está disponível pelo tempo necessário para carregar esse tamanho de arquivo nesse tipo de rede.
Se você estiver usando o SDK da AWS, também poderá usar o AWS Signature versão 4 (SigV4) para assinar suas solicitações. Para criar uma abordagem de defesa aprofundada, que colocará um limite no tempo total de expiração, você pode utilizar chaves de condição nas políticas do bucket. Para ver um exemplo de política, consulte Limitação de recursos de URL pré-assinados.
3. Gerando um UUID para substituir o nome do arquivo carregado
Quando um aplicativo permite que um usuário faça upload de arquivos, ele se expõe a várias ameaças à segurança, como ataques de passagem de caminhos (path traversal attacks). As vulnerabilidades de passagem de caminhos permitem que os invasores acessem arquivos que não devem ser acessados ou substituam arquivos fora da estrutura de diretórios pretendida. Para proteger seus aplicativos contra essas vulnerabilidades, a abordagem mais eficaz é incorporar a validação e a higienização das entradas do usuário. Você pode limpar o nome do arquivo substituindo-o por um UUID (Identificador Único Universal) gerado.
Você pode ver um exemplo de função no código do lado do servidor para o Lambda neste repositório do GitHub.
4. Aplicando o Princípio do Privilégio Mínimo e usando uma função Lambda separada para criar URLs pré-assinadas do S3
Os recursos de uma URL pré-assinada do S3 são limitados pelas permissões do “Principal” (usuário ou conta) que o criou. Para oferecer acesso refinado, a primeira etapa para limitar o uso de uma URL pré-assinada do S3 deve ser criar uma função Lambda específica que gere essas URLs. Ao ter uma função Lambda dedicada a essa finalidade, você não corre o risco de uma função Lambda excessivamente permissiva. A segunda etapa é limitar o acesso de sua função específica do Lambda ao S3.
Seguindo o Princípio do Privilégio Mínimo, é importante restringir as permissões da função Lambda somente aos prefixos necessários no bucket e permitir que ela execute somente as ações necessárias no bucket, em vez de conceder acesso total ao bucket. Isso minimiza a potencial superfície de ataque e reduz o risco de exposição ou modificação não intencional dos dados. É importante limitar as permissões ao conjunto mínimo necessário de ações e recursos.
Este exemplo de política do AWS Identity and Access Management (IAM) demonstra como conceder à função Lambda acesso de leitura (GET) a objetos dentro do prefixo “Example-Prefix” de um bucket S3 específico. A política do IAM é anexada à função Lambda por meio de uma função de execução, que, em conjunto, estabelece quais ações a função Lambda pode realizar.
Este exemplo de política do IAM demonstra como conceder à função Lambda permissões para fazer upload (PUT) de objetos dentro do prefixo “Example-Prefix” de um bucket S3 específico.
Essa abordagem garantirá que sua função Lambda possua as permissões mínimas necessárias para realizar as tarefas pretendidas e reduza o risco de acesso ou modificação não intencional de dados.
Se você quiser restringir o uso de URLs pré-assinadas do S3 e todo o acesso do S3 a um caminho de rede específico, você também pode definir uma política de restrição de caminho de rede no S3 Bucket. Essa restrição no bucket exige que todas as solicitações para o bucket sejam originadas de uma rede especificada. A orientação prescritiva da AWS afirma que uma extensão de menor privilégio é manter um perímetro de dados consistente com as necessidades da sua organização. O objetivo de um perímetro da AWS é garantir que o acesso seja permitido somente se a solicitação for proveniente de uma entidade confiável, para recursos confiáveis de uma rede confiável. Esses perímetros de dados também se aplicam às URLs pré-assinadas do S3.
5. Criação de URLs pré-assinados do S3 de uso único
Os desenvolvedores de aplicativos Serverless podem querer que cada URL pré-assinada do S3 seja usada apenas uma vez. Os desenvolvedores podem incorporar um mecanismo baseado em tokens para facilitar o uso seguro e único de uma URL pré-assinada do S3. Isso envolve a geração de tokens exclusivos para cada usuário ou cliente autorizado e a associação desses tokens às URLs pré-assinadas do S3. Quando um cliente tenta acessar o recurso usando a URL pré-assinada do S3, ele deve fornecer o token correspondente para validação. Essa camada adicional de segurança garante que somente entidades autorizadas possam acessar as URLs pré-assinadas do S3 e os recursos associados. Além disso, você pode aproveitar um banco de dados para rastrear os tokens emitidos e expirá-los após cada uso. Uma solução para implementar esse mecanismo foi discutida em detalhes em Como transferir arquivos com segurança com URLs pré-assinadas.
Limpando
Você pode limpar o aplicativo de exemplo excluindo o API Gateway, a função Lambda e o bucket do S3. Além disso, não se esqueça de excluir todas as funções de execução do IAM que você criou para a função Lambda.
Conclusão
Nesta postagem,, discutimos várias considerações que um desenvolvedor deve fazer ao projetar um aplicativo que utiliza URLs pré-assinados do S3. Ao incorporar medidas de segurança robustas, como controle de acesso adequado, higienização de entradas, tratamento de expiração e verificações de integridade, os desenvolvedores podem mitigar riscos potenciais ao usar URLs pré-assinados do S3.
Este conteúdo foi traduzido da postagem original do blog, que pode ser encontrada aqui.
Autores
![]() |
Raaga N.G é uma Arquiteta de soluções senior na HAQM Web Services (AWS). |
![]() |
Ryan Hillard é Arquiteto de soluções na HAQM Web Services (AWS). |
Tradutor
![]() |
Daniel Abib é Arquiteto de Soluções Sênior e Especialista em HAQM Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem. |
Biografia do Revisor
![]() |
Rodrigo Peres é Arquiteto de Soluções na AWS, com mais de 20 anos de experiência trabalhando com arquitetura de soluções, desenvolvimento de sistemas e modernização de sistemas legados |