1. 시작하기 전에

빌드할 항목
이 Codelab에서는 App Check를 사용하여 웹 환경에서 사용되는 API 키에 또 다른 보호 레이어를 추가합니다.
특히 Codelab에서는 다음 단계를 따라 기능을 연결합니다.
- Google Maps Platform JavaScript API를 사용하여 지도를 호스팅하는 웹페이지를 만듭니다.
- 온라인에서 액세스할 수 있도록 페이지를 호스팅합니다.
- Cloud 콘솔을 사용하여 API를 사용할 수 있는 도메인과 API를 제한합니다.
- Firebase를 통해 앱 체크 라이브러리를 추가하고 초기화합니다.
- 애플리케이션 유효성을 확인하기 위해 증명 제공자를 추가합니다.
- 앱 및 모니터링에 대한 확인을 적용합니다.
Codelab이 끝나면 사용 중인 API 키, 액세스하는 도메인, 사용할 수 있는 애플리케이션 유형에 보안이 적용되는 사이트가 있어야 합니다.
2. 기본 요건
앱 체크를 사용 설정하려면 보호 기능을 제공하는 세 가지 Google 서비스를 사용해야 하므로 이러한 영역에 대해 잘 알고 있어야 합니다.
Firebase - API 키가 적절한 도메인에서 참조되고 있는지 확인하는 서비스의 시행을 제공합니다. 또한 Firebase Studio를 사용하여 호스팅 및 배포 기능을 제공합니다.
reCAPTCHA - 사람이 애플리케이션을 사용하고 있는지 확인하는 기능을 제공하며 Firebase를 클라이언트 애플리케이션 도메인에 연결하기 위한 공개 키와 비공개 키도 제공합니다.
Google Cloud Platform - Google Maps Platform과 Firebase에서 모두 사용하는 API 키와 지도 키를 사용하는 도메인에 대한 제한을 제공합니다.
다음 아키텍처 다이어그램에서 이러한 요소가 함께 작동하는 방식을 확인할 수 있습니다.

앱 체크와 Google Maps Platform을 사용하는 경우 다음 요소가 함께 작동하여 증명 제공자(이 경우 reCAPTCHA)가 제공하는 증명을 사용하여 요청이 유효한 애플리케이션과 사용자로부터 오는 것인지 확인합니다.
이는 Firebase에서 제공하는 앱 체크 SDK를 사용하여 실행됩니다. 이 SDK는 호출 애플리케이션의 유효성을 확인한 후 Google Maps Platform JavaScript API에 대한 후속 호출이 이루어지는 애플리케이션에 토큰을 제공합니다. 그러면 Google Maps Platform JavaScript API는 제공된 토큰의 유효성을 Firebase로 확인하여 올바른 도메인에서 제공될 뿐만 아니라 증명 제공업체를 통해 유효한 사용자로부터 제공되는지 확인합니다.
다음 위치에서 App Check 및 Maps JavaScript API 사용에 관한 자세한 내용을 확인할 수 있으며 필요한 단계를 숙지해야 합니다.
https://developers.google.com/maps/documentation/javascript/maps-app-check
3. 설정
아직 Google Cloud 계정이 없다면 시작 시 결제가 사용 설정된 계정을 설정해야 합니다. 시작하기 전에 안내에 따라 이를 만드세요.
Google Maps Platform 설정하기
Google Cloud Platform 계정 및 결제가 사용 설정된 프로젝트가 없는 경우 Google Maps Platform 시작하기 가이드를 참고하여 결제 계정 및 프로젝트를 만듭니다.
- Cloud Console에서 프로젝트 드롭다운 메뉴를 클릭하고 이 Codelab에 사용할 프로젝트를 선택합니다.

