포스트

유니티 앱에 Google의 Play Integrity API를 추가하는 과정2 (Firebase서버검증 또는 로컬 검증)

https://firebase.google.com/docs/app-check/unity/default-providers?hl=ko

Unity 앱에서 앱 체크 사용 시작하기  |  Firebase 문서 Unity 앱에서 앱 체크 사용 시작하기 이 페이지의 내용 1. Firebase 프로젝트 설정 2. 앱에 앱 체크 라이브러리 추가 3. 앱 체크 초기화 다음 단계 측정항목 모니터링 및 적용 사용 설정 앱 체크 적용 사용 설정 디버그 환경에서 앱 체크 사용 이 페이지에서는 Android의 Play Integrity, Apple 플랫폼의 Device Check 또는 App Attest 등 기본 제공자를 사용하여 Unity 앱에서 앱 체크를 사용 설정하는 방법을 설명합니다. 앱 체크를 사용 설정하면 사용자의 앱만 프로젝트의 Firebas… Unity 앱에서 앱 체크 사용 시작하기 이 페이지의 내용 1. Firebase 프로젝트 설정 2. 앱에 앱 체크 라이브러리 추가 3. 앱 체크 초기화 다음 단계 측정항목 모니터링 및 적용 사용 설정 앱 체크 적용 사용 설정 디버그 환경에서 앱 체크 사용 이 페이지에서는 Android의 Play Integrity, Apple 플랫폼의 Device Check 또는 App Attest 등 기본 제공자를 사용하여 Unity 앱에서 앱 체크를 사용 설정하는 방법을 설명합니다. 앱 체크를 사용 설정하면 사용자의 앱만 프로젝트의 Firebas…

firebase로 하는 앱 체크(App Check)는 firebase의 백엔드 리소스에 접근하는 요청이 올바른 앱에서 발생하는 지 체크해주는 기능이다.

구글의 Play Integrity API 서비스는 실행된 앱에서 구글에 토큰을 요청하여 받을 수 있게 한다.

받은 토큰은 서버로 보내어 구글 플레이 스토어에서 올바르게 설치된 앱인지 서버에서 검증할 수 있게 해야 한다.

서버에서 검증을 통과할 경우 서버의 리소스에 접근 가능하도록 할 수 있고,

검증을 통과 못할 경우 서버 리소스에 접근을 못하게 할 뿐만 아니라 실행 중인 앱을 종료하도록 앱에 명령을 보낼 수도 있다.

따라서 서버를 가지고 있어야만 유용할 기능이 바로 Play Integrity API 토큰 서비스,

그리고 그 토큰을 보내서 Firebase 서버와의 연결도 검증하는 Firebase 앱체크인 것이다.

따라서 어떠한 백엔드 서버도 가지지 않고 Firebase도 사용하지 않는 앱은 해당 기능이 필요 없다.

정말로 백엔드 서버가 꼭 있어야 되는지와 관련해서 Chatgpt에게 물어보았다.

요약하자면, Play Integrity API 토큰을 사용해서 무결성 검사를 해서 의미 있는 보안 기능을 구현하려면 반드시 서버가 있어야 한다는 내용이다.


서버가 부담된다면 상대적으로 저렴한 클라우드 공급자의 서버리스 기능을 사용할 수 있다.

서버리스는 서버와 다르게 고정비는 들지 않지만 요청이 많아질 경우 그에 비례해서 요금을 내는 '유료' 요금제를 써야 한다. firebase도 그러하다.

유료로 Firebase 서버리스 API를 사용한다면 다음 내용을 참조할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class IntegrityChecker : MonoBehaviour
{
    public void VerifyToken(string token)
    {
        StartCoroutine(CallFirebaseFunction(token));
    }

    IEnumerator CallFirebaseFunction(string token)
    {
        string functionUrl = "https://us-central1-your-project-id.cloudfunctions.net/verifyPlayIntegrity";
        var request = new UnityWebRequest(functionUrl, "POST");
        byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(new { token }));
        request.uploadHandler = new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");

        yield return request.SendWebRequest();

        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Error: " + request.error);
        }
        else
        {
            Debug.Log("Response: " + request.downloadHandler.text);
        }
    }
}

정말로 구현하려 한다면 아래 sdk와 설치 문서를 참조하면 된다.

https://github.com/firebase/firebase-unity-sdk/releases/tag/v11.6.0

