사용자 API 키는 OAEP 패딩을 사용해야 합니다

작은 문제 하나와 더 큰 문제 하나가 있습니다:

문서에 언급되지 않은 필수 nonce 파라미터가 있습니다:

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

이제 더 까다로운 문제입니다. Discourse는 인자 없이 public_encrypt 메서드를 호출합니다:

즉, padding 인자의 기본값은 PKCS1_PADDING이 됩니다. Ruby 문서에 따르면:

공개 키로 string을 암호화합니다. padding은 기본값이 PKCS1_PADDING이며, 이는 보안상 취약한 것으로 알려져 있지만 하위 호환성을 위해 유지되고 있습니다.

불행히도, Node v20.14.0(현재 LTS)에서는 RSA_PKCS1_PADDING으로 crypto.privateDecrypt를 호출하려고 하면 오류가 반환됩니다:

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 is no longer supported for private decryption, this can be reverted with --security-revert=CVE-2023-46809

Node 앱에 대한 가능한 해결 방법은 보안 해제 플래그를 사용하여 Node를 실행하는 것입니다:

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

Discourse 측에서 수정하는 것은 간단할 수 있지만, 기존 통합 기능의 상당수가 깨질 것으로 추정됩니다:

public_key = OpenSSL::PKey::RSA.new(params[:public_key])
@payload = Base64.encode64(public_key.public_encrypt(@payload, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING))
3개의 좋아요

@simon 네, Node v22에서 확실히 문제를 일으키고 있습니다. 보안 패치를 되돌리지 않는 것이 가장 좋습니다. API 호출이나 Discourse 사이트 설정에 플래그를 설정하여 원하는 패딩을 선택할 수 있으면 좋겠습니다. (이렇게 하면 원하는 경우 기존 기본값을 유지할 수 있습니다.)

1개의 좋아요

여기에 있는 단계를 대략적으로 따르면서 NodeRSA를 사용하면 작동합니다

이건 꽤 간단한 추가 기능인 것 같네요?

OAEP가 CCA / Bleichenbach 공격에 대한 저항성을 제공하므로 새로운 앱에 권장된다는 점은 이해합니다. Node가 우리에게 손을 들어주지 않는 것은 다소 아쉽지만, 이것은 아마도 '더 큰 선(善)'을 위한 일일 것입니다.

이 문제를 Discourse 관리자가 더 고려해야 할 또 다른 토글로 만드는 것에 대해 매우 우려하고 있습니다. 그것은 악몽이 될 것입니다.

대신, Discourse Hub를 수정하여 새로운 방식과 기존 방식을 동시에 지원하고, 공개 키의 '버전’을 나타내는 API 신호를 도입해야 합니다.

이것은 여러 시스템을 관통하는 복잡한 변경 사항입니다. 당신이 제안한 수정은 Discourse Hub가 해당 모드로 전환하는 관리자에게 더 이상 작동하지 않게 되는 문제를 일으키므로, 그 자체로 문제가 됩니다.

3개의 좋아요

추가 컨텍스트를 제공해 주셔서 감사합니다.

정리하자면, 이는 로컬 개발을 수행할 때 제가 겪는 문제입니다. 하지만 AWS EC2 인스턴스에 배포된 리소스에 연결할 때는 문제가 발생하지 않습니다. 해당 Node 버전에는 암호화 라이브러리가 이 문제를 겪지 않도록 하는 내부적인 커스터마이징이나 버전 관리가 적용되어 있을 것으로 추측됩니다.

늦게 합류했지만, 그 오류는 잘못된 것 같습니다. 이는 Node에서 제거된 기능이 아니라 특정 OpenSSL 설치 환경의 문제입니다. Node 문서를 참고하세요:

crypto.privateDecrypt()에서 crypto.constants.RSA_PKCS1_PADDING을 사용하려면 OpenSSL이 implicit rejection(rsa_pkcs1_implicit_rejection)을 지원해야 합니다.

참고: [Bug]: RSA_PKCS1_PADDING is no longer supported for private decryption · Issue #487 · bropat/eufy-security-client · GitHub

로컬에서 테스트해 보니, 암호화와 복호화 모두 패딩으로 crypto.constants.RSA_PKCS1_PADDING을 사용하도록 전환해도 저에게는 잘 작동합니다: An example of RSA Encryption implemented in Node.js · GitHub 저는 OpenSSL 3.4.0과 Node 23.6.1을 사용 중입니다.

사이트 설정을 사용하는 것의 까다로운 점은 클라이언트가 특정 인스턴스가 어떤 패딩을 지원하는지 알 수 없다는 것입니다. 이로 인해 인스턴스/서비스 간 호환성을 이해하기가 더 어려워집니다.

기존 구현을 명확히 해야 한다고 생각합니다. 즉, RSA_PKCS1_PADDING을 사용하고 있음을 명시적으로 기록하고, 이후 업그레이드에 대해 생각해 봐야 합니다. 아마도 해당 엔드포인트에 버전 관리를 도입하여 클라이언트가 해당 버전 이전/이후에 올바른 패딩을 깔끔하게 사용할 수 있도록 해야 할 수도 있습니다.

2개의 좋아요

참고로, 이것은 제가 직접 요청한 기능이 아니라, 지난해 6월에 제가 한 관찰입니다.

2개의 좋아요

PSA: 이 작업은 다음 커밋에 따라 수행되었습니다.

2개의 좋아요