⚡ Electron6. 패키징 & 배포04. Code Signing — Authenticode와 Developer ID

04. Code Signing — Authenticode와 Developer ID

사용자 디스크에 binary를 까는 순간, OS는 묻는다 — “이 binary가 누구의 것이냐”. 답은 코드 서명이다. 누군가가 돈을 내고 발급받은 인증서로 binary에 서명하고, OS는 그 서명을 공인된 CA의 루트까지 추적해 신뢰한다. 이 문서는 인증서의 비용·발급·갱신·실제 트러블슈팅까지 다룬다.


한 줄 답

코드 서명은 binary의 출처를 OS에게 증명하는 신뢰 사슬이다. Windows는 Authenticode (EV vs OV 인증서로 평판 차이), macOS는 Developer ID (Apple Developer Program $99/yr). 둘 다 없으면 사용자에게 “이 앱은 신뢰할 수 없습니다” 경고가 뜬다.


Why — 서명이 운영 필수 인프라가 된 이유

웹은 TLS 인증서 한 장으로 끝난다 — 서버 신뢰. 그런데 디스크에 깔리는 binary는 다른 문제다.

위협서명이 막는 것
MITM 변조다운로드 도중 누가 binary에 malware 주입 → 서명 깨짐 → OS 차단
출처 위조”Microsoft 발 업데이트”라고 위장한 binary → CA가 그 이름으로 안 발급
사후 변조디스크의 .exe를 다른 프로세스가 패치 → 서명 검증 실패
사용자 사회공학사용자가 “이상한 다운로드”를 받았을 때, OS가 명확한 발행자 이름을 보여줌

즉, 코드 서명은 그 자체로 보안이 아니라 — 공격 비용을 올리고, 사용자에게 신뢰 신호를 준다. 서명 없는 binary는 2025년 OS에서 사실상 배포 불가.


How — Windows Authenticode

인증서 두 종류 — OV vs EV

종류풀네임비용 (연)SmartScreen 평판키 보관
OVOrganization Validation150 150~400천천히 누적 (수천 다운로드 + 수 주)보통 USB token (2023~)
EVExtended Validation300 300~700즉시 부여하드웨어 토큰 강제 (FIPS 140-2)

2023년 6월 이후, OV도 하드웨어 키 보관이 강제됐다 (CA/Browser Forum의 Baseline Requirements 업데이트). 즉 클라우드 CI에서 자동 서명이 어려워졌다 — Azure Key Vault 등 HSM 서비스로 우회.

SmartScreen — Windows의 평판 시스템

  • Windows Defender SmartScreen은 어떤 서명자가 얼마나 다운로드되었는지로 평판을 매긴다.
  • 낮은 평판: 사용자에게 “이 앱은 잘 알려지지 않았습니다 — 더 많은 정보” 경고. 절반 이상이 닫음.
  • EV 인증서는 이 단계를 스킵 — 발급 즉시 평판 부여.
  • 그래서 신규 배포에 EV가 거의 필수.

서명 명령 (signtool.exe)

# Windows SDK의 signtool — electron-builder가 내부적으로 호출
signtool sign ^
  /tr http://timestamp.digicert.com ^   /* timestamping (필수!) */
  /td sha256 ^
  /fd sha256 ^
  /sha1 <인증서 thumbprint> ^
  myapp-setup.exe

timestamping: 서명 시점의 신뢰할 만한 timestamp를 함께 박는다. 인증서가 5년 뒤 만료되더라도, 서명 당시 유효했음이 증명되면 OS는 binary를 영구적으로 신뢰한다. 빼먹으면 인증서 만료 시 과거 binary가 갑자기 안 열린다.

electron-builder 설정

win:
  target: nsis
  publisherName: "My Co Inc."
  signtoolOptions:
    sign: ./scripts/sign.js     # 커스텀 서명 함수 (HSM 호출 등)
    signingHashAlgorithms: [sha256]
    additionalCertificateFile: build/cert.pem

