사용자가 Google Play 스토어에서 합법적인 앱 버전을 구매 또는 다운로드했는지 확인하려면 개발자가 제어하는 서버에서 라이선스 확인을 실행하는 것이 가장 좋습니다.
이 가이드에서는 서버 측 라이선스 확인을 완료하는 단계별 프로세스와 확인 실행 시의 권장사항을 제공합니다.
프로세스 개요
그림 1은 앱, Google Play, 비공개 서버간에 정보가 전송되는 방식을 보여줍니다.
그림 1. 앱과 Google Play 간, 앱과 비공개 서버 간 데이터 흐름
앱이 Google Play에 요청하여 특정 사용자가 합법적인 앱 버전을 구매 또는 다운로드했는지 문의합니다.
Google Play는 응답 데이터 객체인 ResponseData 유형 객체를 앱에 전송하여 응답합니다. 이 객체는 사용자가 합법적인 앱 버전을 구매 또는 다운로드했는지를 나타내는 서명된 정보입니다.
앱은 개발자가 제어하는 비공개 서버에 요청하여 응답 데이터의 콘텐츠를 확인합니다.
서버는 사용자가 실제로 합법적인 앱 버전을 구매 또는 다운로드했는지를 표시하는 상태를 앱에 전송하여 응답합니다. 서버가 'success' 메시지를 제공하면 응답을 확인하고 사용자에게 라이선스가 필요한 리소스의 액세스 권한을 부여합니다.
응답 데이터는 Google Play에서 서명하고 서버에서 확인하므로 앱을 실행하는 기기에서는 객체를 수정할 수 없습니다. 앱이 서버에 의존하고 합법적인 사용자에게만 리소스를 제공하는 경우 앱은 승인되지 않은 사용자로부터 훨씬 더 안전하게 보호됩니다.
다음 섹션에서는 서버 측 라이선스 확인을 실행할 때 유의해야 할 추가 고려사항을 제공합니다.
재전송 공격으로부터 보호
사용자의 라이선스 상태에 관한 Google Play의 응답을 수신한 후 사용자는 응답 데이터를 복사하여 여러 번 사용하거나 다른 사용자에게 제공할 수 있고, 이러한 사용자들이 앱의 비공개 서버에 자체 요청을 위조할 수 있습니다. 이러한 종류의 작업을 재전송 공격이라고 합니다.
사용자가 재전송 공격을 성공적으로 실행할 가능성을 줄이려면 앱 서버에 요청을 전송하기 전에 다음 조치를 취하세요.
응답 데이터에 포함된 타임스탬프를 확인하여 Google Play에서 최근에 응답을 생성했는지 확인합니다.
지수 백오프와 같은 서버 요청의 비율 제한을 실행하여 앱이 동일한 응답 데이터를 앱 서버로 전송하려는 횟수를 줄입니다.
비공개 서버에서 Google Play 응답 데이터의 콘텐츠를 확인하기 전에 비공개 서버에 초기 인증 기반 요청을 합니다. 이 첫 번째 요청에서 사용자 인증 정보를 서버에 전송하면 서버는 nonce 또는 한 번만 사용되는 숫자로 응답합니다. 그런 다음 이 nonce를 비공개 서버에 하는 다음 요청에 포함하여 라이선스 확인 데이터를 요청할 수 있습니다. nonce에 적합한 값을 선택하는 방법에 관한 자세한 내용은 적합한 nonce 값 생성 섹션을 참조하세요.
적합한 nonce 값 생성
다음 기법 중 하나를 사용하여 추측하기 어려운 nonce 값을 만듭니다.
사용자 ID에 기반하여 해시 값 생성
사용자별로 임의의 값 생성. 이 임의의 값을 지정된 사용자 속성의 일부로 앱 서버에 저장합니다.
서버의 응답 데이터 확인
앱 서버가 앱으로 전송하는 응답 데이터를 검토할 때 라이선스 확인 라이브러리 응답이 위조되지 않았는지 확인하세요. 앱 서버의 응답 데이터에 포함된 서명을 이전 단계의 Google Play에서 앱이 수신한 키와 비교하여 확인합니다.
라이선스 확인 라이브러리(LVL) 관련 블록이 서명된 유일한 부분이라는 것을 기억해야 합니다. 따라서 앱이 신뢰해야 하는 앱 서버 응답 데이터의 유일한 부분이 바로 이 부분입니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[null,null,["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Adding Server-Side License Verification to Your App\n\nWhen verifying that the user has purchased or downloaded a legitimate copy of\nyour app from the Google Play Store, it's best to perform the license\nverification check on a server that you control.\n\nThis guide presents a step-by-step process for completing server-side license\nverification and presents some best practices related to performing this check.\n\nProcess overview\n----------------\n\nFigure 1 shows how information is transferred between your app, Google Play, and\nyour private server: \n**Figure 1.** Flow of data between your app and Google Play, then between your app and your private server\n\n1. Your app makes a request to Google Play, inquiring about whether a particular user has purchased or downloaded a legitimate copy of your app.\n2. Google Play responds by sending a *response data object* , an object of type [`ResponseData`](/google/play/licensing/licensing-reference#lvl-summary), to your app. This object is a signed piece of information that states whether the user has purchased or downloaded a legitimate copy of your app.\n3. Your app makes a request to a private server that you control, verifying the contents of the response data.\n4. The server responds by sending a status to your app, indicating whether the user has indeed purchased or downloaded a legitimate copy of your app. If the server provides a \"success\" message, [verify the\n response](#verify-app-server-response) and then grant the user access to the resources that require a license.\n\nBecause the response data is signed by Google Play, then checked on your\nserver, there's no way to modify the object on the device running your app. If\nyour app relies on the server and makes resources available only to legitimate\nusers, your app is substantially more protected against unauthorized users.\n\nThe following sections provide additional considerations to keep in mind when\nperforming server-side license verification.\n\nSafeguard against replay attacks\n--------------------------------\n\nAfter receiving a response from Google Play regarding the user's license status,\nit's possible for the user to copy the response data and use it multiple times,\nor give it to other users who could then forge their own requests to your app's\nprivate server. This sort of action is known as a *replay attack*.\n\nTo reduce the likelihood of users performing replay attacks successfully, take\nthe following measures before sending a request to your app's server:\n\n- Check the timestamp that's included in the response data, making sure that\n Google Play generated the response recently.\n\n | **Note:** You can increase the allowed difference between the response data's timestamp and the current time based on how long users should be able to interact with license-bound resources after they deactivate their license.\n- Perform rate-limiting on your server request, such as exponential backoff, to\n reduce the number of times that your app attempts to send the same response data\n to your app's server.\n\n | **Caution:** To preserve a good user experience in cases where a user interacts with your app on a variety of devices, be careful if you add rate-limiting based on number of devices.\n- Before verifying the contents of Google Play's response data on your private\n server, make an initial, authentication-based request to your private server. In\n this first request, send user credentials to your server, and have your server\n then respond with a *nonce* , or a number that is used only once. You can then\n include this nonce in your next request to your private server, asking for\n license verification data. For details on how to choose a good value for the\n nonce, see the [generate a suitable nonce value](#generate-nonce) section.\n\n | **Note:** Include a user ID field in both the nonce request and the license verification request. Your app's server can then compare the fields' values from the two requests and make sure they match.\n\n### Generate a suitable nonce value\n\nUse one of the following techniques to create a nonce value that's difficult to\nguess:\n\n- Generate a hash value based on the user's ID.\n- Generate a random value on a per-user basis. Store this random value on your app's server as part of a given user's attributes.\n\nVerify response data from your server\n-------------------------------------\n\nWhen reviewing response data that your app's server sends to your app, make sure\nthat the License Verification Library response isn't forged. Verify the\nsignature that's included in the app server's response data by comparing it\nwith the key that your app received from Google Play in a previous step.\n\nIt's also worth remembering that the block specific to the License Verification\nLibrary (LVL) is the only part that's signed. Therefore, it's the only part of\nyour app server's response data that your app should trust."]]