GitHub Push Protection, 보안의 마지막 경고

jul ee·2025년 5월 19일

데이터 성장기

목록 보기
101/139

GitHub는 최근 몇 년 사이 보안 기능을 꾸준히 강화해왔다.

특히 잘 알려진 시크릿 값들이 코드에 포함되는 것을 막기 위해 Secret Scanning 및 Push Protection 기능을 기본적으로 제공하고 있다.

이 글에서는 React Native 앱 개발 중 Google Sheets 연동을 위한 OAuth 토큰 설정 과정에서 발생한 Push Protection 차단 사례를 담아 보았다. 해당 오류를 해결하면서 얻은 경험과 보안에 대한 교훈을 공유하기 위해 작성해 보았다.

결국 결론은 보안에 경각심을 가지는 것,  커밋 전에 한 번 더 확인하는 습관 !



문제 상황

날씨 앱에서 사용자 로그 데이터 수집을 위해 Google Sheets 연동을 세팅하는 중에 문제가 발생했다. OAuth 인증을 통해 얻은 토큰들을 AsyncStorage에 저장하는 로직을 구현했었다.

보안 문제를 방지하기 위해 GOOGLE_ACCESS_TOKEN, GOOGLE_REFRESH_TOKEN은 .env에 잘 분리해서 사용했고, .gitignore에도 .env를 추가해 깔끔하게 관리했다.

그런데 브랜치에서 두 개의 커밋을 한 뒤 푸시하려 했을 때 에러가 발생하며 푸시가 차단되었다.

remote: error: GH013: Repository rule violations found for refs/heads/feat/#407.
...
remote: —— Google OAuth Client Secret ————————————————————————
remote:   path: front/src/api/googleSheetLogger.js:6
...
remote: Push cannot contain secrets

GH013 에러와 Push cannot contain secrets라는 메시지는 처음 만나는 거라 좀 당황했다. GitHub가 내 푸시를 아예 거부한 것이다.



원인 분석

Push cannot contain secrets

깃이 친절하게 알려준 덕분에 문제의 원인을 바로 찾아낼 수 있었다.

확인해보니 Google OAuth Client ID와 Secret을 하드코딩한 코드가 그대로 커밋되어 있었다.

  • Google Sheets API를 연동하여 로그 데이터를 기록하려면 Google 계정에 대한 인증 및 권한 부여 과정(OAuth 2.0)을 반드시 거쳐야 한다. Google OAuth Client ID와 Client Secret은 이때 사용된다.

  • 특히 Client Secret은 서버 간 인증에 사용되는 비공개 키로, 말 그대로 외부에 노출되면 안 되는 민감 정보이다.

토큰 발급 과정에서 몇 가지 테스트한다고 넣어둔 건데, 테스트 중에 발생한 에러를 해결하는 데 정신이 팔려서 처리하는 걸 잊고 올려버렸다.

const CLIENT_ID = '...';
const CLIENT_SECRET = '...';

GitHub는 알려진 패턴의 시크릿(Google, AWS, Firebase 등)을 자동으로 감지하여 푸시 자체를 차단하는 Secret Scanning + Push Protection 기능을 제공하고 있는데, 정확히 여기에 걸린 것이다.

하마터면 토큰이 그대로 올라갈 뻔했다. 감사합니다..



해결 방법

1. 시크릿을 .env로 이동

기존 코드에서 하드코딩된 값을 모두 제거하고, .env에서 불러오도록 수정했다.

// .env
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
// googleSheetLogger.js
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '@env';

const CLIENT_ID = GOOGLE_CLIENT_ID;
const CLIENT_SECRET = GOOGLE_CLIENT_SECRET;

2. 커밋 수정 (-amend)

이미 하드코딩된 시크릿이 포함된 상태로 커밋이 된 상황이었기 때문에, 새로운 커밋을 만드는 대신 기존 커밋을 덮어씌우는 방식으로 수정했다.

git add front/src/api/googleSheetLogger.js
git commit --amend

3. 강제 푸시 (-force)

수정된 커밋으로 기존 기록을 덮어씌운 상태라서 원격 저장소에는 --force 옵션으로 강제 푸시해야 했다.

git push origin "feat/#407" --force

이제 GitHub의 Push Protection에도 걸리지 않고, PR에 커밋이 정상적으로 반영되었다.




인사이트 및 교훈 ..

  • GitHub는 자동으로 Google, AWS, Stripe 등 수십 가지 시크릿 유형을 탐지한다.

  • .env로 분리만 했다고 끝이 아니다. 하드코딩된 시크릿이 있는 파일이 커밋되면 즉시 차단된다.

  • git commit --amend + -force는 이미 커밋된 민감 정보 제거 후 다시 푸시할 때 해결책으로 사용될 수 있다. (그래도 force는 항상 주의하자)

  • 평소에 .env만 신경 쓰는 것이 아니라, 커밋 전에 하드코딩된 민감 정보가 없는지 다시 점검하는 것이 필요하다.

하드코딩된 시크릿은 한 줄의 코드이지만 프로젝트의 보안을 무너뜨릴 수 있다.

무엇보다 중요한 건 커밋 전에 한 번 더 확인하는 습관!

profile
AI에 관심을 가지고, 데이터로 가치를 만들어 나가는 과정을 기록합니다.

0개의 댓글