- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한 지금 보는 글
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run
웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
‘누구로 실행’ × ‘누가 접근’ 조합이 데이터 권한과 코드 공개 여부를 결정한다. 공개 앱은 앱 레벨 인증을 따로 설계해야 한다.
웹앱 배포의 두 선택: “누구 권한으로 실행”과 “누가 접근”이 보안 모델을 결정한다. 코드를 짜기 전에 정하고 문서에 남겨야 나중에 권한 사고가 안 난다.
| Execute as | 의미 | 주의 |
|---|---|---|
| Me (배포자) | 항상 배포자 권한으로 실행 | 사용자별 권한 분리가 필요한 앱엔 부적합 |
| User accessing | 접속자 권한으로 실행 | 사용자 OAuth 동의·scope 누락 처리 필요 |
왜 중요한가
Execute as me로 “Anyone”에 공개하면, 접속한 누구나 배포자 권한으로 시트·메일을 건드릴 수 있게 된다. 입력 검증과 인증을 따로 안 하면 공개 엔드포인트가 그대로 뚫린다. 비용은 데이터 유출이나 오남용이다.
정직한 함정: 소스 공개
“Anyone with Google account”로 배포하면 프로젝트 공유가 필요해 고객이 소스를 열람할 수 있다. 코드 비공개가 계약 조건이면 “Me + Anyone” + 자체 앱 레벨 인증(이메일 코드 + CacheService 만료 등)으로 가야 한다.
공개 doPost는 tier로 지킨다
function doPost(e) {
try {
const body = JSON.parse(e.postData.contents || "{}");
if (!ALLOWED.has(body.action)) throw new Error("unknown action");
// payload의 함수명을 직접 실행하지 않는다 (allowlist만)
return json({ ok: true, result: handle(body) });
} catch (err) {
return json({ ok: false, error: String(err.message || err) });
}
}
- minimal: API key + handler allowlist + 입력 검증 (내부/저위험)
- standard: + timestamp/nonce replay 방지 + AuditLog (운영 데이터 쓰기)
- hardened: + HMAC 서명 + 함수별 ACL + rate limit (외부 공개·민감)
깊이: CORS는 simple request로
외부 브라우저에서 GAS를 호출할 땐 application/json 대신 text/plain;charset=utf-8을 기본값으로 둬 preflight를 피한다. 서버는 e.postData.contents를 직접 파싱하고, 오류도 HTTP status가 아니라 JSON body로 반환한다.
핵심 한 줄: 실행 주체·접근 범위·인증을 배포 전에 정하고, payload 함수명을 절대 직접 실행하지 마라.
자주 묻는 질문
- Execute as Me로 Anyone에 공개하면 어떤 위험이 생기나요?
- 접속한 누구나 배포자 권한으로 시트와 메일을 건드릴 수 있게 됩니다. 입력 검증과 인증을 따로 구현하지 않으면 공개 엔드포인트가 그대로 뚫립니다.
- Anyone with Google account 배포 시 소스 코드가 노출될 수 있나요?
- 네. 이 옵션은 프로젝트 공유가 필요하기 때문에 접속자가 소스를 열람할 수 있습니다. 코드 비공개가 계약 조건이라면 Me + Anyone 조합에 자체 앱 레벨 인증을 추가해야 합니다.
- 공개 doPost 엔드포인트를 최소한으로 보호하려면 무엇이 필요한가요?
- API 키, 핸들러 allowlist, 입력 검증이 기본(minimal) 티어입니다. payload의 함수명을 직접 실행하지 않고 allowlist에 등록된 핸들러만 호출해야 합니다.
- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한 지금 보는 글
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run