Code Signing — 코드 서명이란 무엇이며 어떻게 작동하는가

저자: IT Sectr 게시일: 2026-04-16 읽는 시간: 9 분

Code Signing(코드 서명)은 실행 파일에 디지털 서명하여 개발자의 신원과 애플리케이션 무결성을 보장하는 메커니즘입니다. Android에서는 모든 APK 파일이 기기에 설치되거나 Google Play에 게시되기 전에 인증서로 서명되어야 합니다. Google, 2024에 따르면 Android는 JAR 기반 v1부터 스트리밍 설치용 v4까지 4세대 서명 체계를 지원합니다.

핵심 요점

  • Code Signing — 코드의 디지털 서명으로, 저작자와 애플리케이션 무결성을 확인합니다.
  • Android에서 서명은 keystore — 키와 인증서 저장소를 통해 수행됩니다.
  • v2(APK Signature Scheme)는 Android 7.0부터 주요 표준이며, APK의 모든 바이트를 보호합니다.
  • 키 로테이션(v3, Android 9.0+)을 통해 애플리케이션을 삭제하지 않고 서명 키를 변경할 수 있습니다.
  • Google Play는 중앙 키 관리를 위해 Play App Signing을 사용합니다.

Code Signing이란?

Code Signing은 개발자가 실행 코드에 디지털 인증서로 서명하는 암호화 프로세스입니다. 서명은 비대칭 암호화를 사용하여 생성됩니다. 개발자의 개인 키가 디지털 서명을 생성하고 공개 키가 인증서에 포함됩니다. 누구나 공개 키를 사용하여 서명을 확인할 수 있지만, 서명을 깨뜨리지 않고 코드를 수정하는 것은 불가능합니다.

모바일 개발에서 코드 서명은 세 가지 기능을 수행합니다. 첫째 — 인증: 사용자와 플랫폼이 애플리케이션 개발자를 식별할 수 있습니다. 둘째 — 무결성: 서명 후 APK의 변경은 서명을 무효화합니다. 셋째 — 신뢰할 수 있는 업데이트: 플랫폼은 설치된 버전과 동일한 인증서로 서명된 APK로만 애플리케이션 업데이트를 허용합니다.

법적 지위

Android 애플리케이션의 디지털 서명은 법적 중요성을 가집니다. 러시아 법률(63-FZ) 및 유럽 eIDAS에 따르면, 적격 전자 서명은 자필 서명과 동등합니다. 그러나 자체 서명된 인증서(Android에서 일반적인 관행)로 APK에 서명하는 것은 적격하지 않습니다. 이는 무결성을 확인하지만 법적 관점에서 개발자의 신원을 확인하지는 않습니다.

Android 서명 체계: v1, v2, v3, v4

Android는 4가지 APK 서명 체계를 지원하며, 각 체계는 이전 버전의 문제를 해결하고 새로운 기능을 추가합니다. 모든 체계는 단일 APK에 공존할 수 있습니다. 이는 이전 Android 버전과의 역호환성을 위해 필요합니다.

v1(JAR 서명) 체계는 Android 1.0에서 등장했습니다. META-INF/MANIFEST.MF의 항목을 사용하여 APK 아카이브 내의 개별 파일에 서명합니다. 단점: 공격자는 APK를 수정(파일 추가 또는 제거)하고 나머지는 건드리지 않고 수정된 파일에만 다시 서명할 수 있습니다. 이로 인해 v1은 특정 공격에 취약합니다. Android 7.0에서 도입된 v2(APK Signature Scheme)는 서명 자체를 제외한 모든 바이트를 포함하여 전체 APK 파일을 하나로 서명하여 선택적 수정 가능성을 제거합니다.

체계Android특징키 로테이션
v1(JAR)1.0+파일별 서명아니요
v27.0+전체 APK 서명아니요
v39.0+서명 + 로테이션
v411.0+스트리밍 + ADB

v3: 서명 키 로테이션

