Las claves API de los usuarios deberían utilizar relleno OAEP

Un problema menor y quizás uno mayor:

Hay un parámetro nonce obligatorio que no se menciona en la documentación:

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

Ahora el problema más complicado. Discourse llama al método public_encrypt sin argumentos:

Eso significa que el argumento padding se establece por defecto en PKCS1_PADDING. Según la documentación de Ruby:

Cifra string con la clave pública. padding se establece por defecto en PKCS1_PADDING, que se sabe que no es seguro pero se mantiene por compatibilidad con versiones anteriores.

Desafortunadamente, Node v20.14.0 (el LTS actual) devuelve un error si intentas llamar a crypto.privateDecrypt con 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 ya no se admite para la descifración privada; esto se puede revertir con --security-revert=CVE-2023-46809

Una posible solución para las aplicaciones Node es ejecutar Node con la bandera insegura:

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

Una solución en el lado de Discourse sería fácil, pero sospecho que rompería muchas integraciones 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 Me gusta

@simon Sí, esto definitivamente está causando problemas con Node v22. Sería genial no revertir los parches de seguridad. Sería bueno establecer una bandera en la llamada a la API o una configuración del sitio en Discourse para elegir el relleno deseado. (De esa manera, las personas pueden mantener el valor predeterminado existente si lo desean).

1 me gusta

Aproximadamente siguiendo los pasos aquí, NodeRSA funciona

¿Parece una adición bastante simple?

Entiendo que se recomienda OAEP para nuevas aplicaciones que sean resistentes a ataques CCA / Bleichenbach. Que Node nos obligue a hacer esto es un poco triste, pero supongo que es una cuestión de “un bien mayor”.

Me preocupa enormemente que esto se convierta en otro interruptor que un administrador de Discourse deba considerar, eso es una pesadilla.

En su lugar, necesitaríamos arreglar Discourse Hub para que admita simultáneamente las versiones nueva y antigua, y que algo en nuestra API señale la “versión” de la clave pública.

Es un cambio complicado que afecta a varios sistemas. La solución que propusiste es un problema porque entonces Discourse Hub dejará de funcionar para los administradores que cambien a ese modo.

3 Me gusta

Gracias por el contexto adicional.

Para aclarar, esto es algo con lo que tengo problemas cuando hago desarrollo local. Pero al conectarme a nuestros recursos desplegados en instancias de AWS EC2, no es un problema. Supongo que su versión de Node tiene algunas personalizaciones o versiones internas donde la biblioteca de criptografía no presenta este problema.

Entro en frío aquí, pero ese error parece incorrecto. Esto no es una característica que se haya eliminado en Node, es un problema con alguna instalación de OpenSSL. De la documentación de Node:

El uso de crypto.constants.RSA_PKCS1_PADDING en crypto.privateDecrypt() requiere que OpenSSL admita el rechazo implícito (rsa_pkcs1_implicit_rejection).

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

Probando localmente, esto funciona para mí: An example of RSA Encryption implemented in Node.js · GitHub incluso cuando cambio a usar crypto.constants.RSA_PKCS1_PADDING para el relleno tanto para cifrar como para descifrar. Estoy en OpenSSL 3.4.0 y Node 23.6.1.

Lo complicado de usar una configuración del sitio es que los clientes no sabrán qué relleno admite la instancia específica. Eso hace que la compatibilidad entre instancias/servicios sea más difícil de entender.

Creo que deberíamos aclarar la implementación existente, es decir, señalar explícitamente que estamos usando RSA_PKCS1_PADDING y luego pensar en una actualización. Quizás necesitemos introducir versionado para este endpoint, para que los clientes puedan usar limpiamente el relleno correcto antes/después de dicha versión.

2 Me gusta

Para contexto, esta no es una solicitud de función por mi parte, solo una observación que hice en junio del año pasado.

2 Me gusta