Release Firebase Unity SDK 11.6.0 · firebase/firebase-unity-sdk Prebuilt versions of the libraries are available for download here for a zip file, here for individual asset package, or here for individual .tgz package for Unity Package Manager. 11.6.0 Changes … Prebuilt versions of the libraries are available for download here for a zip file, here for individual asset package, or here for individual .tgz package for Unity Package Manager. 11.6.0 Changes …

https://developers.google.com/unity/archive?hl=ko#play_integrity_api https://firebase.google.com/docs/unity/setup-alternative?hl=ko

추가 Unity 설치 옵션  |  Firebase for Unity Firebase 데모 데이가 시작되었습니다. Google 최고의 기술을 활용하여 AI 기반 풀 스택 앱을 빌드하고 성장시키는 방법에 관한 데모를 시청 하세요. Firebase Firebase 문서 Firebase for Unity 기초 도움이 되었나요? 추가 Unity 설치 옵션 이 페이지의 내용 Firebase 패키지를 애셋으로 가져오기 Unity Package Manager를 사용하여 Firebase 패키지 가져오기 Unity Package Manager에서 애셋 패키지로 마이그레이션 애셋 패키지에서 Unity Package M… Firebase 데모 데이가 시작되었습니다. Google 최고의 기술을 활용하여 AI 기반 풀 스택 앱을 빌드하고 성장시키는 방법에 관한 데모를 시청 하세요. Firebase Firebase 문서 Firebase for Unity 기초 도움이 되었나요? 추가 Unity 설치 옵션 이 페이지의 내용 Firebase 패키지를 애셋으로 가져오기 Unity Package Manager를 사용하여 Firebase 패키지 가져오기 Unity Package Manager에서 애셋 패키지로 마이그레이션 애셋 패키지에서 Unity Package M…


혹시 그럼에도 불구하고 서버를 사용하지 않겠다! 내 앱에서 직접 무결성 검사를 하겠다! 하시는 분은 다음 내용이 도움이 되시면 좋겠습니다. 보안 문제는 있습니다.

Unity 앱에서 Google Play Integrity API의 응답을 처리하여 기기 무결성, 계정 세부정보, 애플리케이션 무결성을 검증하고 그 결과를 Debug.Log를 통해 출력하는 예시 코드는 다음과 같습니다. 이 코드는 Play Integrity API로부터 반환된 응답을 분석하여 해당 라벨에 따라 다른 메시지를 로그로 출력합니다.
이 코드는 Google Play Integrity API의 응답을 IntegrityApiResponse 클래스의 인스턴스로 변환한 후, 각 라벨(deviceIntegrity, accountDetails, applicationIntegrity)에 따라 적절한 메시지를 출력합니다. 실제 응답 데이터는 JSON 문자열 형태이며, 이 예시에서는 간단한 하드코딩된 문자열을 사용했습니다. 실제 애플리케이션에서는 API로부터 받은 실제 JSON 응답을 사용해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using UnityEngine;
using System;

public class PlayIntegrityResponseHandler : MonoBehaviour
{
    // 예시 응답 데이터, 실제 응답 데이터로 교체해야 함
    private string integrityApiResponse = "{\"deviceIntegrity\":\"MEETS_DEVICE_INTEGRITY\",\"accountDetails\":\"LICENSED\",\"applicationIntegrity\":\"PLAY_RECOGNIZED\"}";

    void Start()
    {
        // API 응답을 처리
        ProcessIntegrityResponse(integrityApiResponse);
    }

