Springboot에서 AppAttest API 사용하기 (3. iOS AppAttest)
Java Kotlin/Spring SpringBoot
2025. 5. 12. 23:23
서론
졸업 프로젝트를 하다 React Native 환경의 클라이언트에서 앱 무결성 검증을 해야 하는 상황이 되었다.
이 기록은 앱 무결성 검증을 하며 헤맨 부분의 기록이다.
본론
iOS AppAttest도 앱의 변조 여부를 파악하는 역할을 한다. 하지만 iOS의 경우 키 복호화 등 절차가 너무 복잡해 라이브러리를 사용하여 문제를 해결하였다.
// implementation("ch.veehait.devicecheck:devicecheck-appattest:0.9.6")
lateinit var attest: AppleAppAttest
init {
attest = AppleAppAttest(
app = App(teamId, packageName),
appleAppAttestEnvironment = AppleAppAttestEnvironment.PRODUCTION
)
}
fun verifyIosAppAttest(
attestation: String,
keyId: String?,
challenge: String
): IntegrityVerificationResponse {
try {
val validator = attest.createAttestationValidator()
val result = validator.validate(
Base64.getDecoder().decode(attestation),
keyId ?: "",
Base64.getDecoder().decode(challenge)
)
// 라이브러리의 validate 메소드는 검증 실패 시 AttestationException을 throw 합니다.
// 여기까지 도달했다는 것은 검증에 성공했다는 의미입니다.
return IntegrityVerificationResponse(
isValid = true,
message = "iOS app attestation verified successfully"
// 필요한 경우 'result' 객체에서 추가 정보를 추출하여 details에 포함
)
} catch (e: AttestationException) { // <-- 라이브러리의 특정 예외를 캐치
// Attestation 검증 자체에서 발생한 오류
logger.error("App attestation validation failed: ${e.message}", e)
return IntegrityVerificationResponse(
isValid = false,
message = "App attestation validation failed: ${e.message}",
details = mapOf("errorType" to e.javaClass.simpleName, "validationError" to (e.message ?: "unknown")) // 예외 메시지 포함
)
} catch (e: Exception) { // 그 외 예상치 못한 다른 오류
logger.error("Unexpected error during iOS app attestation verification", e)
return IntegrityVerificationResponse(
isValid = false,
message = "Unexpected error verifying iOS attestation: ${e.localizedMessage ?: e.message}",
details = mapOf("errorType" to e.javaClass.simpleName)
)
}
}
iOS의 경우도 똑같이 검사 결과를 Decode하는 절차가 필요하다. 하지만 애플의 경우 키 교환 등.... 직접 구현하기엔 너무 많은 보안절차가 필요하다.
그렇다고 전용 엔드포인트를 제공하지도 않는다... 그래서 라이브러리를 사용하는 상황이 되었다;
검증결과, 프론트엔드에서 생성된 KeyId, 그리고 Challenge code(Nonce)를 비교해 검증을 실시한다.
결론
앱의 무결성 검사는 무척 중요한 파트이다. 하지만 국내에서는 잘 다뤄지지 않은 파트로 보인다.
그래서 미래에 똑같은 일을 하게 될 상황을 대비해 기록을 남긴다.
'Java Kotlin > Spring SpringBoot' 카테고리의 다른 글
Springboot에서 Play Integrity API 사용하기 (2. Google 연동) (0) | 2025.05.12 |
---|---|
Springboot에서 Play Integrity API 사용하기 (1. 기본 설정) (0) | 2025.05.12 |