admob 서버사이드 검증(SSV)를 진행하자

Alex·2025년 2월 17일
0

Plaything

목록 보기
111/118

Plaything에서는 광고를 시청하면 유저에게 포인트를 제공한다.
이를 위해서 서버에서 ssv라는 검증을 해줘야 한다고 한다.

Server-side verification validates each completed rewarded ad view. This ensures you're only rewarding users who actually finished watching the video in your app.
Each time a user finishes viewing a rewarded ad, AdMob uses the callback URL you provide to validate the view.

구글 애드몹 페이지에 있는 설명으로, 실제로 광고를 모두 시청한 유저에게만 보상을 제공하도록 하는 검증을 말한다.

서버에서 콜백 url을 전달하면, 애드몹이 이걸 통해서 광고 조회를 validate해준다.

콜백 url이란 내가 호출한 외부 api가 작동을 끝낸 후에, 해당 api서버에서 다시 콜백(호출)해주는 url을 말한다. 즉, 우리가 구글 애드몹 관련 api 요청을 보내면 이때 구글 애드몹에서 작업을 끝낸 후에 plaything 서버의 api를 호출해준다고 생각하면 된다.

구글에서 어떻게 진행해야 할지 예제를 보여준다.

Tink 의존성을 추가한 뒤에 코드를 작성했다.

    //SSV
    implementation group: 'com.google.crypto.tink', name: 'tink''
    implementation 'com.google.crypto.tink:apps-rewardedads'
    

이 두개의 의존성을 먼저 추가해줘야 한다.

코드 작업은 굉장히 간단하다.

이렇게 코드만 짜주면 된다.
그런데, 역시 처음부터 잘 되지 않았다.

우선, 애드몹에서 정해진 규격은 GET 메서드였다. 지금은 POST 메서드로 돼 있어서 API 요청이 오지 않았고, GET으로 변경했더니 이제는 401이 떴다.

애드몹에서 정해진 규격에 따라 GET 요청을 보내는 것이기에 헤더로 JWT 토큰을 넣을 수가 없었다.

그래서, 고민해본 방식은 JWT 토큰으로 임시 토큰을 발급한 뒤에 이걸 JWT 토큰과 임시토큰을 매칭시켜서 메모리에 저장 -> 콜백 URL로 지정된 API를 호출할 때는 헤더에 JWT 토큰을 넣는 대신 임시 토큰을 URL 파라미터로 넣기로 했다.

이렇게 한 방식은 JWT 토큰을 URL에 노출하는 것이 보안상 좋지 않기 때문이다. 관련 내용은 JWT 토큰을 URL에 넣어도 될까?에 정리해두었다. URL은 브라우저 히스토리에 기록으로 남기 때문에 JWT 토큰을 URL로 넣으면 안된다.

이제 문제가 해결됐나 싶더니 queryString이 null이라는 예외가 계속 발생했다.

구글에서 보여준 예제를 보면 이 rewardUrl이 어떻게 들어가야 하는건지 정확하지 않아서 일단 url을 넣고 디버깅을 해봤다.

여길 보면, queryString을 잘라오는 부분이 있는데
url을 url로 들어간 파라미터 쿼리들이 잘라진 채로 들어가 있었다.

그래서 이렇게 도메인+querystring을 해주고서 이를 verify에 넣었다.

그렇게 하면 query들이 등록이 돼서 파싱이 잘 되고 안에서 해독까지 잘 해준다.
그렇다면, 어떤 파라미터를 받아야하는지? 궁금했다.

지금은 콜백 url로 날라오는 모든 파라미터를 다 받고 있는데
그중에서 하나라도 빼면

invalid signature라는 예외가 발생한다.


여기서 발생하는 것으로 보인다.

여기서 예외가 터진다.

구글 애드몹에서 수동으로 검증하는 과정을 한번 살펴보자

어떤 원리로 필요한 파라미터를 판단할 수 있을지 잘 모르겠다.
그래서, 구글 애드몹에서 제공한 수동 검증과정을 한번 살펴봤다.

우선 Admob이 제공하는 공개키가 필요하다.

이걸 json형태로 바꿔준다. 공개키는 정기적으로 로테이션 된다고 한다.

이렇게 나오는데 ssv 콜백은어떤 방식으로든 수정해서는 안된다고 한다. 쿼리 매개변수의 순서 유지까지 포함.

디버깅을 해보니

여길 보면 queryString가 있는 것의 인덱스를 구하고,

직접 저렇게 잘라보니
index를 통해서 querystring을 모두 뽑아오는 것으로보인다.

그리고 전체 쿼리 스트링을 다 검증한다.
모든 쿼리 파라미터를 그대로 다 보내는 게 맞는듯하다.

혹시나 싶어서 쿼리 파라미터를 하나씩 빼보면서 테스트해봤지만
하나라도 없으면 invalid signature 예외가 발생했다.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글