    private void ProcessIntegrityResponse(string responseJson)
    {
        try
        {
            var response = JsonUtility.FromJson(responseJson);

            // 기기 무결성 확인
            switch (response.deviceIntegrity)
            {
                case "MEETS_DEVICE_INTEGRITY":
                    Debug.Log("기기가 시스템 무결성 검사를 통과하고 Android 호환성 요구사항을 충족합니다.");
                    break;
                case "":
                    Debug.Log("앱이 공격이나 시스템 손상 징후가 있는 기기에서 실행되거나, 에뮬레이터에서 실행됩니다.");
                    break;
                default:
                    Debug.Log("기기 무결성: 알 수 없는 상태");
                    break;
            }

            // 계정 세부정보 확인
            switch (response.accountDetails)
            {
                case "LICENSED":
                    Debug.Log("사용자에게 앱 사용 권한이 있습니다.");
                    break;
                case "UNLICENSED":
                    Debug.Log("사용자에게 앱 사용 권한이 없습니다.");
                    break;
                case "UNEVALUATED":
                    Debug.Log("라이선스 세부정보가 평가되지 않았습니다.");
                    break;
                default:
                    Debug.Log("계정 세부정보: 알 수 없는 상태");
                    break;
            }

            // 애플리케이션 무결성 확인
            switch (response.applicationIntegrity)
            {
                case "PLAY_RECOGNIZED":
                    Debug.Log("앱과 인증서가 Google Play에서 배포된 버전과 일치합니다.");
                    break;
                case "UNRECOGNIZED_VERSION":
                    Debug.Log("인증서나 패키지 이름이 Google Play 레코드와 일치하지 않습니다.");
                    break;
                case "UNEVALUATED":
                    Debug.Log("애플리케이션 무결성이 평가되지 않았습니다.");
                    break;
                default:
                    Debug.Log("애플리케이션 무결성: 알 수 없는 상태");
                    break;
            }
        }
        catch (Exception ex)
        {
            Debug.LogError("Play Integrity API 응답 처리 중 오류 발생: " + ex.Message);
        }
    }

    // JSON 응답을 매핑하기 위한 클래스
    [Serializable]
    private class IntegrityApiResponse
    {
        public string deviceIntegrity;
        public string accountDetails;
        public string applicationIntegrity;
    }
}

실제 API로부터 받은 응답을 사용하도록 바꾼다면…
Unity에서 Google Play Integrity API를 사용하여 실제 응답을 받고 처리하는 과정은 다음과 같습니다. 이 프로세스는 클라이언트 측에서 API를 호출하고, 응답을 받아 처리하는 과정을 포함합니다.1. Play Integrity API 설정: Google Play Console에서 Play Integrity API를 설정하고 필요한 인증 정보를 얻습니다.2. Unity 프로젝트 설정: Unity 프로젝트에서 필요한 네트워크 라이브러리를 설정하고, API 호출을 위한 준비를 합니다.3. API 호출: Unity에서 Google Play Integrity API를 호출하고 응답을 받습니다.4. 응답 처리: 받은 응답을 분석하고 필요한 정보를 추출합니다.
Play Integrity API 호출 예시아래 코드는 Unity에서 Google Play Integrity API를 호출하는 예시입니다. 실제로 작동하려면 Google Play Console에서 얻은 인증 정보와 API 엔드포인트를 사용해야 합니다.
주의사항- API URL과 인증 정보는 보안을 위해 서버에서 관리하는 것이 좋습니다.- Unity에서 직접 API를 호출하는 것은 보안에 취약할 수 있으므로, 가능하다면 서버를 통해 API를 호출하고 응답을 클라이언트로 전달하는 방식을 권장합니다.- 이 코드는 기본적인 예시이며, 실제 애플리케이션에 사용하기 전에 필요한 보안 조치를 강구해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class PlayIntegrityAPIHandler : MonoBehaviour
{
    // Google Play Integrity API URL
    private string apiUrl = "YOUR_API_URL";

    // API 호출
    public void CallPlayIntegrityAPI()
    {
        StartCoroutine(GetPlayIntegrityResponse());
    }

    // API 응답을 Coroutine으로 처리
    private IEnumerator GetPlayIntegrityResponse()
    {
        using (UnityWebRequest request = UnityWebRequest.Get(apiUrl))
        {
            // API 요청 보내기
            yield return request.SendWebRequest();

            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("API 호출 실패: " + request.error);
            }
            else
            {
                // API 응답 처리
                string jsonResponse = request.downloadHandler.text;
                ProcessIntegrityResponse(jsonResponse);
            }
        }
    }

    // JSON 응답 처리
    private void ProcessIntegrityResponse(string responseJson)
    {
        try
        {
            var response = JsonUtility.FromJson(responseJson);
            Debug.Log("API 응답: " + responseJson);
            // 기타 응답 처리 로직 추가
        }
        catch (System.Exception ex)
        {
            Debug.LogError("응답 처리 중 오류: " + ex.Message);
        }
    }

    // JSON 응답을 매핑하기 위한 클래스
    [System.Serializable]
    private class IntegrityApiResponse
    {
        public string deviceIntegrity;
        public string accountDetails;
        public string applicationIntegrity;
    }
}

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.