- Google Cloud Marketplace에서 이 Codelab에 필요한 Google Maps Platform API 및 SDK를 사용 설정합니다. 사용 설정을 위해 이 동영상 또는 이 문서에서 설명하고 있는 단계를 따르세요.
- Cloud Console의 사용자 인증 정보 페이지에서 API 키를 생성합니다. 이 동영상 또는 이 문서에서 설명하고 있는 단계를 따릅니다. Google Maps Platform에 대한 모든 요청에는 API 키가 필요합니다.
이 Codelab의 기타 요구사항
이 Codelab을 완료하려면 다음과 같은 계정, 서비스, 도구가 필요합니다.
- 자바스크립트, HTML 및 CSS에 대한 기본 지식
- 결제가 사용 설정된 Google Cloud 계정 (위에서 언급한 대로)
- Maps JavaScript API가 사용 설정된 Google Maps Platform API 키 (Codelab 중에 완료됨)
- 웹 호스팅 및 배포에 대한 기본적인 이해 (Codelab에서 안내해 드립니다). 이 작업은 Firebase Console 및 Firebase Studio를 통해 진행됩니다.
- 작업하면서 파일을 볼 수 있는 웹브라우저
4. Firebase Studio에서 페이지 만들기
이 Codelab에서는 이미 애플리케이션이 생성되었다고 가정하지 않으며 Firebase 스튜디오를 사용하여 지도 애플리케이션을 호스팅할 페이지를 만들고 테스트 목적으로 Firebase에 배포합니다. 기존 애플리케이션이 있는 경우 이를 대신 사용할 수도 있습니다. 올바른 구현을 위해 적절한 호스트 도메인, 코드 스니펫, API 키를 변경하세요.
Firebase Studio (Google 계정 필요)로 이동하여 새 Simple HTML 애플리케이션을 만듭니다. 이 옵션을 표시하려면 '모든 템플릿 보기' 버튼을 클릭하거나 이 링크를 클릭하여 직접 액세스해야 할 수도 있습니다.

작업공간에 적절한 이름 (예: myappcheck-map)을 지정합니다. 고유성을 위해 임의의 숫자를 추가할 수 있으며, 숫자가 자동으로 추가됩니다. 그러면 Firebase Studio에서 작업공간을 만듭니다.

이름을 입력한 후 만들기 버튼을 클릭하면 프로젝트 생성 프로세스가 시작됩니다.

생성되면 index.html 파일의 텍스트를 지도가 포함된 페이지를 만드는 다음 코드로 바꿀 수 있습니다.
<!doctype html>
<html>
<head>
<title>Secure Map</title>
<style>
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h3>App Check Security Demo</h3>
<!--The div element for the map -->
<div id="map"></div>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "YOUR_API_KEY",
v: "weekly",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map;
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
map = new Map(document.getElementById("map"), {
center: { lat: 51.5208, lng: -0.0977 },
zoom: 17,
});
}
initMap();
</script>
</body>
</html>
실행하면 이미지에 표시된 대로 작동하는 애플리케이션의 지도를 보여주는 페이지가 표시되어야 합니다. 하지만

페이지가 실제로 로드되면 오류가 표시됩니다. 페이지에 Google Maps Platform API 키가 필요하기 때문입니다. 이 키는 다음 섹션에서 추가됩니다.

실제 오류 메시지는 Firebase Studio의 웹 콘솔에서 확인할 수 있습니다.

이 문제를 해결하려면 페이지에 API 키를 추가해야 합니다. API 키는 페이지와 Maps JavaScript API 구현을 연결하는 방법입니다. 또한 API 키가 암호화되지 않은 방식으로 페이지에 포함되어야 하므로 악용될 수 있습니다. API 키가 가져와 다른 사이트에서 사용될 수 있기 때문입니다.
보호 방법 중 하나는 사용 중인 애플리케이션 유형 또는 호출되는 참조 도메인이나 IP 주소를 통해 애플리케이션 제한사항을 사용하는 것입니다. 권장사항에 대한 자세한 내용은 다음 사이트를 참고하세요.
https://developers.google.com/maps/api-security-best-practices#rec-best-practices
또는 명령줄이나 서버에서 직접 호출을 사용하는 경우, 자체적으로 리퍼러를 제공하거나 추적할 방법이 없어 잠재적으로 보안 허점이 될 수 있는 애플리케이션
5. Firebase 애플리케이션 만들기
Firebase는 증명 제공자를 연결하여 다음을 확인하는 기능을 제공하는 데 사용됩니다.
- 요청이 인증된 앱에서 발생함
- 요청이 변조되지 않은 인증된 기기 및 사용자 세션에서 발생합니다.
이 Codelab에서는 reCAPTCHA v3가 증명의 제공자로 사용됩니다.
Firebase 애플리케이션을 만들고 호스팅합니다.
https://firebase.google.com/ 으로 이동하여 '콘솔로 이동' 링크에서 새 Firebase 프로젝트를 만듭니다.

