PC용 Play Integrity를 사용하면 게임 이벤트와 서버 요청이 정품 PC 기기의 정품 PC용 Google Play 게임즈 인스턴스에서 비롯되는지 확인할 수 있습니다. 잠재적으로 위험한 기기와 알 수 없는 에뮬레이터를 감지함으로써 게임의 백엔드 서버는 속임수, 무단 액세스, 허위 트래픽, 악용을 방지하기 위한 적절한 조치를 취할 수 있습니다.
사전 준비 사항
- SDK 설정을 완료합니다.
- Integrity API 보안 고려사항을 검토합니다.
- Integrity API 서비스 약관 및 데이터 처리 정보를 읽고 이해합니다.
- Google Cloud 콘솔에서 Cloud 프로젝트를 만들거나 PC용 Play Integrity와 함께 사용할 기존 Cloud 프로젝트를 선택합니다. API 및 서비스로 이동하여 Google Play Integrity API를 사용 설정합니다.
- 일일 Play Integrity for PC 요청 수가 10, 000개를 초과할 것으로 예상되는 경우 일일 최대 요청 수를 늘려야 합니다.
1단계: 게임에서 PC용 Play Integrity를 사용하는 방법 결정하기
PC용 Play Integrity를 호출하여 환경에 관한 무결성 확인 결과를 가져올 시기를 결정합니다. 예를 들어 게임이 열리거나, 플레이어가 로그인하거나, 플레이어가 멀티플레이어 게임에 참여할 때 확인 결과를 요청할 수 있습니다. 그런 다음 다양한 무결성 응답을 처리하는 방법을 결정합니다. 예를 들면 다음과 같은 작업을 할 수 있습니다.
- 강제 조치 없이 응답을 수집하고 내부적으로 데이터를 분석하여 악용의 유용한 신호인지 파악합니다.
- 응답을 수집하고 백엔드 서버에 로직을 구현하여 무결성 결과를 통과한 기기는 게임을 정상적으로 플레이할 수 있도록 허용하고, 의심스러운 환경에서 유입되는 트래픽은 차단하거나 액세스를 거부합니다.
- 응답을 수집하고 백엔드에서 로직을 구현하여 무결성 검사를 통과한 기기의 플레이어를 함께 매칭하는 동시에 의심스러운 환경에서 발생하는 트래픽을 함께 매칭합니다.
2단계: 게임에서 무결성 토큰 요청
PC용 Play Integrity 워밍업
PC용 Play Integrity를 준비합니다. 이렇게 하면 무결성 확인 결과 요청을 할 때 중요한 경로의 지연 시간을 줄이기 위해 Google Play에서 기기의 부분 증명 정보를 스마트하게 캐시할 수 있습니다. 게임이 열리자마자 비동기적으로 이 작업을 실행하여 필요할 때 주문형 무결성 요청을 할 수 있습니다.
void PrepareIntegrityToken( const PrepareIntegrityTokenParams & params, PrepareIntegrityTokenContinuation continuation )
성공하면 무결성 토큰을 요청하는 데 사용해야 하는 RequestTokenData가 포함된 PrepareIntegrityTokenResultValue로 연속이 호출됩니다. 이 데이터는 메모리에 캐시되어야 하며 RequestIntegrityToken 호출을 위해 애플리케이션 세션 기간 동안 재사용되어야 합니다.
애플리케이션에서 무결성 확인 결과를 완전히 재평가해야 한다고 판단하는 경우에만 PrepareIntegrityToken을 호출해야 합니다.
세부정보 | |
---|---|
매개변수 | params : Google Cloud 프로젝트 번호가 포함된 매개변수입니다. continuation : 무결성 토큰 제공자를 반환하는 비동기 콜백입니다. |
PrepareIntegrityToken 작업을 호출하는 방법을 보여주는 코드 스니펫은 다음과 같습니다.
google::play::integrity::IntegrityClient client_;
google::play::integrity::PrepareIntegrityTokenResult
IntegrityInterface::PrepareIntegrityToken(int64_t cloud_project_number) {
google::play::integrity::PrepareIntegrityTokenParams params;
params.cloud_project_number = cloud_project_number;
auto promise = std::make_shared<
std::promise<google::play::integrity::PrepareIntegrityTokenResult>>();
client_.PrepareIntegrityToken(
params,
[promise](
google::play::integrity::PrepareIntegrityTokenResult result) {
promise->set_value(std::move(result));
});
return promise->get_future().get();
}
무결성 토큰 요청
무결성 토큰은 게임이 기기가 무단 변경되지 않았음을 확인할 수 있는 메커니즘입니다. 게임에서 진짜인지 확인하려는 서버 요청을 실행할 때마다 무결성 토큰을 요청하고 복호화 및 확인을 위해 게임의 백엔드 서버로 전송할 수 있습니다.
PC용 Play Integrity API로 앱에서 사용자 작업을 확인할 때 RequestIntegrityTokenParams::request_hash 필드를 사용하여 조작 공격을 완화할 수 있습니다. 예를 들어 플레이어의 점수를 게임의 백엔드 서버에 보고하려고 할 때 서버는 프록시 서버에서 이 점수가 조작되지 않았는지 확인하려고 합니다. PC용 Play Integrity는 서명된 무결성 응답 내에서 이 필드에 설정된 값을 반환할 수 있습니다. requestHash가 없으면 무결성 토큰은 기기에만 바인딩되고 특정 요청에는 바인딩되지 않으므로 공격이 발생할 수 있습니다.
void RequestIntegrityToken( const RequestIntegrityTokenParams & params, RequestIntegrityTokenContinuation continuation )
공격 가능성을 완화하려면 무결성 확인 결과를 요청할 때 다음을 충족해야 합니다.
- 발생하는 사용자 작업 또는 서버 요청에서 모든 관련 요청 매개변수(예: 안정적인 요청 직렬화의 SHA256)의 다이제스트를 계산합니다.
- RequestIntegrityTokenParams::request_hash 필드를 다이제스트로 설정합니다.
세부정보 | |
---|---|
매개변수 | params : 준비된 RequestTokenData 및 무결성 확인 요청 해시가 포함된 매개변수입니다. continuation : 데이터를 반환하는 비동기 콜백입니다. |
RequestIntegrityToken 작업을 호출하는 방법을 보여주는 코드 스니펫은 다음과 같습니다.
absl::StatusOr<google::play::integrity::RequestIntegrityTokenResult>
IntegrityInterface::RequestIntegrityToken(
const google::play::integrity::PrepareIntegrityTokenResult&
prepare_integrity_token_result,
const std::string& request_hash) {
// Check if the prepare_integrity_token_result is OK
if (!prepare_integrity_token_result.ok()) {
return absl::FailedPreconditionError(
absl::StrCat("PrepareIntegrityTokenResult is not OK. Error code: ",
prepare_integrity_token_result.error_code));
}
google::play::integrity::RequestIntegrityTokenParams params{
.request_token_data =
prepare_integrity_token_result.request_token_data,
.request_hash = request_hash};
auto promise = std::make_shared<std::promise<
google::play::integrity::RequestIntegrityTokenResult>>();
client_.RequestIntegrityToken(
params,
[promise](google::play::integrity::RequestIntegrityTokenResult result) {
promise->set_value(std::move(result));
});
return promise->get_future().get();
}
3단계: 게임의 백엔드 서버에서 무결성 토큰 복호화 및 확인
무결성 토큰 복호화
무결성 확인 결과를 요청하면 Play Integrity API가 암호화된 응답 토큰을 제공합니다. 기기 무결성 확인 결과를 가져오려면 Google 서버에서 무결성 토큰을 복호화해야 합니다.
- 앱에 연결된 Google Cloud 프로젝트 내에서 서비스 계정을 만듭니다.
앱 서버에서 playintegrity 범위를 사용하여 서비스 계정 사용자 인증 정보로부터 액세스 토큰을 가져오고 다음과 같이 요청합니다.
playintegrity.googleapis.com/v1/<var>PACKAGE_NAME</var>:decodePcIntegrityToken -d \ '{ "integrity_token": "<var>INTEGRITY_TOKEN</var>" }'
JSON 응답을 읽습니다.
결과 페이로드는 무결성 확인 결과와 세부정보가 개발자 제공 정보와 함께 포함된 일반 텍스트 토큰입니다. 복호화된 무결성 토큰은 다음과 같습니다.
{
"requestDetails": {
"requestPackageName": "com.your.package.name",
"requestTime": "2025-08-29T13:10:37.285Z",
"requestHash": "your_request_hash_string"
},
"deviceIntegrity": {
"deviceRecognitionVerdict": [
"MEETS_PC_INTEGRITY"
]
},
}
무결성 토큰 확인
디코딩된 무결성 토큰의 requestDetails
필드에는 요청에 관한 정보가 포함됩니다. 여기에는 requestHash
에 개발자가 제공한 정보가 포함됩니다.
requestHash
및 packageName
필드는 원래 요청의 필드와 일치해야 합니다. 따라서 requestPackageName
과 requestHash
가 다음 코드 스니펫과 같이 원래 요청에서 전송된 것과 일치하는지 확인하여 JSON 페이로드의 requestDetails
부분을 확인합니다.
const auto& request_details = json_payload["requestDetails"];
if (request_details.value("requestPackageName", "") != <YOUR_PACKAGE_NAME>) {
// Don't trust the verdicts.
}
// Check for the existence of the request_hash.
// If you set a request hash in the request and it's not present, you shouldn't
// trust the verdicts.
if (!request_details.contains("requestHash")) {
// Don't trust the verdicts.
}
// The requestHash from request_details needs to match the request hash your
// app provided.
if (request_details.value("requestHash", "") != <PROVIDED_REQUEST_HASH>) {
// Don't trust the verdicts.
}
// You can read the rest of payload's fields.
4단계: 무결성 확인 결과에 따라 취할 조치 결정
deviceIntegrity
필드에는 단일 값 deviceRecognitionVerdict
가 포함될 수 있습니다. 이 값을 사용하여 게임이 Play 무결성 검사를 통과하는 PC에서 실행되고 있는지 확인할 수 있습니다 (MEETS_PC_INTEGRITY
응답). 게임의 백엔드 서버는 이 정보를 수집하고 이를 사용하여 게임에서 취해야 하는 조치(예: 게임 이벤트 진행 허용 또는 위험한 트래픽에 대한 액세스 거부)를 결정할 수 있습니다.
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_PC_INTEGRITY"]
}
deviceRecognitionVerdict
가 보유할 수 있는 값은 다음과 같습니다.
MEETS_PC_INTEGRITY
- 게임이 정품 PC 환경에서 실행되고 있으며 기기 내 조작이 감지되지 않았습니다.
- 비어 있음(빈 값)
- 게임이 공격(예: API 후킹)이나 시스템 손상(예: 조작된 Google 데스크톱 서비스 버전을 실행하는 기기) 징후가 있는 기기에서 실행되거나, 앱이 Google Play 무결성 검사를 통과하지 못한 에뮬레이터와 같은 실제 기기에서 실행되지 않습니다.
5단계: 오류 코드 처리
게임에서 PC용 Play Integrity 요청을 하고 호출이 실패하면 게임에 오류 코드가 수신됩니다. 이러한 오류는 네트워크 연결 불량과 같은 환경 문제, API 통합 문제, 악의적인 활동 및 활성 공격 등 다양한 이유로 발생할 수 있습니다.
재시도 가능한 오류 코드
이러한 오류의 원인은 일시적인 조건으로 인해 발생할 수 있으므로 지수 백오프 전략을 사용하여 호출을 다시 시도해야 합니다.
IntegrityError | 오류 설명 | 오류 코드 |
---|---|---|
kNetworkError |
기기의 네트워크 연결 문제 | 5 |
kTooManyRequests |
기기에서 요청한 횟수가 너무 많습니다. | 6 |
kClientTransientError |
클라이언트의 일시적인 문제입니다. | 7 |
재시도 전략에 대한 자세한 권장사항은 여기를 참고하세요.
재시도할 수 없는 오류 코드
이 경우에는 자동 재시도가 도움이 되지 않습니다. 단, 사용자가 문제의 원인이 된 조건을 해결한다면 수동 재시도가 도움이 될 수 있습니다.
IntegrityError | 오류 설명 | 오류 코드 | 권장 작업 |
---|---|---|---|
kError |
SDK 작업 중 치명적인 오류가 발생했습니다. | 1 | 다시 시도하기 전에 API 구현을 확인하세요. |
kCloudProjectNumberIsInvalid |
클라우드 프로젝트 번호가 잘못되었습니다. | 2 | Google Cloud 콘솔에서 클라우드 프로젝트 번호가 올바르게 구성되어 있고 요청이 올바른 클라우드 프로젝트 번호로 이루어지는지 확인합니다. |
kRequestHashTooLong |
요청 해시가 너무 깁니다. | 3 | 생성된 요청 해시가 너무 깁니다. 500자(영문 기준) 미만이어야 합니다. |
kNoValidPreparedTokenFound |
토큰 요청을 하기 전에 준비된 토큰이 없습니다. | 4 | [RequestIntegrityToken][request-integrity-token] 호출을 하기 전에 [PrepareIntegrityToken][prepare-token] 작업을 호출합니다. |
kSdkRuntimeUpdateRequired |
Play for Native SDK를 업데이트해야 합니다. | 8 | 기기의 Google Play 서비스 클라이언트가 최신 상태이고 최신 버전의 Play for Native PC SDK를 사용하고 있는지 확인합니다. |