MakeAI 딥러닝

공개 데모를 안전하게 운영하기 — Basic auth, 다중 계정, 상수 시간 비교

도면 분석 콘솔을 누구나 써 볼 수 있게 열면서도 아무나 들어오진 못하게 해야 했어요. 사용자 모델 없는 앱에 HTTP Basic auth로 데모 계정을 붙이면서 지킨 것들이에요.

4분 읽기

지난주에 이어 가벼운 운영 글이에요. 저희 도면 분석 콘솔은 원래 사내용이라 로그인 기능이 없어요. 그런데 사이트에서 "라이브 데모"로 연결하려면 외부에 열어야 하고, 열면 아무나 도면을 올리고 지울 수 있어요. 사용자 모델을 새로 만들기엔 과하고, 그렇다고 그냥 열 수는 없고. HTTP Basic auth로 갔어요.

왜 Basic auth냐면요

  • 앱 코드를 거의 안 건드려요. 미들웨어 한 파일이에요.
  • 브라우저가 로그인 창을 띄워 줘요. UI를 만들 필요가 없어요.
  • HTTPS 위에서는 자격 증명이 암호화돼요. HTTPS 없이는 절대 안 돼요.
  • 한계도 분명해요. 사용자별 권한이 없고, 로그아웃이 애매하고, "비밀번호를 아는 사람 = 같은 권한"이에요. 데모 용도로는 받아들일 만했어요.

미들웨어 구조

Next.js 미들웨어에서 Authorization 헤더를 확인하고, 없거나 틀리면 401과 WWW-Authenticate를 돌려줘요. 핵심 결정 몇 가지예요.

1. 설정이 없으면 열려 있어요. 환경 변수에 계정이 하나도 없으면 인증을 안 해요. 로컬 개발과 사내망 배포에서는 비밀번호 없이 쓰려고요. 공개 배포에서만 환경 변수를 넣어요. 단, 이 "기본 열림"은 실수하면 위험하니까 배포 스크립트의 헬스체크가 인증 없이 401이 오는지 확인해요. 200이 오면 배포 실패예요.

2. 계정은 여러 개예요. 관리자 계정과 데모 계정을 분리했어요. 환경 변수 하나에 user:pass,user2:pass2 형식으로 넣고 파싱해요. 데모 비밀번호가 새면 데모 계정만 바꾸면 돼요.

3. 비밀번호는 저장소에 없어요. 서버의 root만 읽을 수 있는 env 파일에 있고, systemd가 서비스에 넘겨요. 코드, 설정 파일, 로그 어디에도 없어요.

상수 시간 비교

비밀번호를 === 로 비교하면 첫 글자가 틀렸을 때와 마지막 글자가 틀렸을 때 응답 시간이 아주 조금 달라요. 이론적으로는 그 차이로 한 글자씩 맞춰 갈 수 있어요. 그래서 길이가 같으면 끝까지 XOR로 비교하는 상수 시간 비교를 써요.

function safeEqual(a, b) {
  if (a.length !== b.length) return false;
  let diff = 0;
  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
  return diff === 0;
}

계정이 여러 개일 때도 마찬가지예요. 첫 계정이 맞으면 바로 return 하지 않고, 모든 계정을 다 비교한 뒤 결과를 내요. 안 그러면 응답 시간으로 "이 아이디는 존재한다"를 알 수 있어요. 실제 위협이 될 만한 상황은 아니지만, 몇 줄이면 되는 걸 안 할 이유가 없어요.

매처(matcher) 함정

미들웨어가 어느 경로에 적용되는지 정하는 매처에서 한 번 당했어요. 정적 자산을 제외하는 흔한 패턴 /((?!_next/static|...).*) 을 썼는데, 이 패턴이 루트 경로 / 에는 안 걸렸어요. API 경로는 401인데 페이지 자체는 인증 없이 열리는 상태였어요. / 를 매처에 따로 추가해서 고쳤고, 위에서 말한 "인증 없이 401인지" 헬스체크를 루트 경로로 하게 바꿨어요. 이런 건 코드 리뷰로는 못 잡아요. 실제로 curl로 쳐 봐야 해요.

데모 계정 안내 페이지

데모 계정은 사이트의 데모 안내 페이지에 그대로 적혀 있어요. 공개 정보예요. 다만 검색엔진에 색인되는 건 원치 않아서 그 페이지는 noindex 와 robots.txt 차단을 걸었어요. "비밀"은 아니지만 "검색하면 나오는" 것도 아니게요. 완벽한 보호가 아니라 노출 범위 조절이에요.

데모 계정의 한계와 운영

Basic auth라 데모 계정도 관리자와 같은 권한이에요. 도면을 올리고 지울 수 있어요. 지금은 이렇게 운영해요.

  • 데모 데이터는 주기적으로 초기화할 수 있게 해 뒀어요.
  • 데모 계정으로 쓰기 요청(POST/DELETE)을 막는 건 미들웨어에 몇 줄이면 돼서, 필요해지면 바로 넣을 수 있어요.
  • 비밀번호를 바꾸면 서버 env와 사이트 안내 페이지 두 군데를 맞춰야 해요. 이건 사람이 기억해야 하는 일이라 README에 적어 뒀어요.

정리

  • 사용자 모델 없는 앱을 잠깐 열 때 Basic auth는 괜찮은 선택이에요. HTTPS가 전제예요.
  • 설정 없으면 열림 + 배포 헬스체크로 "닫혀 있는지" 확인.
  • 계정을 분리하고, 비밀번호는 저장소 밖에.
  • 비교는 상수 시간으로, 계정 전부를 비교한 뒤 판정.
  • 매처는 curl로 직접 확인하세요. 루트가 빠질 수 있어요.

다음 주부터는 다시 본업으로 돌아가요. 4분기에는 도면 세트 간 참조 관계(조립도 ↔ 단품도)를 자동으로 연결하는 작업을 하고 있는데, 그 진행 상황을 쓸게요. 읽어 주셔서 고마워요!