다음 영역을 클릭하여 새 프로젝트를 만듭니다.

프로젝트 이름을 선택합니다(예: 내 앱 확인 프로젝트). 참조용이므로 이전에 사용한 이름과 동일하지 않아도 됩니다. 텍스트 바로 아래에서 프로젝트의 실제 이름을 수정할 수 있으며, 입력한 이름으로 구성되고 고유하지 않은 경우 숫자가 추가됩니다.

애플리케이션에 Google 애널리틱스와 같은 다른 서비스를 추가하라는 메시지가 표시되면 수락해도 되고 수락하지 않아도 됩니다. 이 Codelab에서는 필요하지 않으므로 추가하지 않아도 됩니다.
'프로젝트 만들기' 버튼을 클릭하고 프로젝트가 생성될 때까지 기다립니다. 완료되면 알림이 전송됩니다.

프로젝트와 상호작용할 준비가 되면 계속을 클릭합니다.

기본 페이지에서 앱에 Firebase를 추가하고 웹 옵션을 선택하여 시작할 수 있습니다.

파일이 배포된 후 저장될 위치로 사이트에 Firebase 호스팅을 설정합니다 (실제 사이트의 경우 자체 옵션을 사용할 수 있지만 이 Codelab을 따라 하려면 Firebase 호스팅에 배포해야 함).

앱 등록을 클릭하여 애플리케이션을 만듭니다. 다음으로 생성된 스크립트를 사용하여 웹 애플리케이션에서 Firebase의 프로젝트를 참조합니다.
다음 탭의 Firebase 구성 코드는 Firebase와 지도 API를 함께 연결하는 데 애플리케이션에서 사용되므로 '스크립트 태그 사용' 섹션에서 복사하는 것이 좋습니다. 이 코드를 프로젝트 index.html에 붙여넣습니다.

다른 섹션의 경우 다음을 클릭한 다음 사이트의 프로젝트 설정 섹션에서 생성된 앱을 확인합니다.
나중에 돌아가서 구성 세부정보를 찾아야 하는 경우 아래와 같이 '설정' 버튼에서 앱 세부정보를 찾을 수도 있습니다.

이 섹션을 나가기 전에 나중에 reCAPTCHA와 함께 사용할 생성된 Firebase 호스팅 사이트의 도메인을 기록해야 합니다. 이를 통해 사이트 이름을 증명 제공업체에 연결할 수 있으므로 해당 사이트의 요청만 인증됩니다.
왼쪽의 프로젝트 바로가기 또는 빌드 메뉴에서 호스팅 섹션으로 이동합니다.
또는 
이 섹션에서 애플리케이션에 대해 생성된 도메인을 조회합니다. 아직 설정하지 않은 경우 설정을 완료하려면 몇 개의 화면을 클릭해야 할 수 있습니다.

6. API 키 보안
Firebase를 사용하는 계정으로 Cloud Console에 들어가서 생성된 프로젝트를 확인합니다.

프로젝트가 여러 개인 경우 드롭다운 또는 검색창을 사용하여 Firebase 프로젝트 이름이 있는 올바른 프로젝트를 선택해야 할 수 있습니다.

그러면 새로 만든 프로젝트가 열립니다. 이제 이 프로젝트 내에서 사용할 수 있도록 Maps JavaScript API를 프로젝트에 추가합니다. 여기에는 특정 API 키와 호스팅 도메인으로 사용을 제한하는 작업이 포함됩니다.

왼쪽의 메뉴를 사용하여 프로젝트에서 지도 API를 사용 설정합니다. 'API 및 서비스' 옵션과 '사용 설정된 API 및 서비스'를 선택합니다.

'API 및 서비스 사용 설정' 옵션을 선택합니다.

검색창에 'Maps JavaScript API'를 입력합니다.

일치하는 결과를 선택합니다.

그런 다음 API에서 사용 설정을 클릭하여 프로젝트에 추가합니다 (이전에 이 프로젝트를 사용한 경우 이미 완료되었을 수 있음).

