서론
Google Apps Script Web Apps는 개발자가 Google Workspace 서비스와 통합하여 웹 기반 애플리케이션을 구축할 수 있는 강력한 플랫폼이다. 그러나 기본적으로 Google Apps Script Web Apps는 전통적인 서버리스 환경과 유사하게 무상태(stateless) HTTP 요청-응답 모델을 기반으로 작동한다. 사용자 인증 및 세션 관리에 대한 기본 지원이 제한적이어서, 보안이 중요한 애플리케이션에서는 추가적인 보안 설계가 필요하다.
무상태 환경에서 인증을 구현할 때 가장 큰 도전은 클라이언트와 서버 간의 상태를 유지하는 것이다. 기본적으로 Apps Script Web Apps는 HTTP 쿠키를 통해 세션 상태를 관리하도록 설계되어 있지만, 이 방식은 제한적이며 모든 보안 요구사항을 충족하지 못한다. 특히, CORS(Cross-Origin Resource Sharing) 제약으로 인해 외부 도메인에서 실행되는 클라이언트 애플리케이션과 통합할 때 쿠키 기반 인증이 작동하지 않는 경우가 많다.
이러한 제약을 극복하기 위해 토큰 기반 인증 메커니즘이 널리 사용된다. 토큰 기반 인증은 상태를 유지하지 않는 무상태 아키텍처에 적합하며, 클라이언트가 토큰을 포함하여 요청을 보내면 서버가 토큰의 유효성을 검증하여 인증을 수행한다. 하지만 이 방식도 올바르게 구현되지 않으면 심각한 보안 취약점이 발생할 수 있다.
본론
Apps Script Web Apps의 보안 모델 제한
Google Apps Script Web Apps는 기본적으로 HTTP GET/POST 요청을 처리할 수 있는 doGet(e) 및 doPost(e) 함수를 제공한다. 이 함수들은 이벤트 객체 e를 통해 요청 파라미터, 쿼리 문자열, 경로 정보 등에 접근할 수 있다. 하지만 이 아키텍처는 전형적인 웹 서버와 달리 다음과 같은 보안 제한이 존재한다.
첫째, 기본 인증 메커니즘이 OAuth 2.0에 의존한다. Apps Script Web Apps는 사용자가 앱에 액세스할 때 OAuth 2.0 인증 흐름을 통해 권한을 부여하도록 설계되어 있다. 이는 Google Workspace 서비스에 대한 접근을 제어하는 데는 적합하지만, 일반적인 웹 애플리케이션 인증 요구사항을 충족하는 데는 제한적이다.
둘째, 세션 관리가 어렵다. 전통적인 웹 애플리케이션은 서버 측 세션 저장소와 쿠키를 사용하여 사용자 상태를 유지한다. 그러나 Apps Script Web Apps는 서버리스 환경에서 실행되며, 요청 간에 상태를 유지하기 위한 기본 메커니즘이 제한적이다. 쿠키를 사용하여 세션을 관리할 수 있지만, CORS 제약으로 인해 외부 클라이언트 애플리케이션과 통합할 때 문제가 발생한다.
셋째, API 토큰 관리의 어려움이 있다. Apps Script에서 서비스 계정 또는 OAuth 클라이언트를 사용하여 외부 API에 접근할 때, 토큰을 안전하게 관리해야 한다. 토큰이 클라이언트 측 코드에 노출되면 공격자가 이를 탈취하여 무단 액세스를 시도할 수 있다.
토큰 기반 인증 아키텍처
토큰 기반 인증은 클라이언트가 자격 증명(사용자 이름, 비밀번호)을 서버에 제출하면, 서버가 암호화된 토큰을 발급하는 방식이다. 클라이언트는 이 토큰을 저장하고, 이후 모든 요청에 토큰을 포함하여 보낸다. 서버는 토큰을 검증하여 사용자의 신원을 확인한다.
Apps Script Web Apps에서 토큰 기반 인증을 구현할 때 고려해야 할 핵심 요소는 다음과 같다.
첫째, 토큰 발급 메커니즘이다. 사용자 인증이 성공하면 서버가 토큰을 생성하여 클라이언트에 반환한다. 이 토큰은 사용자의 신원을 나타내는 정보(사용자 ID, 권한 등)을 포함하며, 암호화되어야 한다. Apps Script에서는 Utilities.computeDigest() 함수를 사용하여 토큰을 서명하거나, ScriptProperties를 사용하여 토큰을 관리할 수 있다.
둘째, 토큰 저장 메커니즘이다. 클라이언트는 토큰을 안전하게 저장해야 한다. 브라우저 환경에서는 localStorage, sessionStorage, 또는 HTTP-only 쿠키를 사용할 수 있다. 각 방식은 장단점이 있으며, 보안 요구사항에 따라 선택해야 한다.
셋째, 토큰 검증 메커니즘이다. 서버는 수신한 토큰의 유효성을 검증해야 한다. 이는 토큰의 서명을 확인하거나, 토큰이 스토리지에 존재하는지 확인하여 수행할 수 있다. Apps Script에서는 토큰 검증 로직을 doGet() 또는 doPost() 함수 내부에 구현해야 한다.
보안 설계 고려사항
Apps Script Web Apps에서 토큰 기반 인증을 구현할 때 다음과 같은 보안 설계 고려사항을 고려해야 한다.
첫째, 토큰 무효화 전략이다. 토큰은 무효화할 수 있어야 한다. 예를 들어, 사용자가 로그아웃하거나 비밀번호를 변경하면 기존 토큰을 무효화해야 한다. Apps Script에서는 ScriptProperties를 사용하여 토큰 목록을 관리하고, 토큰 무효화 시 이를 제거하여 구현할 수 있다.
둘째, 토큰 만료 정책이다. 토큰은 수명이 제한되어 있어야 한다. 긴 수명을 가진 토큰은 탈취 시 위험이 증가한다. 액세스 토큰과 리프레시 토큰을 분리하여 사용하고, 액세스 토큰의 수명을 짧게 설정하여 위험을 완화할 수 있다.
셋째, HTTPS 강제 사용이다. 토큰은 항상 HTTPS를 통해 전송되어야 한다. HTTP를 사용하면 중간자 공격(Man-in-the-Middle)으로 인해 토큰이 탈취될 수 있다. Apps Script Web Apps는 기본적으로 HTTPS를 사용하므로 이 요구사항은 기본적으로 충족된다.
넷째, 토큰 크기 제한 고려이다. Apps Script Web Apps는 URL 파라미터 길이에 제한이 있다. 토큰이 너무 길면 URL 파라미터로 전송할 수 없으며, POST 요청 본문 또는 HTTP 헤더를 사용해야 한다.
구현 예시
Apps Script Web Apps에서 토큰 기반 인증을 구현하는 방법을 간단히 설명한다. 이 예시는 ScriptProperties를 사용하여 토큰을 관리하고, POST 요청 본문을 통해 토큰을 전송한다.
서버 측 코드(Apps Script)에서는 먼저 토큰을 생성하고 저장하는 함수를 구현한다.
function createToken(userId) {
var token = Utilities.getUuid();
var timestamp = new Date().getTime();
var tokenData = userId + "|" + timestamp;
var signature = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, tokenData + "SECRET_KEY");
var signedToken = token + "." + signature;
// ScriptProperties에 토큰 저장
var properties = PropertiesService.getScriptProperties();
var activeTokens = properties.getProperty("activeTokens") || "{}";
var tokens = JSON.parse(activeTokens);
tokens[signedToken] = {
userId: userId,
createdAt: timestamp,
expiresAt: timestamp + (60 * 60 * 1000) // 1시간 후 만료
};
properties.setProperty("activeTokens", JSON.stringify(tokens));
return signedToken;
}
function validateToken(token) {
var properties = PropertiesService.getScriptProperties();
var activeTokens = properties.getProperty("activeTokens") || "{}";
var tokens = JSON.parse(activeTokens);
if (tokens[token]) {
var tokenInfo = tokens[token];
var now = new Date().getTime();
// 토큰 만료 확인
if (tokenInfo.expiresAt < now) {
delete tokens[token];
properties.setProperty("activeTokens", JSON.stringify(tokens));
return null;
}
return tokenInfo.userId;
}
return null;
}
클라이언트 측 코드에서는 토큰을 저장하고 모든 요청에 포함한다.
// 로그인 요청
async function login(username, password) {
const response = await fetch("https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec", {
method: "POST",
body: JSON.stringify({
action: "login",
username: username,
password: password
})
});
const data = await response.json();
if (data.success) {
localStorage.setItem("authToken", data.token);
}
return data;
}
// 인증이 필요한 요청
async function makeAuthenticatedRequest(endpoint, data) {
const token = localStorage.getItem("authToken");
const response = await fetch("https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec", {
method: "POST",
body: JSON.stringify({
action: endpoint,
token: token,
data: data
})
});
return response.json();
}
보안 위험 완화
토큰 기반 인증을 구현할 때 발생할 수 있는 보안 위험을 완화하기 위한 방법을 고려해야 한다.
첫째, 토큰 탈취 방지이다. 토큰은 HTTPS를 통해 전송되어야 하며, 클라이언트 측 저장소에 안전하게 저장되어야 한다. localStorage 대신 HTTP-only 쿠키를 사용하면 XSS(Cross-Site Scripting) 공격으로부터 토큰을 보호할 수 있다. 하지만 Apps Script Web Apps에서는 CORS 제약으로 인해 HTTP-only 쿠키 사용이 제한적일 수 있다.
둘째, 리플레이 공격 방지이다. 공격자가 탈취한 토큰을 사용하여 이전 요청을 재시도하는 것을 방지해야 한다. 토큰에 타임스탬프를 포함하고, 서버에서 요청의 유효 시간을 확인하여 구현할 수 있다.
셋째, CSRF(Cross-Site Request Forgery) 방지이다. 토큰을 URL 파라미터로 전송하면 CSRF 공격에 취약해진다. 반드시 POST 요청 본문 또는 HTTP 헤더를 사용하여 토큰을 전송해야 한다.
넷째, 토큰 저장소 보안이다. ScriptProperties는 Apps Script 프로젝트 소유자만 접근할 수 있지만, 민감한 정보(비밀 키, 사용자 비밀번호)를 저장하는 데는 적합하지 않다. 가능한 경우, Secrets Management 서비스를 사용하거나, 민감한 정보를 암호화하여 저장해야 한다.
결론
Google Apps Script Web Apps에서 보안 토큰 기반 인증을 구현하는 것은 무상태 아키텍처의 제약을 극복하고 안전한 웹 애플리케이션을 구축하는 데 필수적이다. 하지만 올바르게 구현하지 않으면 심각한 보안 취약점이 발생할 수 있다.
기본적인 인증 메커니즘의 제한, 세션 관리의 어려움, API 토큰 관리의 복잡성 등 다양한 도전이 존재하지만, 토큰 기반 인증 아키텍처를 적절히 설계하고 구현하면 이러한 제약을 극복할 수 있다. 특히, 토큰 무효화 전략, 만료 정책, HTTPS 강제 사용, 토큰 크기 제한 고려 등 보안 설계 원칙을 준수해야 한다.
실무 환경에서는 Google Workspace Admin SDK 또는 Firebase Authentication과 같은 관리형 인증 서비스를 통합하는 것을 고려해야 한다. 이러한 서비스는 복잡한 보안 요구사항을 처리하는 데 도움이 되며, 개발 리소스를 절약할 수 있다. 하지만 관리형 서비스를 사용할 수 없는 경우, 위에서 설명한 원칙에 따라 직접 토큰 기반 인증을 구현해야 한다.
Apps Script Web Apps는 보안이 중요한 애플리케이션을 구축하는 데 사용될 수 있지만, 개발자는 플랫폼의 제약을 이해하고 적절한 보안 조치를 취해야 한다. 보안은 구현의 복잡성을 증가시키지만, 데이터 보호 및 사용자 신뢰를 위해 필수적인 요소이다.
참고문헌
-
Google Apps Script Web Apps
https://developers.google.com/apps-script/guides/web -
Google Apps Script Security Best Practices
https://developers.google.com/apps-script/guides/security -
OAuth 2.0 for Mobile & Desktop Apps
https://developers.google.com/identity/protocols/oauth2 -
OWASP Token Storage Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Token_Storage_Cheat_Sheet.html
본 콘텐츠는 AI 기술로 작성된 분석 리포트를 포함하고 있습니다. 내용 중 사실과 다르거나 보완이 필요한 정보를 발견하시면 댓글을 통해 소중한 의견 부탁드립니다. 여러분의 피드백은 더 정확한 보안 정보 공유에 큰 도움이 됩니다.
댓글 (0)
댓글을 작성하려면 로그인이 필요합니다.
로그인아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!