Skip to main content

Code Signing

코드 서명은 애플리케이션이 개발자 본인에 의해 생성되었음을 보증하는 보안 기술이다. 애플리케이션에 서명을 추가하면 운영체제의 보안 경고를 방지할 수 있다.

macOS Sonoma Gatekeeper 경고: 앱이 손상되었습니다

Windows와 macOS 모두 사용자가 서명되지 않은 애플리케이션을 실행하는 것을 차단한다. 코드 서명 없이 애플리케이션을 배포할 수는 있지만, 사용자가 이를 실행하려면 여러 고급 및 수동 단계를 거쳐야 한다.

만약 패키징하고 배포할 Electron 앱을 개발 중이라면, 반드시 코드 서명을 해야 한다. Electron 생태계의 도구를 사용하면 앱에 쉽게 코드 서명을 추가할 수 있다. 이 문서는 Windows와 macOS에서 앱에 서명하는 방법을 설명한다.

macOS 빌드 서명 및 공증

macOS 애플리케이션을 출시하기 위해서는 두 가지 단계를 거쳐야 한다. 먼저, 앱에 코드 서명을 추가해야 한다. 그 다음, 앱을 Apple에 업로드해 공증(notarization) 과정을 거쳐야 한다. 이 과정에서 자동화된 시스템이 앱이 사용자에게 위험을 초래하지 않는지 추가로 검증한다.

이 과정을 시작하기 전에, 앱에 서명하고 공증하기 위한 요구사항을 충족했는지 확인해야 한다:

  1. Apple Developer Program에 가입한다 (연회비 필요)
  2. Xcode를 다운로드하고 설치한다 (macOS가 설치된 컴퓨터 필요)
  3. signing certificates를 생성, 다운로드, 설치한다

Electron 생태계는 설정과 자유를 중시하기 때문에, 애플리케이션에 서명하고 공증하는 방법이 여러 가지 있다.

Electron Forge 사용하기

Electron의 선호하는 빌드 도구를 사용한다면, 애플리케이션에 서명하고 공증을 받기 위해 몇 가지 설정을 추가해야 한다. Forge는 공식 Electron 도구 모음으로, 내부적으로 @electron/packager, @electron/osx-sign, 그리고 @electron/notarize를 사용한다.

애플리케이션 설정 방법에 대한 자세한 지침은 Electron Forge 문서의 macOS 앱 서명 가이드에서 확인할 수 있다.

Electron Packager 사용하기

Forge와 같은 통합 빌드 파이프라인을 사용하지 않는다면, @electron/packager를 사용할 가능성이 높다. 이 패키지는 @electron/osx-sign@electron/notarize를 포함한다.

Packager의 API를 사용한다면, 앱에 서명하고 notarize하는 설정을 전달할 수 있다. 아래 예제가 요구사항을 충족하지 않는다면, @electron/osx-sign@electron/notarize에서 다양한 설정 옵션을 확인할 수 있다.

const packager = require('@electron/packager')

packager({
dir: '/path/to/my/app',
osxSign: {},
osxNotarize: {
appleId: 'felix@felix.fun',
appleIdPassword: 'my-apple-id-password'
}
})

Mac App Store 애플리케이션 서명하기

자세한 내용은 [Mac App Store 가이드][]를 참고한다.

윈도우 빌드에 서명하기

애플리케이션에 코드 서명을 하려면 먼저 코드 서명 인증서를 획득해야 한다. 애플과 달리 마이크로소프트는 개발자들이 공개 시장에서 이러한 인증서를 구매할 수 있도록 허용한다. 일반적으로 HTTPS 인증서를 제공하는 회사들이 코드 서명 인증서도 판매한다. 가격은 다양하므로 여러 업체를 비교해 보는 것이 좋다. 주요 판매처는 다음과 같다:

2023년 6월부터 마이크로소프트는 소프트웨어에 "확장 검증" 인증서(일명 EV 코드 서명 인증서)로 서명할 것을 요구한다. 과거에는 "Authenticode 코드 서명 인증서"나 "소프트웨어 기반 OV 인증서"와 같이 더 간단하고 저렴한 인증서로도 서명이 가능했다. 하지만 이제는 이러한 간단한 인증서를 사용하면 윈도우가 해당 앱을 완전히 서명되지 않은 것으로 간주하고 경고 대화상자를 표시한다.

새로운 EV 인증서는 FIPS 140 Level 2, Common Criteria EAL 4+ 또는 이에 준하는 하드웨어 저장 모듈에 저장해야 한다. 즉, 이 인증서는 단순히 CI 인프라에 다운로드할 수 없다. 실제로 이러한 저장 모듈은 고급 USB 메모리처럼 생겼다.

많은 인증서 제공업체가 이제 "클라우드 기반 서명"을 제공한다. 이 경우 전체 서명 하드웨어가 데이터 센터에 위치하며, 원격으로 코드에 서명할 수 있다. 이 방식은 GitHub Actions, CircleCI 등과 같은 CI 환경에서 애플리케이션에 서명하기가 상대적으로 쉬워 Electron 유지보수자들 사이에서 인기가 있다.