이 기능을 사용 설정하면 API 키를 추가하고 제한할 수 있지만 지금은 건너뜁니다.
왼쪽 메뉴 옵션을 다시 사용하여 API 및 서비스 섹션으로 돌아가서 생성된 브라우저 키를 선택합니다.

API 제한사항 중 하나에 Maps JavaScript API를 추가합니다.

라이브 애플리케이션의 키의 경우 애플리케이션을 호스팅하는 도메인에 제한을 두어야 합니다. 지금 Firebase에서 생성된 도메인을 사용하여 이 작업을 실행하세요. 또한 도메인 끝에 /* 를 추가하여 도메인 아래의 모든 경로를 포함해야 합니다.

API 키 제한에 관한 자세한 내용은 다음 위치에서 이 기능을 사용 설정하는 방법을 참고하세요.
https://developers.google.com/maps/api-security-best-practices#restricting-api-keys
7. reCAPTCHA 보안 비밀 만들기
다음 단계는 클라이언트와 서버 모두의 증명 및 키를 제공하는 reCAPTCHA 프로젝트를 만드는 것입니다.
https://www.google.com/recaptcha/ 에서 reCAPTCHA 사이트로 이동하여 시작하기 버튼을 클릭합니다.

다음으로 새 사이트를 등록하고 제한할 도메인을 올바르게 입력합니다.

계정이 두 개 이상인 경우 Firebase에서 만든 것과 동일한 Google Cloud 프로젝트를 선택했는지도 확인합니다.
이렇게 하면 두 개의 키가 생성됩니다. 하나는 Firebase Console에 입력할 비밀 키로, 공개적으로 볼 수 있는 페이지나 애플리케이션에 절대 입력해서는 안 됩니다. 다른 하나는 웹 애플리케이션에서 사용할 사이트 키입니다.

이 페이지가 필요하므로 열어 두세요. 'Secret Key'(비밀 키) 복사 버튼을 클릭한 다음 Firebase 사이트로 돌아갑니다.
8. Firebase에 reCAPTCHA 추가
Firebase 관리 콘솔에서 왼쪽 메뉴 항목으로 이동합니다. 빌드 메뉴 항목에서 App Check를 선택합니다.

앱이 등록될 때까지 서비스 목록을 사용 설정할 수 없습니다 (이전에 호스팅이 사이트에 추가될 때 생성됨). 설정해야 하는 경우 시작을 클릭하세요.
앱 탭을 클릭하고 웹 앱을 연 다음 reCAPTCHA 사이트에서 복사한 보안 비밀을 입력하고 저장을 클릭합니다.

이제 reCAPTCHA 제공업체 옆에 녹색 체크표시가 표시됩니다. 이제 이 웹 애플리케이션에서 reCAPTCHA를 사용하여 사용자 또는 사이트가 서비스를 올바르게 호출하는지 증명할 수 있습니다.

이제 API 탭에 Google Maps Platform API가 활성 상태이지만 시행되지 않는 것으로 표시됩니다.

이제 reCAPTCHA 비밀을 Firebase 프로젝트에 연결했으므로 웹페이지에 코드를 추가하여 사이트 키를 Maps 애플리케이션과 함께 사용할 올바른 제공업체와 일치시킬 수 있습니다.
사이트 키는 reCAPTCHA에서 비밀 키와 일치하는지 확인합니다. 완료되면 호출 페이지가 올바른지 확인하고 App Check는 이 증명 없이 토큰이 제공되지 않고 요청을 검증할 수 없는 Maps JavaScript API에 대한 후속 호출에서 사용할 수 있는 토큰을 제공합니다.
9. 페이지에 인증을 추가하고 배포합니다.
Cloud 콘솔로 돌아가 Maps API에 사용할 API 키를 복사합니다.
이 값은 콘솔의 측면 메뉴에 있는 'API 및 서비스' 측면 메뉴의 '사용자 인증 정보' 옵션에서 확인할 수 있습니다.

여기에서 기존 브라우저 키를 선택할 수 있습니다 (다른 기존 키를 사용하거나 새 키를 만들 수도 있음).

키 표시 버튼을 클릭하고 표시된 대화상자 창에서 키를 복사합니다.
이전에 만든 HTML 페이지가 열려 있는 Firebase 스튜디오 프로젝트로 돌아갑니다. 이제 페이지에 API 키를 추가하여 페이지에 'YOUR_API_KEY'가 있는 경우 지도 API가 작동하도록 할 수 있습니다.

페이지를 다시 실행하면 이제 다른 오류 메시지가 표시됩니다.

즉, 페이지를 호스팅하는 개발 도메인이 허용되지 않습니다 (배포된 도메인만 추가됨). Firebase 호스팅을 사용하여 이 사이트를 올바른 도메인에 게시해야 합니다. 자세한 내용은 다음 위치에서 확인할 수 있습니다.
이 동영상
Project IDX에서 Firebase 웹 앱을 더 빠르게 빌드, 테스트, 배포

자세한 내용은 Maps JavaScript API 사이트의 지도 로드 오류를 참고하세요.
RefererNotAllowedMapError가 표시되면 페이지를 올바른 도메인에 배포하여 이 문제를 해결할 수 있습니다.
Firebase Studio로 돌아가 'Firebase Studio' 아이콘을 클릭하여 호스팅 옵션을 엽니다. 이 아이콘은 설정한 옵션에 따라 왼쪽 끝 또는 오른쪽 끝에 있을 수 있습니다.

이 Codelab에서는 다음으로 'Firebase로 앱 호스팅'을 통해 Firebase 인스턴스를 스튜디오 애플리케이션과 연결해야 합니다.

그런 다음 'Firebase 인증'을 클릭하여 인증 프로세스를 시작합니다. 이렇게 하면 스튜디오 내에서 백엔드를 사용하여 호스팅을 자동화할 수 있습니다.

명령 창의 안내에 따라 배포를 승인합니다.

화면에 표시된 안내 (새 창 열기 포함)에 따라 요청된 위치에 승인 코드를 복사하여 Firebase 스튜디오의 명령어 창에 붙여넣습니다.

이 절차에 대한 자세한 내용은 다음 위치에서 확인할 수 있습니다.
https://firebase.google.com/docs/studio/deploy-app
이 단계를 완료한 후 'Firebase 호스팅 초기화'를 클릭하여 프로젝트를 Firebase 프로젝트에 연결할 수 있습니다.
'기존 프로젝트 사용'을 선택하고 앞 섹션에서 만든 프로젝트를 선택합니다. 나머지 기본값은 그대로 적용합니다 (예는 프로젝트를 설정할 때 선택한 이름에 따라 다를 수 있음).

탐색기 뷰로 돌아가서 public 디렉터리에 생성된 index.html 파일을 루트 디렉터리에 이미 있던 파일로 바꿉니다.

이제 Firebase Studio 사이드바로 돌아가 사이트를 프로덕션에 배포할 수 있습니다.

그러면 콘솔에 배포 단계가 표시됩니다.

표시된 '호스팅 URL'에서 배포된 사이트를 엽니다 (여기서는 https://my-app-check-project.web.app/ 으로 표시되지만 프로젝트마다 다름).
이제 사용 중인 도메인에서 API가 작동하므로 애플리케이션에 페이지의 지도가 표시됩니다.

이제 API 키와 함께 사용할 수 있는 API 유형과 API 키를 사용할 수 있는 도메인에 대한 제약 조건이 적용된 작동하는 페이지가 있습니다. 다음 단계는 해당 도메인에 대한 액세스만 허용하도록 잠그는 것입니다. 이렇게 하려면 이전에 생성된 Firebase 스크립트 섹션을 추가하여 앱 체크를 사용하여 페이지를 보호해야 합니다. 이 작업은 다음 섹션에서 수행합니다.
10. 보안 페이지
현재 페이지에서는 도메인에 API 키를 보안 처리하지만, 올바른 애플리케이션과 사람이 사용하고 있는지 확인하기 위한 증명 단계를 추가하지는 않습니다. 악의적인 행위자가 키를 훔쳐 사용할 수 있습니다. 이 문제를 해결하려면 클라이언트의 올바른 토큰을 가져오기 위해 Firebase 구성, 제공업체, 사이트 키를 페이지에 추가해야 합니다.
또한 Maps API의 사용량이 Firebase에서 추적되고 있음을 확인할 수 있습니다. 올바른 토큰을 사용하지 않으므로 확인되지 않은 요청을 하고 있습니다.
필요한 연결 세부정보는 Firebase 프로젝트에서 가져올 수 있습니다.
Firebase 구성 세부정보가 포함된 콘솔에서 Firebase 세부정보를 가져옵니다. Firebase의 프로젝트 설정 페이지로 이동하여 앱의 CDN 섹션에서 CDN 설정의 코드 섹션을 가져옵니다 (가장 간단함).
Firebase 프로젝트에서 톱니바퀴를 선택하여 프로젝트 설정을 표시합니다.

앱 아래의 일반 섹션에 세부정보가 포함된 다음 페이지가 열립니다.

지도가 포함되어 호스팅되는 Firebase 스튜디오 페이지 (public/index.html)에 이를 복사합니다. 다음과 같이 표시됩니다 (세부정보는 이 파일의 세부정보와 정확히 일치하지 않음).
<!doctype html>
<html>
<head>
<title>Secure Map</title>
<style>
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h3>App Check Security Demo</h3>
<!--The div element for the map -->
<div id="map"></div>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "YOUR_API_KEY",
v: "weekly",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script type="module">
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.2.1/firebase-app.js";
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "appcheck-map.firebaseapp.com",
projectId: "appcheck-map",
storageBucket: "appcheck-map.firebasestorage.app",
messagingSenderId: "YOUR_SENDER_KEY",
appId: "YOUR_APP_ID"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
let map;
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
map = new Map(document.getElementById("map"), {
center: { lat: 51.5208, lng: -0.0977 },
zoom: 17,
});
}
initMap();
</script>
</body>
</html>
이제 Firebase가 애플리케이션에 추가되었으므로 앞에서 reCAPTCHA 사이트에서 가져온 제공된 사이트 키를 사용하여 reCAPTCHA 라이브러리를 호출합니다.

다음 지도 문서 페이지에서 이러한 섹션 추가에 대해 자세히 알아볼 수 있습니다.
https://developers.google.com/maps/documentation/javascript/maps-app-check
페이지에 앱 체크 라이브러리를 추가한 다음 함수를 로드하여 firebase 구성으로 앱 체크를 초기화하고 ReCaptchaV3Provider를 사용하여 토큰을 가져옵니다.
먼저 앱 체크 라이브러리를 가져옵니다.
import {
getToken,
initializeAppCheck,
ReCaptchaV3Provider,
} from "https://www.gstatic.com/firebasejs/12.2.1/firebase-app-check.js";
다음으로 사이트 토큰을 사용하여 Firebase 구성 및 reCAPTCHA 제공자로 앱 체크를 초기화하는 코드를 추가합니다.
// Get App Check Token
const appCheck = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('<INSERT SITE KEY>'),
isTokenAutoRefreshEnabled: true,
});
마지막으로 Maps Core 라이브러리의 설정 함수를 사용하여 토큰을 가져와 지도 컨트롤에 함수를 연결합니다. 이렇게 하면 토큰 수명에 따라 지도 컨트롤에 필요한 토큰 요청이 이루어집니다.
const { Settings } = await google.maps.importLibrary('core');
Settings.getInstance().fetchAppCheckToken = () =>
getToken(appCheck, /* forceRefresh = */ false);
전체 파일은 다음과 같습니다.
<!doctype html>
<html>
<head>
<title>Secure Map</title>
<style>
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h3>App Check Security Demo</h3>
<!--The div element for the map -->
<div id="map"></div>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "YOUR_API_KEY",
v: "weekly",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.2.1/firebase-app.js";
import {
getToken,
initializeAppCheck,
ReCaptchaV3Provider,
} from "https://www.gstatic.com/firebasejs/12.2.1/firebase-app-check.js";
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "appcheck-map.firebaseapp.com",
projectId: "appcheck-map",
storageBucket: "appcheck-map.firebasestorage.app",
messagingSenderId: "YOUR_SENDER_KEY",
appId: "YOUR_APP_ID"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Get App Check Token
const appCheck = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('<INSERT SITE KEY>'),
isTokenAutoRefreshEnabled: true,
});
let map;
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
const { Settings } = await google.maps.importLibrary('core');
Settings.getInstance().fetchAppCheckToken = () =>
getToken(appCheck, /* forceRefresh = */ false);
map = new Map(document.getElementById("map"), {
center: { lat: 51.5208, lng: -0.0977 },
zoom: 17,
});
}
initMap();
</script>
</body>
</html>
Firebase Studio를 사용하여 Firebase 사이트에 배포하고 페이지를 실행합니다.
11. 모니터링 적용
이제 페이지가 설정되었으므로 실행하면 확인되고 있음을 확인할 수 있습니다. Firebase Console로 돌아가서 앱 체크 섹션을 다시 엽니다. 이제 앱 체크에서 Maps JavaScript API를 모니터링해야 합니다.

