블로그 글에 서버 정보가 들어갔을까, 발행 전 보안 검토 규칙을 만들었습니다
기술 글의 서버 IP, 계정, 키, 토큰, 내부 경로와 이미지 메타데이터 노출을 원문과 렌더링 결과에서 확인하는 실제 발행 전 검토 과정입니다.

최근 minml에 서버 작업 과정을 설명하는 글을 연달아 작성했습니다. SSH로 상태를 확인한 명령, 정적 사이트 파일 권한을 고친 방법과 월간 유지보수 결과까지 실제 경험을 넣으니 글은 구체적이 됐습니다. 그런데 발행 직전에 새로운 질문이 생겼습니다.
“이 글에 공개하면 안 되는 서버 정보가 들어가 있지는 않을까?”
기술 글은 경험을 증명하려고 실제 명령과 결과를 보여줄수록 유용해집니다. 동시에 터미널 출력을 그대로 붙이면 서버 IP, 호스트 이름, 계정, 내부 경로와 로그 속 개인정보까지 함께 공개될 수 있습니다. 명령 자체는 평범해도 결과가 민감할 수 있고, Markdown 원문에서는 보이지 않던 값이 빌드된 HTML이나 이미지 메타데이터에 남을 수도 있습니다.
그래서 최근 글을 커밋하고 배포하기 전에 별도의 보안·개인정보 검토 단계를 만들었습니다. 초안을 자동으로 한 번 검색하는 데서 끝내지 않고, 원문과 렌더링 결과를 검사하고 사람이 문맥을 판단한 뒤 이미지를 확인하도록 순서를 정했습니다. 이번 글은 실제 비밀정보가 유출된 사고 기록이 아닙니다. 공개 전에 불필요한 운영 정보를 발견해 제거하고, 같은 실수를 반복하지 않도록 규칙을 만든 과정입니다.
명령어와 실제 출력은 따로 봐야 했습니다
예를 들어 서버에 접속해 호스트 이름과 웹 서버 상태를 확인하는 구조는 다음처럼 설명할 수 있습니다.
ssh example-server "hostname; systemctl is-active example-service"
example-server와 example-service는 설명용 값이므로 이 명령만으로 실제 서버에 접근할 수 없습니다. 하지만 운영 환경에서 실행한 결과를 그대로 붙이면 비공개 호스트 이름과 서비스 구성이 나타날 수 있습니다. 터미널 프롬프트까지 복사했다면 계정명과 현재 디렉터리가 함께 보일 수도 있습니다.
그래서 저는 명령과 출력을 다음처럼 구분합니다.
| 구분 | 발행할 때 처리 |
|---|---|
| 일반적인 명령 구조 | 독자가 이해할 수 있도록 유지 |
| 실제 접속 대상 | example-server 같은 값으로 교체 |
| 실제 계정·호스트 이름 | 제거하거나 역할만 설명 |
| 내부 절대 경로 | 공개용 예시 경로로 변경 |
| 상태 결과 | active, 200처럼 설명에 필요한 값만 유지 |
| 원문 로그 | 그대로 붙이지 않고 필요한 행만 다시 작성 |
AI에게 SSH 서버 작업을 맡길 때 확인하는 7가지에서도 실제 접속 정보와 서비스 이름을 플레이스홀더로 바꿨습니다. 당시에는 명령을 안전하게 실행하는 데 초점을 맞췄다면, 이번에는 그 작업 기록을 외부에 공개해도 되는지 확인하는 과정에 집중했습니다.
발행 전 찾는 정보를 네 종류로 나눴습니다
모든 서버 관련 숫자를 무조건 지우면 실제 경험이 사라지고 글이 다시 일반론이 됩니다. 반대로 “비밀번호만 아니면 괜찮다”고 생각하면 불필요한 접근 정보와 개인정보가 남을 수 있습니다. 그래서 발견한 값을 네 종류로 나눠 처리합니다.
1. 발견 즉시 제거하고 교체해야 하는 비밀
- 비밀번호와 데이터베이스 자격 증명
- API 키와 액세스 토큰
- SSH 개인키와 실제 접근에 사용되는 키 정보
- 쿠키와 세션 식별자
- 인증서 개인키와 복구 코드
이 값은 일부를 가리는 것만으로 충분하지 않을 수 있습니다. 이미 공개 저장소나 웹페이지에 올라갔다면 원문에서 지우기 전에 해당 자격 증명을 폐기하거나 교체해야 합니다.
2. 공개 승인을 받지 않은 개인정보
- 개인 이메일과 전화번호
- 실명, 주소와 계정 식별자
- 로그에 포함된 방문자 IP와 요청값
- 브라우저 화면에 보이는 로그인 계정
- QR 코드와 복구 정보
작성자 이름이나 사이트의 공개 문의 주소처럼 이미 의도적으로 공개한 정보는 글에 필요할 때 유지할 수 있습니다. 다만 터미널 로그에 우연히 들어간 주소와 연락처까지 공개 정보로 보지는 않습니다.
3. 설명에 필요하지 않은 운영 정보
- 실제 서버 IP와 비공개 호스트 이름
- SSH 별칭, 사용자 이름과 키 파일 위치
- 로컬 홈 디렉터리와 서버 내부 절대 경로
- 정확한 방화벽 구성과 불필요한 포트 정보
- 계정 구조와 서비스 간 내부 연결
- 설명에 필요하지 않은 세부 패치 버전
이 정보가 모두 비밀키처럼 즉시 악용되는 것은 아닙니다. 하지만 독자가 글의 핵심을 이해하는 데 필요하지 않다면 최소한으로 줄이는 편이 낫다고 판단했습니다.
4. 근거로 유지할 수 있는 공개·집계 정보
- 의도적으로 공개한 사이트 도메인
200,301,404같은 HTTP 상태- 문제 전후의 파일 개수처럼 개인을 식별하지 않는 집계값
- 일반적인 서비스와 명령 이름
- 실제 판단에 필요하지만 접근 수단이 되지 않는 비율
예를 들어 개인 사이트 유지보수 체크리스트의 디스크 사용 비율과 보관 릴리스 개수는 유지했습니다. 이 값은 특정 계정이나 경로를 알려주지 않으면서 “왜 지금 삭제하지 않고 관찰 대상으로 남겼는가”를 설명하는 근거였기 때문입니다.
이번 초안에서 실제로 바꾼 내용
새 검토 규칙을 처음 적용한 대상은 유지보수 체크리스트 글이었습니다. 자동 검색에서는 키, 토큰, 실제 IP와 계정 정보가 발견되지 않았습니다. 그래도 수동으로 다시 읽으면서 정확한 커널 패치 버전이 적혀 있는 문장을 찾았습니다.
커널 버전은 비밀번호가 아니고 서버에 접속할 방법도 아닙니다. 하지만 그 글에서 독자에게 필요한 결론은 “업데이트 뒤 재부팅이 필요한가”였습니다. 정확한 패치 문자열이 없어도 판단 과정은 설명할 수 있었기 때문에, 버전을 삭제하고 재부팅 필요 표시가 없었다는 결과만 남겼습니다.
명령 예시의 인증서 경로는 실제 도메인 대신 example.com을 사용했습니다. 새 글과 이미지 주소도 실제 초안에서는 역할을 알 수 있는 플레이스홀더로 표시했습니다. 반면 공개 사이트의 HTTP 상태, 디스크 비율과 인증서 잔여일처럼 판단 근거가 되는 집계 결과는 유지했습니다.
이 과정에서 제거한 것은 경험이 아니라 독자에게 필요하지 않은 식별 가능성이었습니다.
Markdown 원문만 검사하지 않았습니다
Astro 글은 Markdown으로 작성하지만 방문자가 받는 것은 빌드된 HTML입니다. 테마의 공통 스크립트, 메타 태그와 이미지 경로가 합쳐진 최종 결과는 원문과 다릅니다. 그래서 다음 두 파일을 각각 검사했습니다.
- 작성한 Markdown 원문
- Astro가 생성한 해당 글의
index.html
자동 패턴 검사에서는 키 헤더, 알려진 토큰 형식, IP 주소, 이메일, 사용자 홈 경로와 실제 서버 경로 같은 항목을 찾도록 했습니다. 처음 렌더링 HTML을 검사했을 때는 HostName이라는 문자열이 잡혔습니다. 문맥을 열어보니 실제 호스트 이름이 아니라 페이지 공통 JavaScript의 location.hostname이었습니다.
이 결과는 두 가지를 보여줬습니다.
- 자동 검사는 사람이 놓치기 쉬운 문자열을 빠르게 찾는 데 유용함
- 일치 결과가 실제 유출인지 문맥을 열어 판단해야 함
GitHub 공식 문서도 Secret Scanning이 지원하는 비밀 형식과 탐지 조건에 따라 작동한다고 설명합니다. 일부 자격 증명은 ID와 비밀값이 같은 파일에 함께 있어야 탐지되고, 지원하지 않는 형식은 잡히지 않을 수 있습니다. 따라서 스캐너가 조용하다는 사실만으로 공개해도 안전하다고 단정하지 않았습니다.
이미지도 파일과 화면을 나눠 확인했습니다
대표 이미지는 코드가 아니지만 화면과 메타데이터에 정보가 남을 수 있습니다. 특히 터미널이나 관리자 화면을 캡처한 이미지라면 다음 항목을 확인해야 합니다.
- 터미널 프롬프트의 계정과 호스트 이름
- 브라우저의 로그인 계정과 프로필 이미지
- 주소창, 탭 제목과 즐겨찾기
- 로그에 표시된 IP와 요청 주소
- 토큰, QR 코드와 복구 코드
- EXIF를 비롯한 파일 메타데이터
이번 대표 이미지는 실제 화면을 캡처하지 않고 문서·검사 프레임·돋보기만 있는 3D 이미지로 만들었습니다. 이미지 안에는 글자, 숫자, 코드와 주소가 없고 저장한 WebP의 EXIF 항목도 비어 있는지 확인했습니다. 대체 텍스트에도 실제 서버나 도구 이름 대신 이미지에서 보이는 세 오브젝트만 설명합니다.
AI 블로그 대표 이미지 스타일 가이드에 글자와 로고를 넣지 않는 규칙이 이미 있었지만, 이번에는 시각적 일관성뿐 아니라 공개하면 안 되는 화면 정보가 없는지도 별도 항목으로 추가했습니다.
반복할 검토 과정을 프로젝트 규칙으로 넣었습니다
한 번 꼼꼼히 확인해도 다음 글에서 잊으면 같은 문제가 반복됩니다. 그래서 프로젝트의 AGENTS.md에 게시 전 개인정보·보안 검토를 필수 절차로 추가했습니다. 핵심 규칙은 다음과 같습니다.
- 글을 다 쓴 뒤 검사하고, 이후 내용을 고쳤다면 다시 검사합니다.
- 본문뿐 아니라 frontmatter, 표, 링크, 코드와 명령 출력을 확인합니다.
- 이미지, 캡션, 대체 텍스트와 메타데이터도 검사합니다.
- 자동 패턴 검색 뒤 사람이 문맥을 직접 읽습니다.
- 민감하거나 불필요한 값은 제거하거나 플레이스홀더로 바꿉니다.
- 수정했다면 같은 검사를 다시 실행합니다.
- 검토가 끝나기 전에는 커밋하거나 배포하지 않습니다.
- 최종 작업 결과에 무엇을 제거·일반화했는지 기록합니다.
규칙 파일이 있다고 자동으로 안전한 글이 만들어지는 것은 아닙니다. 자동 검사는 “이 문자열을 확인해보라”고 알려주지만 공개할 가치와 위험을 대신 판단하지는 못합니다. 정확한 커널 버전을 남길지, 집계된 디스크 비율을 유지할지는 글의 목적과 공개 범위를 사람이 결정해야 합니다.
이미 공개된 뒤 비밀을 발견하면 먼저 폐기합니다
커밋 전에 발견했다면 원문을 고치고 다시 검사하면 됩니다. 하지만 실제 키나 토큰이 이미 저장소나 웹페이지에 공개됐다면 글에서 문자열을 지우는 것만으로 끝나지 않습니다. 복사본, Git 기록과 캐시에 값이 남아 있을 수 있기 때문입니다.
GitHub의 민감정보 제거 안내는 비밀번호·토큰·자격 증명이 노출됐다면 먼저 폐기하거나 교체하라고 권합니다. 그다음 필요하다면 저장소 기록 제거를 검토합니다. Git 기록을 다시 쓰는 작업은 커밋 해시와 협업자의 복제본에도 영향을 주므로, 단순히 명령 하나를 복사해 실행할 작업으로 다루지 않습니다.
제가 정한 순서는 다음과 같습니다.
- 노출된 키·토큰·비밀번호를 즉시 폐기하거나 교체
- 공개 페이지와 현재 소스에서 해당 값 제거
- 배포본, 캐시와 검색 노출 범위 확인
- Git 기록과 다른 복제본에 남았는지 조사
- 영향 범위를 확인한 뒤 기록 정리 방법 결정
- 같은 유형을 발행 전 검사 규칙에 추가
OWASP의 비밀정보 관리 안내도 로그에 비밀값이 들어갔을 때 로그의 무결성을 유지하면서 해당 값을 제거할 절차가 필요하다고 설명합니다. 그래서 실제 로그 전체를 글에 붙이지 않고, 필요한 결과만 개인·접근 정보를 제외한 문장이나 표로 다시 작성합니다.
제가 사용하는 발행 전 최종 체크리스트
원문과 코드
- IP, 비공개 호스트명과 SSH 별칭이 없는가
- 계정명, 홈 디렉터리와 내부 절대 경로가 없는가
- 키, 토큰, 비밀번호, 쿠키와 환경 변수가 없는가
- 명령뿐 아니라 붙여 넣은 출력도 확인했는가
- 이메일, 전화번호와 로그 속 개인정보가 없는가
- 불필요한 포트·방화벽·버전 정보가 없는가
- 공개값과 예시값을 독자가 구분할 수 있는가
빌드 결과와 이미지
- 렌더링된 HTML도 같은 패턴으로 검사했는가
- 탐지 결과를 문맥에서 직접 확인했는가
- 이미지에 계정·주소·코드·QR 정보가 보이지 않는가
- EXIF 등 이미지 메타데이터를 확인했는가
- 캡션과 대체 텍스트에 내부 정보가 없는가
커밋과 배포 전
- 수정 뒤 보안 검사를 다시 실행했는가
- 스테이징할 파일과 최종 diff를 확인했는가
- 새 글과 이미지 외의 파일이 섞이지 않았는가
- 최종 보고에 제거하거나 일반화한 내용을 남겼는가
유용한 경험과 안전한 공개 범위는 함께 만들 수 있습니다
서버 IP와 로그를 그대로 보여주지 않아도 기술 글은 구체적일 수 있습니다. 어떤 명령을 왜 실행했고, 무엇을 기준으로 정상과 문제를 나눴으며, 수정 전후에 어떤 결과를 확인했는지는 실제 접근 정보를 제거한 뒤에도 설명할 수 있습니다.
이번 검토에서는 실제 비밀정보가 발견되지는 않았습니다. 대신 설명에 필요하지 않은 정확한 커널 버전을 제거했고, 예시 경로를 일반화했으며, 자동 검색의 오탐을 사람이 확인하고 이미지 메타데이터까지 검사했습니다. 그리고 이 과정을 다음 글에서도 반복하도록 프로젝트 규칙으로 남겼습니다.
저에게 발행 전 보안 검토는 기술적인 내용을 감추는 과정이 아닙니다. 독자가 배울 수 있는 판단과 결과는 남기고, 서버에 접근하거나 개인을 식별하는 데만 도움이 되는 값은 빼는 과정에 가깝습니다. 글의 구체성과 안전성을 둘 중 하나만 선택할 필요는 없었습니다.