Android 9.0에서 도입된 체계 v3는 오랜 문제를 해결합니다. 서명 키가 손상되거나 만료되면 어떻게 해야 할까요? 이전에는 서명 키를 변경하면 애플리케이션이 새 것으로 처리되어 기존 애플리케이션 위에 설치할 수 없었습니다. v3는 로테이션 메커니즘을 추가합니다. APK에는 이전 키로 서명된 로테이션 증명(proof-of-rotation)이 포함될 수 있습니다. 시스템은 체인을 확인하고 새 키로 서명된 애플리케이션의 업데이트를 허용합니다.

Keystore 및 인증서

Keystore는 애플리케이션 서명을 위한 개인 키와 인증서를 포함하는 보안 컨테이너입니다. Android 개발에서는 JKS(Java KeyStore) 또는 PKCS12 형식이 사용됩니다. Keystore는 JDK의 일부인 keytool 유틸리티로 생성됩니다. 저장소의 각 키는 별칭(alias)으로 식별되고 암호로 보호됩니다.

Keystore의 인증서에는 공개 키와 소유자 정보(조직 이름, 국가, 유효 기간)가 포함됩니다. Android 애플리케이션의 경우 인증서는 자체 서명될 수 있습니다. Google은 인증 기관(CA)을 요구하지 않으며, 이는 Android를 iOS와 구별합니다. 그러나 인증서 유효 기간은 최소 25년이어야 합니다. 애플리케이션이 동일한 키로 업데이트되기 때문입니다.

bash
# 서명을 위한 새 keystore 생성
keytool -genkey -v -keystore my-release.keystore \
        -alias my-app-alias \
        -keyalg RSA \
        -keysize 2048 \
        -validity 10000

# keystore 내용 보기
keytool -list -v -keystore my-release.keystore

키 형식

Android는 서명 키에 두 가지 알고리즘을 지원합니다: RSAECDSA. 2048비트 키 크기의 RSA는 사실상의 표준이며 모든 Android 버전에서 지원됩니다. 곡선 P-256을 사용하는 ECDSA(타원 곡선 디지털 서명 알고리즘)는 더 작은 키 크기로 동일한 암호화 강도를 제공합니다. Android 9.0부터 모바일 기기에서 확인 속도가 더 빠른 ECDSA가 권장됩니다.

빌드에서 서명 구성

Android Gradle Plugin에서 서명은 모듈 수준 build.gradle의 signingConfigs 블록을 통해 구성됩니다. 디버그 빌드의 경우 Android Studio가 알려진 암호로 디버그 keystore를 자동으로 생성합니다. 릴리스 빌드의 경우 개발자가 자신의 keystore 경로, 키 별칭 및 암호를 지정합니다. 암호는 버전 관리에서 제외된 별도 구성 파일에 저장하는 것이 좋습니다.

현대적인 방법은 CI/CD를 통한 중앙 서명 관리입니다. Jenkins, GitLab CI 또는 GitHub Actions는 keystore를 보호된 아티팩트로, 암호를 환경 시크릿으로 저장할 수 있습니다. 이는 리포지토리를 통한 키 유출을 방지하고 필요시 키 로테이션을 단순화합니다.

