As chaves de API do usuário devem usar preenchimento OAEP

Um problema menor e talvez um maior:

Há um parâmetro nonce obrigatório que não é mencionado na documentação:

  def require_params
    %i[public_key nonce scopes client_id application_name].each { |p| params.require(p) }
  end

Agora o problema mais complicado. O Discourse chama o método public_encrypt sem argumentos:

Isso significa que o argumento padding tem como padrão PKCS1_PADDING. Da documentação Ruby:

Criptografa string com a chave pública. padding tem como padrão PKCS1_PADDING, que é conhecido por ser inseguro, mas é mantido por compatibilidade retroativa.

Infelizmente, o Node v20.14.0 (o atual LTS) retorna um erro se você tentar chamar crypto.privateDecrypt com RSA_PKCS1_PADDING:

function decryptData(data: string, privateKey: string) {
  const buffer = Buffer.from(data, "base64");
  const decrypted = crypto.privateDecrypt(
    {
      key: privateKey,
      padding: crypto.constants.RSA_PKCS1_PADDING,
    },
    buffer
  );
  return decrypted.toString("utf8");
}

TypeError: RSA_PKCS1_PADDING não é mais suportado para descriptografia privada, isso pode ser revertido com --security-revert=CVE-2023-46809

Uma possível solução para aplicativos Node é executar o Node com a flag insegura:

node --security-revert=CVE-2023-46809

Uma correção no lado do Discourse seria fácil, mas suspeito que quebraria muitas integrações existentes:

public_key = OpenSSL::PKey::RSA.new(params[:public_key])
@payload = Base64.encode64(public_key.public_encrypt(@payload, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING))
3 curtidas

@simon Sim, isso definitivamente está causando problemas com o Node v22. Seria ótimo não reverter os patches de segurança. Seria bom definir um sinalizador na chamada da API ou uma configuração do site no Discourse para escolher o preenchimento desejado. (Dessa forma, as pessoas podem manter o padrão existente, se quiserem.)

1 curtida

Seguindo aproximadamente os passos aqui, usando NodeRSA funciona

Isso parece uma adição bem simples?

Entendo que OAEP é recomendado para novas aplicações que resistem a ataques CCA / Bleichenbach. O Node nos forçando a isso é um pouco triste, mas acho que é uma questão de “bem maior”.

Estou extremamente preocupado em tornar isso apenas mais uma opção para um administrador do Discourse raciocinar, isso é um pesadelo.

Em vez disso, precisaríamos corrigir o Discourse Hub para suportar as versões nova e antiga simultaneamente, ter algo em nossa API que sinalize a “versão” da chave pública.

É uma mudança complicada que afeta vários sistemas. A correção que você propôs é um problema, pois o Discourse Hub deixará de funcionar para administradores que mudarem para esse modo.

3 curtidas

Obrigado pelo contexto adicional.

Para deixar claro, isso é algo com que eu tenho problemas ao fazer desenvolvimento local. Mas ao me conectar aos nossos recursos implantados em instâncias AWS EC2, não é um problema. Acho que a versão do Node deles possui algumas personalizações ou versionamentos nos bastidores, onde a biblioteca de criptografia não apresenta esse problema.

Chegando agora, mas esse erro parece incorreto. Isso não é um recurso que foi removido no Node, é um problema com alguma instalação do OpenSSL. Da documentação do Node:

Usar crypto.constants.RSA_PKCS1_PADDING em crypto.privateDecrypt() requer que o OpenSSL suporte rejeição implícita (rsa_pkcs1_implicit_rejection).

Veja também [Bug]: RSA_PKCS1_PADDING is no longer supported for private decryption · Issue #487 · bropat/eufy-security-client · GitHub

Testando localmente, isso funciona para mim: An example of RSA Encryption implemented in Node.js · GitHub mesmo quando mudo para usar crypto.constants.RSA_PKCS1_PADDING para o preenchimento tanto para criptografia quanto para descriptografia. Estou no OpenSSL 3.4.0 e Node 23.6.1.

A coisa complicada em usar uma configuração de site é que os clientes não saberão qual preenchimento a instância específica está suportando. Isso torna a compatibilidade entre instâncias/serviços mais difícil de entender.

Acho que devemos esclarecer a implementação existente, ou seja, observar explicitamente que estamos usando RSA_PKCS1_PADDING e, em seguida, pensar em uma atualização. Talvez precisemos introduzir versionamento para este endpoint, para que os clientes possam usar corretamente o preenchimento antes/depois de dita versão.

2 curtidas

Para contextualizar, isso não é um pedido de recurso meu, é apenas uma observação que fiz em junho do ano passado.

2 curtidas