scripts/sign.js (HSM/cloud 서명):

exports.default = async function (config) {
  const { path: filePath } = config;
  // Azure Key Vault, AWS CloudHSM, DigiCert KeyLocker 등 호출
  await runSignCommand({
    keyVaultName: 'my-kv',
    certName: 'my-cert',
    file: filePath,
    timestampUrl: 'http://timestamp.digicert.com'
  });
};

Windows 인증서 발급 흐름

  1. CA 선택 — DigiCert / Sectigo / SSL.com / GlobalSign
  2. organization 검증 — 사업자등록증, 전화 인증 (영어 응답), DUNS number
  3. 하드웨어 토큰 수령국제 배송. 시간 걸림 (1~3주)
  4. PIN 설정 + signtool 등록
  5. CI 통합USB 토큰을 CI 서버에 꽂거나, Azure Key Vault/eSigner로 클라우드 서명

이 과정이 1~3주 걸린다. 출시 일정 잡을 때 반드시 미리 시작.


How — macOS Developer ID

Apple Developer Program

  • 연 $99 USD (organization 또는 individual).
  • organization은 D-U-N-S number 필요 → 신청 후 전화 인증 (북미 office hours).
  • individual은 본인의 이름이 그대로 노출 — 보통 organization 권장.

인증서 종류

인증서용도
Developer ID Application.app 본체 서명 (필수)
Developer ID Installer.pkg installer 서명 (pkg 빌드 시)
Mac App DistributionMac App Store 빌드
Mac Installer DistributionMac App Store pkg
Apple Development로컬 개발용 (CI에는 부적합)

서명 명령 (codesign)

# .app 본체 서명
codesign --force --deep --options runtime \
  --entitlements build/entitlements.mac.plist \
  --sign "Developer ID Application: My Co Inc. (XXXXXXXXXX)" \
  MyApp.app
 
# 검증
codesign --verify --deep --strict --verbose=2 MyApp.app
spctl -a -t exec -vv MyApp.app   # Gatekeeper 시뮬레이션

--deep.app 안의 모든 내부 binary (frameworks, helpers, native modules)에 재귀 서명. 하나라도 안 된 게 있으면 전체 실패. --options runtimehardened runtime 적용 — notarization 전제조건. 05 notarization에서 자세히.

electron-builder 설정

mac:
  target:
    - target: dmg
      arch: [x64, arm64]
    - target: zip
      arch: [x64, arm64]
  identity: "Developer ID Application: My Co Inc. (XXXXXXXXXX)"
  hardenedRuntime: true
  entitlements: build/entitlements.mac.plist
  entitlementsInherit: build/entitlements.mac.plist
  gatekeeperAssess: false       # CI 환경에서 시도 안 함 (notarize에서 함)

build/entitlements.mac.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  {/* Electron이 V8 JIT에 필요 */}
  <key>com.apple.security.cs.allow-jit</key>
  <true/>
 
  {/* node native modules의 unsigned 코드 허용 */}
  <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
  <true/>
 
  {/* dyld env vars (electron 빌드 도구가 필요할 수 있음) */}
  <key>com.apple.security.cs.allow-dyld-environment-variables</key>
  <true/>
 
  {/* 필요한 경우만 */}
  <key>com.apple.security.device.audio-input</key>
  <true/>
  <key>com.apple.security.device.camera</key>
  <true/>
</dict>
</plist>

entitlements가 너무 관대하면 Apple 리뷰가 까다로워질 수 있고, 너무 좁으면 앱이 일부 기능에서 죽는다. 균형이 어려움.


What — 비용 한눈에

항목비용 (연)비고
Apple Developer Program$99organization 권장
Windows OV 인증서150 150~400DigiCert/Sectigo. HSM token 별도
Windows EV 인증서300 300~700SmartScreen 즉시 평판. 신규 배포는 거의 필수
HSM 클라우드 서비스 (Azure Key Vault, DigiCert KeyLocker)10 10~100/moCI 자동 서명용 (USB token 대안)
Microsoft Store 개인$19 (1회)organization은 $99/년
Mac App Store(Apple Dev Program에 포함)추가 비용 없음
합계 (최소)~$400/년Apple + Win OV (UI 우회)
합계 (권장)~800 800~1,000/년Apple + Win EV + 클라우드 HSM

