이 도움말에서는 앱과 게임에 맞게 Google Play 조작 방지 기능을 맞춤설정하는 방법을 설명합니다. 이 페이지에 설명된 맞춤설정 기능을 사용하려면 Play Console에 조작 방지 기능이 사용 설정된 자동 보호를 사용하고 있어야 합니다.
맞춤설정된 조작 방지 정보
맞춤설정된 조작 방지를 사용하면 앱에서 더 강력한 보안이 필요한 특정 Java 및 Kotlin 메서드를 식별할 수 있습니다. 사용자의 버전이 Google Play에 업로드되면 Google Play는 이러한 메서드를 대상으로 향상된 보호 모드를 우선시합니다.
향상된 보호 모드가 필요한 메서드를 식별하면 앱의 조작 방지 성능을 개선할 수 있습니다. 메서드 보호를 사용하여 바이너리에서 클라이언트 보안 비밀(예: 클라이언트에 포함해야 하는 민감한 키나 URL)이 유출되지 않도록 할 수도 있습니다.
맞춤설정된 조작 방지 설정하기
앱의 코드베이스에 맞춤설정된 조작 방지를 구현하려면 다음 단계를 따르세요.
1단계: 코드베이스에 자동 보호 인터페이스 추가하기
먼저 앱 또는 게임에 보호 인터페이스를 추가합니다.
Kotlin:
package com.google.android.play.protections.annotations/**
* 메서드가 향상된 보호 모드의 후보임을 설명합니다.
*
* <p>이 주석은 Google Play에서 번들을 보호하는 시점에
* 번들의 dex 코드에서 자동으로 삭제됩니다. 메서드 수준
* 주석으로만 사용하세요. 다른 모든 용도(예: 런타임 시
* 리플렉션을 사용하여 클래스에 액세스하기)는 지원되지 않습니다.
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
public annotation class PlayAutomaticIntegrityProtection() {}
Java:
package com.google.android.play.protections.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 메서드가 향상된 보호 모드의 후보임을 설명합니다.
*
* <p>이 주석은 Google Play에서 번들을 보호하는 시점에
* 번들의 dex 코드에서 자동으로 삭제됩니다. 메서드 수준
* 주석으로만 사용하세요. 다른 모든 용도(예: 런타임 시
* 리플렉션을 사용하여 클래스에 액세스하기)는 지원되지 않습니다.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PlayAutomaticIntegrityProtection {}
# 주석 클래스와 그 멤버를 유지합니다.
-keep class com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection* { *; }
# 기본적으로 ProGuard는 주석 속성을 선택사항으로 취급하고
# 난독화 단계에서 삭제합니다. 이 규칙은 주석이 보관되도록 합니다.
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault
# 메서드를 주석과 함께 유지하되, 난독화될 수 있도록 허용합니다.
-keepclassmembers,allowobfuscation class * {
@com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection *;
}
2단계: 맞춤 보호를 위해 메서드에 주석 달기
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun myMethod() {
// 메서드 본문...
}
Java
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public void myMethod() {
// 메서드 본문...
}3단계: (선택사항) 클라이언트 측 보안 비밀 보호하기
맞춤 메서드 보호는 주석이 달린 메서드의 본문 내의 코드를 직접 난독화(숨김 처리)합니다. 이를 사용하여 민감한 API 키를 보호할 수 있습니다.
Kotlin:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public static void callApi() {
api.connect("YOUR_API_KEY");
}
4단계: (선택사항) 보호 성능 오버헤드 관리하기
기본적으로 보호된 메서드를 호출하면 수 밀리초의 오버헤드가 추가됩니다. 따라서 성능에 민감한 시나리오나 기본 스레드에서는 호출하면 안 됩니다.
빠른 실행이 필요한 메서드를 보호해야 하는 경우, 더 가벼운 보호 모드를 사용할 수 있습니다. 주석 속성을 사용하여 더 빠르게 액세스되도록(시작 시 로드) 할 수 있지만, 여기에 해당하는 보호 기능은 그다지 강력하지 않습니다.
Kotlin:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
public static void callApi() {
api.connect("YOUR_API_KEY");
}
이를 사용하려면 1단계의 원본 주석 정의 본문에 인터페이스 속성을 추가합니다.
// Kotlin 주석 정의 업데이트
public annotation class PlayAutomaticIntegrityProtection(
/**
* true인 경우 주석이 달린 메서드가 시작 시 로드됩니다. false인 경우
* 온디맨드 방식으로 로드됩니다.
*
* <p>온디맨드 로드의 경우 메서드를 호출하면 성능
* 페널티가 발생합니다. 시작 시 로드의 경우 메서드가 앱의 수명 주기 동안 메모리에서 난독화
* 해제된 상태로 유지됩니다.
*/
val loadAtStartup: Boolean = false
) {}
5단계: 앱 테스트하기
메서드 선택을 위한 권장사항
메서드를 신중하게 선택하면 전반적인 보호 성능이 강화됩니다. 각 신규 버전이 새롭게 보호된 메서드를 갖는다면 해당 버전의 앱 또는 게임은 공격에 대한 복원력이 더 높아집니다.
앱 성능에 영향을 미치지 않으려면 일반적으로 핫 메서드보다 콜드 메서드를 선택하는 것이 좋습니다. 보호 수준을 극대화하려면 다음과 같은 메서드를 선택하세요.
- 애플리케이션에 중요합니다(삭제하면 앱이 정상적으로 작동하지 않음).
- 기본/UI 스레드에서 실행되지 않습니다.
- 앱의 수명 주기 동안 두 번 이상 실행되지만 핫 루프에서는 실행되지 않습니다.
- 단순하지 않습니다(단순하지 않은 코드 또는 데이터를 포함하는 메서드).
- (가능하다면) 시작 중에 실행되지 않습니다.
- 이 버전에서 새로 도입되었거나 대대적으로 리팩터링되었습니다.
- 추상 메서드, 인터페이스 메서드 또는 생성자가 아닙니다.
- 리플렉션을 사용하지 않고 네이티브 라이브러리를 직접 로드하지 않습니다.
맞춤설정된 보호 삭제하기
특정 메서드를 더 이상 보호하지 않으려면 @PlayAutomaticIntegrityProtection() 주석을 삭제하면 됩니다.