Preocupação de Segurança/Privacidade: E-mail exposto na URL de redirecionamento do provedor DiscourseConnect

Descreva o bug

Ao usar o Discourse como um Provedor DiscourseConnect (Provedor SSO), o endereço de e-mail do usuário é exposto no URL de redirecionamento 302 para a parte confiável (relying party). Isso ocorre porque o método populate_user_data em lib/second_factor/actions/discourse_connect_provider.rb sempre define o e-mail:

  def populate_user_data(sso)
    sso.name = current_user.name
    sso.username = current_user.username
    sso.email = current_user.email  # <-- Sempre incluído
    sso.external_id = current_user.id.to_s
    # ...
  end

Este e-mail é então codificado em Base64 e incluído no URL de redirecionamento:
https://site-alvo.com/callback?sso=<payload_base64>&sig=<assinatura_hmac>

A decodificação do payload base64 revela o endereço de e-mail em texto simples.

Impacto

  1. Histórico do navegador: O e-mail é registrado no histórico do navegador
  2. Logs do Nginx: O URL completo é registrado nos logs de acesso do nginx
  3. Logs do site de destino: A parte confiável recebe o e-mail sem consentimento explícito do usuário
  4. Expectativa do usuário: Os usuários geralmente autorizam para provar “Eu sou um usuário legítimo” - eles não esperam que seu e-mail seja compartilhado

Comportamento esperado

Os usuários devem ser capazes de controlar se seu e-mail é compartilhado com a parte confiável. Deve haver uma opção de configuração semelhante a discourse_connect_overrides_groups, discourse_connect_overrides_avatar, etc.

Atualmente, não há configuração de site para desativar esse comportamento. Escrever um plugin para substituir esse comportamento é possível, mas não ideal.

Etapas de reprodução

  1. Habilitar enable_discourse_connect_provider
  2. Configurar discourse_connect_provider_secrets (ex: *.example.com|secret123)
  3. Fazer um usuário autenticar via Provedor DiscourseConnect
  4. Verificar o URL de redirecionamento 302 - o e-mail é visível nos parâmetros do URL

O URL de redirecionamento se parece com:
https://parte-confiavel.com/sso?sso=bm9uY2U9xxx&sig=xxx

A decodificação do parâmetro sso revela:
nonce=xxx&return_sso_url=xxx&email=user@example.com&external_id=123

Ambiente

  • Versão do Discourse: (mais recente)
  • Auto-hospedado

Sugestões de correção possíveis

  1. Adicionar uma configuração de site como discourse_connect_provider_includes_email (padrão: true para compatibilidade com versões anteriores) para controlar se o e-mail é incluído na resposta
  2. Ou implementar o callback baseado em POST em vez de redirecionamento GET 302 para evitar o registro do URL
1 curtida

Isso também não é criptografado com o segredo compartilhado?

1 curtida

Olá Falco,

A assinatura HMAC apenas garante que a carga útil não foi adulterada - ela não criptografa os dados. Base64 é codificação, não criptografia, então qualquer um pode decodificá-la para ler o conteúdo.

O problema central é: não queremos expor informações desnecessárias do usuário (como e-mail) a “sites de terceiros que usam o Discourse para login SSO”. Os usuários autorizam apenas para provar “Eu sou um usuário legítimo” - eles não esperam que seu e-mail seja compartilhado.

Uma configuração de site para controlar se o e-mail é retornado seria aceitável?

Estou curioso, qual é esse terceiro de destino que implementou nosso protocolo SSO personalizado?

Eu diria que isso é pr-welcome, desde que não seja o padrão, para não quebrarmos sites existentes.

Obrigado pelo feedback!

Para dar um pouco de contexto sobre o caso de uso: nosso fórum é um “fórum do campus”, e um estudante construiu um site gratuito para outros estudantes usarem. Eles querem usar nosso fórum do campus baseado em Discourse para autenticar se um usuário é de fato um estudante em nossa escola - essencialmente provando “Eu sou um estudante legítimo aqui.”

Neste cenário, o site externo só precisa saber “este é um usuário válido do nosso fórum do campus” - eles não precisam necessariamente do e-mail do usuário, que é uma informação sensível que não deve ser compartilhada desnecessariamente.

Trabalharei em um PR que adiciona uma configuração de site para controlar esse comportamento, com um padrão que mantém a compatibilidade retroativa para instalações existentes.

2 curtidas