출시 결정의 연 운영 비용이 시작되는 지점이다. 1인 개발자가 가장 놀라는 부분.


What-if — 실제 실패 사례

함정증상해결
timestamping 누락인증서 만료 후 과거 binary모두 안 열림signtool /tr 옵션, electron-builder는 기본 자동
EV 인증서가 USB token에 있는데 CI에서 못 씀CI 매번 사람이 PIN 입력DigiCert KeyLocker / Azure Key Vault로 클라우드 HSM 마이그레이션
--deep 빼먹음내부 native module 한 개가 unsigned → Gatekeeper 거부electron-builder는 자동. 직접 codesign 호출 시 명시
entitlements에 allow-jit 빠짐macOS 10.15+에서 V8이 segfaultentitlements에 com.apple.security.cs.allow-jit
인증서 이름이 정확히 일치 안 함"Developer ID Application: My Co" vs "Developer ID Application: My Co Inc."security find-identity -v -p codesigning로 정확한 이름 확인
새 도메인에 새 EV 인증서 발급 → SmartScreen이 그래도 경고EV가 평판을 즉시 부여한다는 건 Microsoft 평판 DB가 인증서를 인지한 이후인증서 발급 후 수 시간~수일 기다림. 첫 다운로드는 경고 가능
macOS 13+ 에서 quarantine 비트 때문에 안 열림dmg에서 끌어다 놓은 .app이 xattr -p com.apple.quarantine 보유notarization + stapler로 ticket을 박아야 함 → 다음 문서
organization 이름이 바뀌었는데 인증서 갱신 안 함사용자에게 다른 발행자로 보임 → 신뢰 신호 깨짐사명 변경 시 인증서 재발급 (1~3주)

Insight — 흥미로운 이야기

“2023년 6월 — Windows 코드 서명의 Big Bang

CA/Browser Forum의 Baseline Requirements 업데이트로 모든 코드 서명 인증서하드웨어 키 보관이 강제됐다. 그 이전엔 OV는 PFX 파일로 받아 CI 어디든 export 가능했고, GitHub Actions에서 base64로 secret에 박아 완전 자동 서명이 가능했다. 이제는 Azure Key Vault, DigiCert KeyLocker, SSL.com eSigner 같은 클라우드 HSM 서비스를 반드시 끼워야 한다. CI 파이프라인이 전 세계에서 한꺼번에 새로 짜였다.

“Apple Notarization은 macOS Catalina(10.15, 2019)에서 사실상 필수가 됐다”

그 이전엔 Developer ID 서명만 있으면 macOS가 열어줬다. Catalina부터 notarization 없는 새 binary경고 + 우회 강제가 들어왔다. 즉, 서명 ≠ 신뢰가 됐다 — Apple은 서명자가 누구든 Apple이 한 번 더 검토한다. 이게 다음 문서의 주제.

“Sectigo의 EV 인증서 가격 인하 — 2022년”

한때 EV 인증서는 연 $700+ 가 흔했다. Sectigo 등 후발 CA가 연 $250까지 내리며 시장이 흔들렸고, 지금은 연 $300~$400이 일반적. 그러나 DigiCert는 여전히 프리미엄 가격을 유지그 추가 비용은 SLA·고객 지원·CI 통합 도구의 값이라는 입장이다.


요약 + Mermaid

코드 서명은 binary의 출처를 OS에 증명하는 신뢰 사슬이다. Windows는 Authenticode + SmartScreen 평판 (EV가 즉시 평판), macOS는 Developer ID + Apple Developer Program ($99/yr). timestamping--deep 서명 같은 디테일이 5년 뒤 binary가 살아남는지를 결정한다.