이제 창을 열면 클라이언트가 요청을 하고 증명이 작동하는 것을 확인할 수 있습니다 (그래프에 어두운 파란색 'verified' 요청으로 표시됨). 다른 요청은 인증이 완료되기 전 개발 단계에서 호출을 표시합니다.

이제 클라이언트가 작동하는 것을 확인할 수 있으므로 사이트에서 시행을 사용 설정하여 유효하지 않은 클라이언트 애플리케이션에서 API 키를 사용할 수 없도록 할 수 있습니다. '시행' 버튼을 클릭하여 시행을 시작합니다.

이 버튼을 클릭하면 애플리케이션이 잠긴다는 큰 경고 표시가 표시됩니다. 실제 환경에서는 모든 클라이언트에 올바른 키가 있고 작동하는 경우에만 이 작업을 실행해야 합니다. 그렇지 않으면 사용자가 사이트에 액세스하지 못할 수 있습니다.

또한 시행하는 데도 시간이 걸릴 수 있습니다. 화면에 표시되듯이 즉시 시행을 테스트하면 전파될 시간이 없었을 수 있습니다.

페이지를 요청할 때 이전과 같이 작동하는 것을 확인할 수 있으며 사이트에는 실제로 변경된 사항이 없습니다.
이제 시간이 지남에 따라 콘솔에서 확인된 요청 수가 증가합니다.