현재 Electron 자체 앱은 DigiCert KeyLocker를 사용하지만, 파일 서명을 위한 커맨드라인 도구를 제공하는 모든 제공업체는 Electron 도구와 호환된다.

Electron 생태계의 모든 도구는 @electron/windows-sign을 사용하며, 일반적으로 windowsSign 속성을 통해 설정 옵션을 제공한다. 이 도구를 사용해 파일에 직접 서명하거나, Electron Forge, @electron/packager, electron-winstaller, electron-wix-msi에서 동일한 windowsSign 설정을 사용할 수 있다.

Electron Forge 사용하기

Electron Forge는 앱과 Squirrel.WindowsWiX MSI 설치 프로그램에 서명하는 데 권장되는 방법이다. 앱을 구성하는 방법에 대한 자세한 설명은 Electron Forge 코드 서명 튜토리얼에서 확인할 수 있다.

Electron Packager 사용하기

Forge와 같은 통합 빌드 파이프라인을 사용하지 않는다면, @electron/packager를 사용할 가능성이 높다. 이 패키지는 @electron/windows-sign도 포함한다.

Packager의 API를 사용한다면, 애플리케이션 서명을 위한 설정을 전달할 수 있다. 아래 예제가 요구사항을 충족하지 못한다면, @electron/windows-sign에서 다양한 설정 옵션을 확인할 수 있다.

const packager = require('@electron/packager')

packager({
dir: '/path/to/my/app',
windowsSign: {
signWithParams: '--my=custom --parameters',
// signtool.exe가 작동하지 않는다면, 커스터마이즈하자!
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})

electron-winstaller 사용하기 (Squirrel.Windows)

electron-winstaller는 Electron 앱을 위한 Squirrel.Windows 설치 프로그램을 생성할 수 있는 패키지다. 이 도구는 Electron Forge의 Squirrel.Windows Maker에서 내부적으로 사용된다. @electron/packager와 마찬가지로, 이 도구도 내부적으로 @electron/windows-sign를 사용하며 동일한 windowsSign 옵션을 지원한다.

const electronInstaller = require('electron-winstaller')
// 참고: Node 12 기준으로 top-level await를 지원하지 않으므로, 이 구문은 async 함수 내에서 사용해야 한다.
try {
await electronInstaller.createWindowsInstaller({
appDirectory: '/tmp/build/my-app-64',
outputDirectory: '/tmp/build/installer64',
authors: 'My App Inc.',
exe: 'myapp.exe',
windowsSign: {
signWithParams: '--my=custom --parameters',
// signtool.exe가 작동하지 않는다면, 직접 설정할 수 있다!
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})
console.log('성공!')
} catch (e) {
console.log(`실패: ${e.message}`)
}

전체 설정 옵션을 확인하려면 electron-winstaller 저장소를 참고하자!

electron-wix-msi (WiX MSI) 사용하기

electron-wix-msi는 Electron 앱을 위한 MSI 설치 프로그램을 생성할 수 있는 패키지다. 이 도구는 Electron Forge의 MSI Maker에서 내부적으로 사용된다. @electron/packager와 마찬가지로, 이 패키지도 내부적으로 @electron/windows-sign을 사용하며 동일한 windowsSign 옵션을 지원한다.

import { MSICreator } from 'electron-wix-msi'

// 1단계: MSICreator 인스턴스 생성
const msiCreator = new MSICreator({
appDirectory: '/path/to/built/app',
description: 'My amazing Kitten simulator',
exe: 'kittens',
name: 'Kittens',
manufacturer: 'Kitten Technologies',
version: '1.1.2',
outputDirectory: '/path/to/output/folder',
windowsSign: {
signWithParams: '--my=custom --parameters',
// signtool.exe가 작동하지 않으면 커스텀 도구 경로 지정
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})

// 2단계: .wxs 템플릿 파일 생성
const supportBinaries = await msiCreator.create()

// 🆕 2a단계: 필요에 따라 지원 바이너리 서명
// 패키징 스크립트에서 바이너리를 서명하는 경우
for (const binary of supportBinaries) {
// 바이너리는 새로운 스텁 실행 파일과 선택적으로
// Squirrel 자동 업데이터다.
await signFile(binary)
}

// 3단계: 템플릿을 .msi 파일로 컴파일
await msiCreator.compile()

전체 설정 옵션을 확인하려면 electron-wix-msi 저장소를 참고한다!

Electron Builder 사용하기

Electron Builder는 애플리케이션 서명을 위한 커스텀 솔루션을 제공한다. 공식 문서에서 더 자세한 정보를 확인할 수 있다.

Windows Store 애플리케이션 서명하기

자세한 내용은 [Windows Store 가이드][]를 참고한다.