이번엔 말하는 법이 아니라 막는 법
지금까지 만든 툴은 전부 "AI에게 정확히 말하기"였다. 화면은 UI 용어 75, 에러는 에러 디버깅 프롬프트 변환기, 저장·로그인·배포는 백엔드·배포 용어 60.
이번 건 결이 조금 다르다. 나는 PHP로 작업하고, 라우터 방식을 고집한다. 모든 요청을 index.php 하나로 받고, 거기서 주소를 보고 할 일을 나눈다. AI에게 기능을 시키면 기능은 잘 만들어 준다. 그런데 "이 파일을 주소로 직접 열 수 있나?", "업로드 폴더에서 PHP가 실행되나?" 같은 건 내가 먼저 말하지 않으면 빠지기 쉽다.
그래서 이 방식으로 사이트를 만들 때 챙기는 것들을 한 화면에 정리했다.
문이 하나면, 검사도 한 곳에서
라우터 방식의 보안은 한 문장으로 요약된다. 밖에서 들어오는 문은 index.php 하나뿐이고, 나머지 PHP 파일은 주소로 직접 열리지 않아야 한다.
문이 하나면 로그인 검사, 권한 검사, CSRF 검사를 그 문 뒤에 한 번만 세우면 된다. 반대로 /app/admin/delete.php처럼 내부 파일이 주소로 열리면, 라우터에 아무리 꼼꼼하게 검사를 넣어 놔도 그 파일은 검사를 건너뛴다. 직접 URL 접속 차단이 중요한 이유가 이거다.
그래서 정리한 것: PHP 라우터 사이트 보안 팁
PHP 라우터 사이트 보안 팁 — mifplus.com/tools/php-router-security
원칙 하나, 팁 7가지, 배포 전 체크 15개로 묶었다. 설정과 코드는 전부 복사 버튼이 붙어 있어서 그대로 가져다 쓸 수 있다.
요청을 직접 보내 보는 흐름도
툴 맨 앞에는 이 흐름도를 넣었다. 글로 "웹서버에서 막고, 라우터에서 막고, 미들웨어에서 막는다"고 쓰면 금방 잊는다. 그래서 요청을 골라 보내면 어디서 멈추는지 눈으로 보게 했다.
| 보내 본 요청 | 어디서 | 결과 |
|---|---|---|
GET /assets/site.css | 웹서버 | 200, PHP 실행 없이 파일 그대로 |
GET /.env | 웹서버 | 404 |
GET /app/admin/delete.php | 웹서버 | 404 |
GET /uploads/shell.php | 웹서버 | 404 |
GET /backup-2024 | 라우터 | 404 (허용 목록에 없음) |
GET /admin/post/5/delete (관리자) | 라우터 | 405 (POST만 허용) |
GET /admin/dashboard (로그아웃) | 미들웨어 | 404 |
POST /admin/post/5/delete (토큰 없음) | 미들웨어 | 419 (CSRF 토큰 불일치) |
POST /admin/post/5/delete (관리자·토큰) | 통과 | 200 |
막은 주소에 403이 아니라 404를 돌려주는 것도 일부러다. 403은 "거기 뭔가 있다"는 대답이라서, 없는 주소와 똑같이 보이게 하는 편이 낫다.
7가지 팁
- 웹 루트는 public 폴더만 — 설정보다 위치가 확실하다.
app/,config/,.env가 웹 루트 밖에 있으면 주소 자체가 없다. - 직접 URL 접속 차단 — 숨김 파일, 백업 확장자, 폴더 목록, 업로드 폴더의 PHP 실행을 웹서버에서 막는다. 내 웹서버에서 Apache와 Nginx를 고르면 그 설정만 보여 준다.
- 라우터 코드 — 허용 목록으로만 라우팅하고, 주소로 파일을 고르는
include $_GET['page']같은 코드는 쓰지 않는다./admin은 라우트 묶음 단위로 한 번에 검사한다. - 입력은 의심하고, 출력은 감싸기 — SQL은 PDO 자리표시자, 출력은
htmlspecialchars, POST는 CSRF 토큰, 업로드는 내용 검사와 새 이름. - 로그인과 세션 —
password_hash, 로그인 직후session_regenerate_id(true), 쿠키 옵션, 시도 횟수 제한. - 서버 설정과 보안 헤더 — 운영 서버는
display_errors = Off, 버전 정보 숨기기, 기본 보안 헤더. - 배포와 비밀 정보 — 서버에
.git,.bak,.sql,phpinfo.php를 남기지 않는다.
7번에는 주석 이야기도 넣었다. 배포할 때 주석을 지워야 하나 싶었는데, PHP 주석은 서버 밖으로 나가지 않으니 지울 필요가 없다. 대신 뷰 파일의 HTML 주석 <!-- -->은 그대로 브라우저로 간다. "TODO: 테스트 계정 test/1234" 같은 메모를 HTML 주석에 남기면 페이지 소스 보기로 누구나 본다.
배포 전 체크리스트
체크리스트는 대부분 주소창에 직접 넣어 보면 확인되는 것으로 골랐다. 진짜 도메인에서 하나씩 열어 보고 404가 나오면 통과다. 맨 위에 내 사이트 주소를 넣으면 항목마다 바로 열어 보는 링크가 생기고, 체크한 건 브라우저에 남아서 다음에 열어도 이어서 볼 수 있다.
AI에게 점검 맡기기
마지막에는 이 팁을 그대로 점검 기준으로 넘기는 요청문을 붙였다. "보안 점검해 줘"만 쓰면 일반론이 돌아오니까, 구조(PHP + 라우터, 웹서버 종류)와 점검 항목 10개를 같이 준다. 그리고 두 가지를 꼭 부탁한다.
- 고치기 전에 항목별로 통과 / 문제 / 확인 불가를 표로 먼저 보여 달라
- 문제는 한 번에 하나씩 고쳐 달라
보안 수정을 한꺼번에 맡기면 라우터나 로그인처럼 사이트 전체에 걸린 부분이 한 번에 바뀌어서, 뭐가 뭘 깨뜨렸는지 찾기 어렵다.
정리하며
앞의 세 툴이 "AI에게 정확히 말하기"였다면, 이번 건 "정확히 막기"다. 문을 하나만 열어 두고, 그 문 뒤에 검사를 세우고, 배포할 때마다 주소창으로 한 번씩 두드려 본다. 거창한 보안 도구보다 이 습관이 먼저라고 생각한다.
PHP로 라우터 방식 사이트를 만들고 있다면, 배포 버튼을 누르기 전에 체크리스트만이라도 한 번 훑어보면 좋겠다.
PHP 라우터 사이트 보안 팁: https://mifplus.com/tools/php-router-security
바이브 코딩 백엔드·배포 용어 60: https://mifplus.com/tools/backend-terms
에러 디버깅 프롬프트 변환기: https://mifplus.com/tools/debug-prompt
바이브 코딩 UI 필수 용어 75: https://mifplus.com/tools/vibe-ui
지난 글: "저장되게 해줘"로는 부족하다 — 바이브 코딩 백엔드·배포 용어 60개 정리



