여러 개의 데이터베이스를 지원하려면 해당 데이터베이스의 드라이버가 필요하다. Data-grip이라는 소프트웨어를 봐도 지원하는 데이터베이스가 어림잡아 10개가 넘어간다. 이때 들었던 생각은 ‘지원하는 데이터베이스가 늘어날 때마다 배포되는 사이즈가 커진다’ 였다.

사실 생각보다 그렇게 많은 데이터베이스를 사용하지는 않는다. 나를 비롯해서 다른 사용자들을 봐도 사용하는 것만 사용하기 때문에 사용자가 사용할지 안할지 모르는, 알 수 없는 상황에서 모든 드라이버를 추가하는 것은 배포되는 파일 크기만 늘리는 것이다.

이를 해결하기 위해서 ‘사용자가 직접 사용하는 드라이버만 다운로드를 하게하여 배포 사이즈를 줄일 수 없을까?’ 라는 생각을 하게 되었고 간단한 시나리오로 사용자가 데이터베이스를 선택하고 연결 버튼을 클릭하면 그때 해당 드라이버를 다운받아서 연결을 하게하는 워크플로우로 동작하게 설계하였다.

프로그램이 연결을 하거나 동작을 하려면 결국 외부 파일(사용자가 다운 받은 드라이버)에 접근을 해서 동작을 하는 상황이므로 결과적으로 보안이 가장 중요하다고 생각을 했다.

flowchart LR
    Dev["👩‍💻 개발자"]

    subgraph PRIV["🔒 Private Repository (monorepo)"]
        PrivCode["전체 소스 코드<br/>+ 드라이버 빌드 스크립트"]
        CI["GitHub Actions<br/>빌드 · 서명"]
    end

    subgraph PUB["🌐 Public Repository"]
        PubCode["미러링된 코드"]
        Rel["Releases<br/>드라이버 번들 + manifest + 서명"]
    end

    App["💻 사용자 앱"]

    Dev -- "1. 코드 커밋" --> PrivCode
    PrivCode -- "2. 미러링 (단방향 push)" --> PubCode
    PrivCode -- "3. main 머지" --> CI
    CI -- "4. 서명 후 릴리스 생성" --> Rel
    Rel -- "5. 연결 시 다운로드 · 검증" --> App

    classDef private fill:#fde2e2,stroke:#c0392b,color:#000
    classDef public fill:#e2f0fd,stroke:#2471a3,color:#000
    class PrivCode,CI private
    class PubCode,Rel public

보안

항목 핵심 조치
공급망 버전 고정, 의존성 감사, manifest 서명
로컬 변조 로드 시마다 해시 검증
악성 서버 드라이버 최신 패치 유지
XSS textContent 렌더링, CSP, sandbox
IPC 이름만 받고 URL/경로는 main이 결정
자격 증명 safeStorage, renderer에 노출 금지
TLS 검증 끄기 기본값 금지, 경고 표시
SSH 호스트 키 확인 및 저장

조사를 해본 결과 위의 리스트 정도의 보안 요소를 확인하였고 드라이버 파일 배포와 직간접적으로 관련이 있는 공급망, 로컬변조를 처리하기로 했다. XSS, IPC, 자격 증명의 경우 코딩에서 처리할 문제였고 TLS와 SSH는 나중에 지원하는 걸로 결정했다.

Manifest 서명

유효한 파일인지를 검증하기 위해서 드라이버 파일과 manifest 서명 파일을 같이 배포했다. manifest에 있는 정보로 검증을하는데 이때 manifest 파일이 유효한지 확인하기 위해 서명이라는 것을 이용하는데 크게 세 가지 방식을 사용할 수 있다.

HMAC (대칭키): 서명과 검증에 같은 키를 쓰는데, 검증하려면 앱에 그 키를 넣어야 하고, 앱을 뜯으면 누구나 서명을 위조할 수 있게 된다. 비대칭 서명이 필요한 이유가 이것이다.

RSA: 가장 오래되고 호환성이 좋다. 대신 키와 서명이 길다. 2048비트 RSA의 서명은 256바이트, 개인키 PEM은 여러 줄에 걸친다

타원곡선 (ECDSA / Ed25519): 훨씬 짧은 키로 같은 수준의 보안을 얻는다.

Ed25519를 고른 이유

구현 실수 여지가 적다. ECDSA는 서명할 때마다 난수(nonce)가 필요한데, 이 난수가 재사용되거나 예측 가능하면 개인키가 통째로 노출된다. Ed25519는 난수 대신 메시지와 개인키로부터 결정적으로 값을 유도하는 방식이라 이 실패 모드가 구조적으로 없다. RSA 대비 장점(짧은 키로 소스에 넣기 편함, 파라미터 선택 불필요)도 있다.

openssl을 이용해서 키를 생성하고 공개키를 추가하였다.

스크린샷 2026-10-02 오후 5.43.59.png

비공개 키를 github CI 과정에 추가해서 서명을한다. 이렇게 해야 공개된 키로 유효한지를 검증할 수 있다.

sequence, expiresAt, TRUSTED_KEYS[keyId] 를 이용해서 롤백 공격 방지, manifest 만료, 키 교체 대비라는 중요한 장치이다. 키를 여러개 넣으면 좋은데 현재는 하나만 넣고 테스트를 해보고 있다. 특히 keyId는 개인키가 유출되었을 떄를 대비해서 여러개의 등록된 키 가운데 다른 키를 선택하기 위한 설정이다. 예를 들어 A 개인키가 유출되었을 때 keyId를 교체해서 다른 B key를 사용하도록 하기 위함이다.