비공개 게시글에서 첨부파일 주소를 복사했다고 가정해 보겠습니다. 글을 읽을 수 있는 계정 A에서는 파일이 열립니다. 글을 읽을 수 없는 계정 B에서도 같은 주소로 파일이 내려온다면, 게시글에 적용한 권한이 다운로드까지 이어지는지 살펴야 합니다. 확인할 곳은 두 군데입니다. 웹서버가 파일을 직접 내주는 경로와 게시판 앱이 다운로드 요청을 처리하는 경로입니다.
공개 URL과 파일 저장 위치
웹 루트는 웹서버가 URL을 실제 파일에 연결하는 기준 디렉터리입니다. 예를 들어 /var/www/site/public 아래의 uploads가 정적 파일로 공개돼 있다면, 브라우저가 /uploads/report.pdf를 요청했을 때 게시판 앱을 거치지 않고 파일을 받을 수 있습니다. 게시글 화면에서 첨부 링크를 감춰도 이미 알려진 파일 주소는 그대로 작동할 수 있습니다.
첨부파일을 /srv/board/attachments처럼 웹 루트 밖으로 옮기고, 공개 URL이 이 디렉터리로 연결되지 않도록 정리합니다. 웹 루트 밖이라도 웹서버의 공개 별칭이나 심볼릭 링크가 그 위치를 가리키면 파일이 노출될 수 있습니다. 저장소를 옮길 때는 새 디렉터리뿐 아니라 예전 /uploads/ 주소에 남은 파일 사본도 확인합니다. OWASP — 파일 저장 위치

첨부 ID와 원본 글의 권한
다운로드 버튼에는 서버의 파일 경로 대신 /attachments/a7f3/download처럼 첨부 ID가 담긴 앱 주소를 넣습니다. 앱은 로그인 세션에서 요청자를 확인하고, 첨부 레코드에서 이 파일이 어느 게시글에 속하는지 찾습니다. 첨부파일이 원본 글의 열람 권한을 따르는 게시판이라면 앱은 그 글의 현재 열람 권한을 다운로드 요청마다 검사합니다. 첨부에 별도 제한을 두는 정책이라면 그 조건도 함께 적용합니다. OWASP — 요청마다 권한 검사
파일을 열 때는 권한 검사를 통과한 레코드의 내부 저장 키를 사용합니다. 이 키는 서버가 파일을 찾기 위해 관리하는 값입니다. 요청에서 받은 파일명이나 경로를 저장 디렉터리 뒤에 붙여 파일을 열면 사용자가 파일 선택에 직접 개입하게 됩니다. 외부에 노출되는 첨부 ID를 UUID처럼 추측하기 어렵게 만들더라도, 주소가 공유될 수 있으므로 파일마다 권한 검사는 필요합니다. OWASP — 객체별 접근 제어와 IDOR 검증
권한 승인 뒤 파일 전송
권한이 확인되면 앱이 파일을 열어 응답으로 전송할 수 있습니다. Nginx를 쓰는 구성에서는 앱이 허용된 요청에만 X-Accel-Redirect 응답 헤더를 내려 주고, Nginx가 internal로 지정한 URL 경로로 내부 리다이렉트해 파일을 보낼 수도 있습니다. 이 경로를 브라우저에서 직접 요청하면 Nginx가 404를 반환합니다. 앱이 권한 검사 뒤 내부 경로를 넘기고, Nginx는 해당 경로의 파일 전송을 맡습니다. NGINX — internal 지시어와 내부 리다이렉트
비공개 첨부 응답을 캐시에 저장하지 않도록 할 때는 최종 응답에 Cache-Control: no-store를 적용합니다. CDN이나 프록시를 앞에 둔 경우에는 다운로드 경로에 캐시 강제 규칙이 적용되는지도 확인합니다. 권한 검사까지 구현했더라도 앞단이 이전 응답을 재사용하면 그 요청은 앱에 도달하지 않을 수 있습니다. RFC 9111 §5.2.2.5 — 응답의 no-store
같은 첨부 주소로 권한 검증
테스트 게시판에 식별하기 쉬운 더미 파일을 올리고, 글을 볼 수 있는 계정 A와 볼 수 없는 계정 B를 준비합니다. A로 받은 다운로드 주소를 B의 별도 브라우저 세션과 비로그인 세션에서 각각 엽니다. 상태 코드와 함께 응답 본문이나 실제로 저장된 파일을 확인합니다. 로그인 화면으로 이동한 뒤 200이 표시되더라도 최종 응답이 로그인 페이지라면 첨부파일이 전달된 경우와 구분할 수 있습니다. OWASP — 객체별 접근 제어와 IDOR 검증
| 요청 조건 | 확인할 결과 |
|---|---|
| 계정 A로 앱의 다운로드 주소 요청 | 첨부한 더미 파일이 내려옴 |
| 계정 B 또는 비로그인 상태에서 같은 주소 요청 | 첨부 데이터가 내려오지 않음 |
| 계정 A의 열람 권한 회수 뒤 같은 주소 재요청 | 첨부 데이터가 내려오지 않음 |
| 예전 정적 주소와 Nginx 내부 주소를 브라우저에서 직접 요청 | 어느 주소에서도 첨부 데이터가 내려오지 않음 |
계정 A로 파일을 받은 직후 B의 세션에서 같은 URL을 다시 열어 보면, 권한이 다른 사용자에게 응답이 재사용되는지도 함께 점검할 수 있습니다.
결론
기존 게시판을 바꿀 때는 새 다운로드 주소에 원본 글의 열람 권한을 연결하고, 예전 정적 주소에 남아 있는 파일 제공 경로를 찾아 정리합니다. 마지막으로 권한이 없는 계정과 권한이 방금 회수된 계정에서 같은 주소를 열어 실제 첨부 데이터가 내려오는지 확인합니다.