groovy
// build.gradle(앱 수준) — 서명 구성
android {
    signingConfigs {
        release {
            storeFile file("my-release.keystore")
            storePassword System.getenv("KEYSTORE_PASSWORD")
            keyAlias System.getenv("KEY_ALIAS")
            keyPassword System.getenv("KEY_PASSWORD")
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

다중 체계 서명

최대 호환성을 위해 APK는 세 가지 체계 모두(v1 + v2 + v3)로 서명되어야 합니다. Android Gradle Plugin은 기본적으로 모든 체계를 포함합니다. v2로만 서명된 APK는 Android 6.0 이하에서 설치되지 않습니다. v1만 있는 APK는 Android 7.0+에서 v2의 무결성 이점을 얻지 못합니다. 모든 체계를 포함해도 APK 크기가 1~2% 이상 증가하지 않으며 모든 기기와의 호환성을 보장합니다.

Play App Signing 및 키 관리

Play App Signing은 애플리케이션 서명 키를 중앙에서 관리하는 Google Play 서비스입니다. 개발자는 업로드 키(upload key)로 서명된 APK를 Google Play Console에 업로드하고, Google Play는 사용자에게 전달하기 전에 배포 키(distribution key)로 다시 서명합니다. 이는 배포 키를 분실이나 손상으로부터 보호합니다.

Play App Signing의 이점: 보안 — 배포 키는 Google의 보호된 저장소에 보관됩니다; 로테이션 — 콘솔을 통해 키 변경을 요청할 수 있습니다; 복구 — 업로드 키를 분실한 경우 새 키를 생성할 수 있습니다. 단점: Play App Signing 도입 전에 존재했던 애플리케이션의 경우, 이전 배포 키가 이미 사용 중이므로 새 애플리케이션을 생성해야 합니다.

bash
# 인증서 지문 가져오기(SHA-256)
keytool -list -v -keystore my-release.keystore \
        -alias my-app-alias | grep "SHA256"

# apksigner로 APK 서명 확인
apksigner verify --verbose app-release.apk

키 복구

서명 키를 분실하고 Play App Signing을 사용하지 않는 경우, 애플리케이션 업데이트 기능을 복원하는 것은 불가능합니다. 새 패키지 이름으로 새 애플리케이션을 생성해야 합니다. 이것이 Play App Signing을 사용해야 하는 주요 이유 중 하나입니다. Google은 keystore의 백업 복사본을 안전한 오프라인 저장소(암호화된 USB 드라이브, 은행 금고)에 보관할 것을 권장합니다.

기기에서 서명 확인

APK를 설치할 때 Android는 여러 단계로 서명 확인을 수행합니다. 첫째 — 인증서 확인: 유효 기간이 만료되었는지, 형식이 올바른지. 둘째 — 서명 확인: 암호화 서명이 APK 내용과 일치하는지. 셋째 — 설치된 버전과 인증서 비교: 애플리케이션이 이미 기기에 있는 경우 인증서가 일치해야 하며, 그렇지 않으면 설치가 차단됩니다.

확인 시스템은 PackageManagerService에 내장되어 있습니다. 설치 요청을 처리할 때 PMS는 APK에서 서명을 추출하고 android.util.PackageParser 클래스를 사용하여 확인한 후 설치된 애플리케이션(있는 경우)의 저장된 서명과 비교합니다. 일치하지 않으면 사용자는 “INSTALL_FAILED_UPDATE_INCOMPATIBLE” 오류를 받습니다. 이 메커니즘은 대체 공격을 방지합니다(악성 코드가 합법적인 애플리케이션을 자체 버전으로 대체할 수 없음).

개발자 확인

개발자는 Android SDK Build Tools의 apksigner 유틸리티를 사용하여 독립적으로 APK 서명을 확인할 수 있습니다. 명령어 apksigner verify --verbose app.apk는 APK가 어떤 체계로 서명되었는지, 인증서가 유효한지, 서명이 내용과 일치하는지 표시합니다. 설치된 애플리케이션의 서명을 프로그래밍 방식으로 확인하려면 GET_SIGNATURES 플래그와 함께 PackageManager.getPackageInfo()를 사용합니다.

kotlin
// 설치된 애플리케이션 서명의 프로그래밍 방식 확인
fun getAppSignature(context: Context, packageName: String): String? {
    val pm = context.packageManager
    val info = pm.getPackageInfo(
        packageName,
        PackageManager.GET_SIGNATURES
    )
    return info.signatures?.firstOrNull()?.toCharsString()
}

서명 보안 모범 사례

서명 키 보안은 Android 개발의 중요한 측면입니다. 키가 손상되면 공격자가 자체 코드로 애플리케이션 업데이트에 서명할 수 있습니다. 주요 규칙: 리포지토리에 키를 절대 저장하지 말고, 다른 애플리케이션에 동일한 키를 사용하지 말며, 안전하지 않은 채널(이메일, 메신저)을 통해 키를 전송하지 마십시오.

권장 방법은 키 분리입니다. 각 애플리케이션에 대해 별도의 키와 Google Play에 업로드하기 위한 별도의 키(업로드 키)를 사용하십시오. 디버그 빌드의 경우 Android Studio가 공유 debug.keystore를 생성합니다. 이는 릴리스 빌드에 사용할 수 없습니다. 인증서 유효 기간은 25~30년이어야 합니다(현재 표준, Google 확인).

방법권장사항
키 저장암호화 미디어, CI/CD 시크릿
인증서 유효 기간최소 25년
알고리즘RSA 2048+ 또는 ECDSA P-256
분리애플리케이션별 별도 키
백업keystore 오프라인 복사본

서명 감사

정기적으로 서명 체인 무결성을 확인하십시오. 키에 접근할 수 있는 직원이 퇴사할 경우 Google Play Console을 통해 업로드 키를 업데이트하십시오. Google Play Integrity API와 같은 도구를 사용하여 사용자 기기에서 애플리케이션이 변조되지 않았는지 확인하십시오. API는 서명 및 무결성에 대한 데이터를 반환하여 확인을 위해 서버로 전송합니다.

자주 묻는 질문

Android에서 Code Signing이란?

Code Signing은 애플리케이션이 특정 개발자에 의해 생성되었고 서명 후 수정되지 않았음을 확인하는 APK 파일의 디지털 서명입니다. 서명이 없으면 APK가 기기에 설치되지 않습니다.

Android 애플리케이션 서명 키를 어떻게 생성하나요?

JDK의 keytool 유틸리티를 사용하세요: keytool -genkey -v -keystore my-release.keystore -alias my-alias -keyalg RSA -keysize 2048 -validity 10000. 결과 keystore를 build.gradle의 signingConfigs 블록에 지정하세요.

서명 키를 분실하면 어떻게 되나요?

키를 분실하고 Play App Signing을 사용하지 않는 경우 애플리케이션 업데이트가 불가능해집니다. 새 패키지 이름으로 Google Play에 새 애플리케이션을 생성해야 합니다. 키 분실을 방지하려면 Play App Signing을 사용하십시오.

v1과 v2 서명 체계의 차이점은 무엇인가요?

v1은 APK 내의 각 파일을 개별적으로 서명합니다. 공격자는 하나의 파일을 수정하고 해당 파일에만 다시 서명할 수 있습니다. v2는 전체 APK를 하나로 서명합니다. 변경 사항이 있으면 서명이 무효화되어 더 높은 수준의 보안을 제공합니다.

Play App Signing이란?

Play App Signing은 애플리케이션 배포 키를 중앙에 저장하는 Google Play 서비스입니다. 개발자가 업로드 키로 서명된 APK를 업로드하면 Google이 사용자에게 전달하기 전에 다시 서명하여 키를 분실이나 도난으로부터 보호합니다.

요약

  • Code Signing은 APK의 필수 디지털 서명으로, 애플리케이션의 신뢰성과 무결성을 보장합니다.
  • Android는 4가지 서명 체계를 지원합니다: v1(JAR), v2(APK Signature), v3(키 로테이션), v4(스트리밍).
  • Keystore는 RSA 2048+ 알고리즘으로 keytool을 통해 생성되는 보안 키 컨테이너입니다.
  • 키 로테이션(v3, Android 9.0+)을 통해 애플리케이션을 삭제하지 않고 서명 키를 변경할 수 있습니다.
  • Play App Signing은 Google Play Console을 통해 배포 키를 중앙에서 관리합니다.
  • 설치 중 서명 확인은 대체 공격을 차단합니다: 인증서 불일치 = INSTALL_FAILED 오류.
  • 키 보안: 애플리케이션별 별도 키, 25년 이상 유효 기간, 오프라인 복사본, 리포지토리에 키 없음.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기