Skip to content

[Fix] FCM 토큰 로그 마스킹#240

Merged
pooreumjung merged 1 commit into
developfrom
fix/#217-fcm-token-log-masking
Jun 19, 2026
Merged

[Fix] FCM 토큰 로그 마스킹#240
pooreumjung merged 1 commit into
developfrom
fix/#217-fcm-token-log-masking

Conversation

@pooreumjung

Copy link
Copy Markdown
Member

🧾 요약

  • 로그에 FCM 디바이스 토큰 원문이 출력되는 보안 이슈 수정 — 앞 8자리만 노출하는 마스킹 처리 적용

🔗 이슈

✨ 변경 내용

  • AsyncNotificationDispatchermaskToken() 헬퍼 추가
  • FCM 발송 성공/실패/만료 로그 3곳 모두 마스킹 처리 적용

✅ 확인

  • 빌드 OK
  • 테스트 OK

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 26884904-1cbd-4a3c-8532-81c15649ea85

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/#217-fcm-token-log-masking

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pooreumjung pooreumjung self-assigned this Jun 19, 2026
@pooreumjung pooreumjung added the bug Something isn't working label Jun 19, 2026
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

본 PR은 FCM 알림 발송 과정에서 발생하는 로그에 디바이스 토큰 원문이 노출되는 문제를 개선합니다. 토큰의 앞 8자리만 노출하도록 마스킹 로직을 적용함으로써, 로그를 통한 개인정보 유출 가능성을 차단하고 보안성을 강화하는 것을 목적으로 합니다.

Highlights

  • 보안 강화: 로그에 FCM 디바이스 토큰 원문이 그대로 노출되는 보안 취약점을 해결하기 위해 마스킹 처리를 도입했습니다.
  • 마스킹 로직 구현: AsyncNotificationDispatcher 클래스에 토큰의 앞 8자리만 노출하고 나머지는 마스킹하는 maskToken() 헬퍼 메서드를 추가했습니다.
  • 로그 적용: FCM 발송 성공, 실패, 만료 관련 로그 3곳에 마스킹 로직을 적용하여 민감 정보 노출을 방지했습니다.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@pooreumjung pooreumjung merged commit 2adb830 into develop Jun 19, 2026
3 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces FCM token masking in log messages within AsyncNotificationDispatcher to prevent sensitive token exposure. The reviewer provided two valuable recommendations: wrapping the token deletion call in a try-catch block to ensure robust exception handling during dispatch, and adding a unit test to verify that the original unmasked token is correctly passed to the deletion service.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 59 to 67
private void handleSendError(String token, FirebaseMessagingException e) {
MessagingErrorCode code = e.getMessagingErrorCode();
if (code == MessagingErrorCode.UNREGISTERED || code == MessagingErrorCode.INVALID_ARGUMENT) {
log.warn("만료/잘못된 토큰 삭제 (token={}, code={})", token, code);
log.warn("만료/잘못된 토큰 삭제 (token={}, code={})", maskToken(token), code);
fcmTokenService.deleteExpired(token);
} else {
log.error("FCM 발송 실패 (token={}, code={}): {}", token, code, e.getMessage());
log.error("FCM 발송 실패 (token={}, code={}): {}", maskToken(token), code, e.getMessage());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

**[P1]                                  **

**   :**
handleSendError           fcmTokenService.deleteExpired(token)           ,            ( :         ,           )               dispatch                . handleSendError      try-catch     catch                ,                            .                                         FCM                                   .

    private void handleSendError(String token, FirebaseMessagingException e) {
        MessagingErrorCode code = e.getMessagingErrorCode();
        if (code == MessagingErrorCode.UNREGISTERED || code == MessagingErrorCode.INVALID_ARGUMENT) {
            log.warn("만료/잘못된 토큰 삭제 (token={}, code={})", maskToken(token), code);
            try {
                fcmTokenService.deleteExpired(token);
            } catch (Exception ex) {
                log.error("만료된 토큰 삭제 중 에러 발생 (token={}): {}", maskToken(token), ex.getMessage(), ex);
            }
        } else {
            log.error("FCM 발송 실패 (token={}, code={}): {}", maskToken(token), code, e.getMessage());
        }
    }
References
  1.   ,     , FCM                     ,              (                          )                                        . (link)

Comment on lines +69 to +75
private String maskToken(String token) {
if (token == null || token.isBlank()) {
return "<empty>";
}
int visibleLength = Math.min(8, token.length());
return token.substring(0, visibleLength) + "***";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

**[P3] maskToken                         **

**   :**
        maskToken          handleSendError                                   .    ,                (maskToken(token))      ,            (fcmTokenService.deleteExpired(token))                                    ,                                                          .

**     :**
AsyncNotificationDispatcherTest                                                                   .

@Test
void dispatchDeletesExpiredTokenWithOriginalTokenOnUnregisteredError() throws Exception {
    AsyncNotificationDispatcher dispatcher = dispatcher();
    NotificationDispatchCommand command = new NotificationDispatchCommand(
            1L, 10L, NotificationType.COMMUNITY_COMMENT,
            "title", "body", Map.of(), List.of("long-fcm-token-value")
    );

    doThrow(new FirebaseMessagingException("test", "unregistered", MessagingErrorCode.UNREGISTERED))
            .when(fcmService).sendMessage(any(), any(), any(), any(), anyBoolean());

    dispatcher.dispatch(command);

    verify(fcmTokenService).deleteExpired("long-fcm-token-value");
}
References
  1.                                          . (link)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] FCM 토큰 원문 로그 출력

1 participant