Codelab의 원래 샘플로 돌아가 앱 확인 기능이 없는 새 페이지를 만들어 작동하는지 테스트할 수 있습니다. 이 페이지의 이름을 nocheck.html로 지정하고 index.html과 동일한 위치의 공개 폴더에 배치합니다.
<!doctype html>
<html>
<head>
<title>Secure Map</title>
<style>
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h3>App Check Security Demo</h3>
<!--The div element for the map -->
<div id="map"></div>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "YOUR_API_KEY",
v: "weekly",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map;
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
map = new Map(document.getElementById("map"), {
center: { lat: 51.5208, lng: -0.0977 },
zoom: 17,
});
}
initMap();
</script>
</body>
</html>
이 작업을 완료하고 올바른 API 키를 입력한 후 페이지를 요청하면 (yourdomain/nocheck.html 사용) 다음 회색 오류 상자가 표시됩니다.

콘솔을 확인하면 다음과 같은 오류 메시지가 표시됩니다.

강제 적용된 사이트의 앱 확인 토큰을 더 이상 가져오지 않으므로 앱 확인이 페이지의 지도 요청을 차단했습니다.
12. 축하합니다.
사이트에서 앱 체크를 사용 설정했습니다.

Firebase 앱 체크를 사용하여 요청이 유효한 도메인과 사용자로부터 전송되었는지 확인하는 애플리케이션을 성공적으로 빌드했습니다.
학습한 내용
- Firebase Studio를 사용하여 웹페이지를 호스팅하고 배포하는 방법
- Cloud 콘솔을 사용하여 Google Maps Platform API를 사용 설정하고 보호하는 방법
- reCAPTURE를 사용하여 호출을 증명하는 데 사용할 수 있는 키를 생성하는 방법
- Firebase 앱 체크를 사용하고 Maps JavaScript API에 통합하는 방법
- Firebase Studio를 사용하여 보호된 사이트에 대한 호출을 강제 적용하고 모니터링하는 방법을 알아보세요.