소개
상점 청구서는 고객의 구매 항목, 가격, 청구 주소를 기록합니다. 고객은 자신의 청구서 또는 명시적으로 공유받은 청구서만 읽을 수 있어야 합니다. 청구서 ID를 안다고 읽기 권한이 생기지는 않습니다.
고객 Alex로 합성 Invoice Desk를 테스트할 권한이 있습니다. 정상 접근부터 시작해 공유 청구서와 비공개 청구서를 비교하고 비공개 응답을 저장하여 소유권 경계의 결함을 입증합니다. 실습은 검증으로 끝나며 서버는 수정하지 않습니다. 제공된 연습 객체만 범위에 포함됩니다.
정상 접근 확인하기
이 단계에서는 Alex로 로그인하고 다른 계정을 테스트하기 전에 자신의 청구서를 가져옵니다.
이 단계를 시작하려면 실습 인터페이스에서 Invoice Desk 탭을 선택합니다.
Invoice Desk 탭으로 전환합니다. 다이어그램의 클라이언트는 요청을 보내고 API 서버는 응답합니다. API는 애플리케이션의 요청 인터페이스입니다. API: ready는 실제 상태 확인 요청의 결과입니다. 표는 의도된 접근 규칙을 설명합니다.
| 청구서 ID | 소유자 | 공유 대상 | Alex가 읽어도 되는가? |
|---|---|---|---|
inv-104 |
alex |
없음 | 예: 소유자 |
inv-208 |
morgan |
없음 | 아니요: 비공개 |
inv-315 |
riley |
alex |
예: 명시적 공유 |
포털에 사용자 이름 alex와 비밀번호 shop-alex-42를 입력하고 Sign in을 선택합니다. Signed in as alex를 확인합니다. Invoice ID에 inv-104를 입력하고 View invoice를 선택합니다. owner는 alex여야 합니다.

Client Terminal 탭으로 전환합니다. /home/student/project의 격리된 고객 작업 공간이며 서버가 아닙니다. invoice-api:8000은 연습 네트워크 안의 서버 주소로 공개 대상이 아닙니다. curl은 터미널에서 HTTP 요청을 보냅니다. HTTP는 여기서 사용하는 요청/응답 프로토콜이며 GET은 리소스 읽기를 요청합니다. 주소 뒤 경로가 리소스를 지정합니다. -i는 응답 상태와 헤더를 포함합니다.
세션이 없으면 401 Unauthorized가 반환되어 로그인이 필요함을 나타냅니다.
다음 명령을 실행하기 전에 Client Terminal 탭으로 전환합니다.
curl -i http://invoice-api:8000/api/invoices/inv-104
브라우저 로그인은 curl에 로그인하지 않습니다. 세션은 로그인한 사용자의 서버 측 기록이며 무작위 cookie가 이후 요청을 이 기록과 연결합니다. 다음 명령은 이름 있는 필드로 이루어진 JSON 객체를 보냅니다. -H는 JSON을 설명하는 요청 헤더를 설정하고, -d는 자격 증명을 보내며 POST를 선택하고, -c는 반환된 cookie를 session.txt에 저장합니다. 작은따옴표는 공백과 큰따옴표를 하나의 셸 인수로 묶습니다.
curl -sS -c session.txt -H 'Content-Type: application/json' -d '{"username":"alex","password":"shop-alex-42"}' http://invoice-api:8000/api/login
-sS는 진행 표시를 숨기지만 연결 오류는 표시합니다. account는 alex여야 합니다. -b는 저장된 cookie를 전송합니다. 세션 신원을 확인합니다.
curl -sS -b session.txt http://invoice-api:8000/api/me
자신의 청구서를 요청합니다.
curl -sS -b session.txt http://invoice-api:8000/api/invoices/inv-104
invoice_id, owner, item, total_usd를 읽습니다. Alex는 Desk lamp를 38.00에 구매했습니다. 빈 shared_with 목록 []는 다른 사람에게 권한을 주지 않았다는 뜻입니다. 정상 동작입니다. 체크포인트는 터미널과 포털 어느 쪽에서 요청했든 서버가 Alex에게 보낸 실제 응답을 확인합니다.
로그인 후에도 401이면 이 터미널에서 로그인 명령을 다시 실행하고 -b session.txt로 재시도합니다. 연결 오류는 HTTP 응답이 오지 않았다는 다른 문제입니다. 주소와 API: ready를 확인하세요.
다른 청구서 요청하기
이 단계에서는 같은 로그인 신원을 유지하면서 명시적 공유와 비공개 청구서를 비교합니다.
이 단계를 시작하려면 실습 인터페이스에서 Client Terminal 탭을 선택합니다.
인증은 “누구인가?”에, 인가는 “이 사람이 이 청구서를 읽어도 되는가?”에 답합니다. 로그인 성공은 첫 질문만 해결합니다. 먼저 정상적으로 공유된 청구서를 다운로드합니다. 다운로드도 GET 요청입니다. /download는 같은 JSON 청구서 필드를 가진 저장용 응답을 선택합니다.
다음 명령을 실행하기 전에 Client Terminal 탭으로 전환합니다.
curl -sS -b session.txt http://invoice-api:8000/api/invoices/inv-315/download
소유자는 riley지만 shared_with에 alex가 포함되므로 접근이 허용됩니다. 소유자가 다르다는 사실만으로 결함을 입증할 수는 없습니다.
다음 비공개 경우를 예상해 보세요. inv-208은 Morgan 소유이며 아무에게도 공유되지 않아 Alex는 보통 403 Forbidden 같은 거부를 받아야 합니다. 서비스는 비공개 객체의 존재를 숨기기 위해 404 Not Found를 사용할 수도 있습니다. 여기서는 모르는 ID에도 404가 반환됩니다. 200 OK는 요청 성공을 뜻하며 본문이 노출 내용을 알려 줍니다.
-v는 실제 전송 요청과 받은 헤더를 표시합니다. 연습 세션 cookie도 표시하므로 출력을 실습 밖에서 공유하지 마세요. 실행합니다.
curl -v -b session.txt http://invoice-api:8000/api/invoices/inv-208
GET /api/invoices/inv-208과 HTTP/1.0 200 OK를 찾습니다. 본문에는 소유자 morgan, 빈 공유 목록, Studio microphone, 청구 주소 82 Cedar Lane이 있습니다. 서버가 Alex에게 비공개 객체를 제공했습니다. 바꾼 것은 객체 경로이며 세션 신원이 아닙니다. 예측 가능한 ID는 테스트를 편리하게 했고, 노출 원인은 권한 검사 누락입니다.
Invoice Desk 탭으로 전환하여 inv-315에 Download invoice, inv-208에 View invoice를 사용해 두 요청을 반복합니다. 브라우저 클라이언트는 다운로드 응답을 같은 고객 작업 공간에 저장합니다. 체크포인트는 허용된 공유 다운로드와 비공개 조회 결과를 요구하며 설명 파일을 요구하지 않습니다.

노출 검증하기
이 단계에서는 실제 비공개 다운로드를 보존하고 노출 데이터가 업무에 미치는 영향을 이해합니다.
이 단계를 시작하려면 실습 인터페이스에서 Client Terminal 탭을 선택합니다.
비공개 청구서에 /download를 사용합니다. -o는 응답 바이트를 출력하는 대신 파일에 씁니다. 현재 고객 작업 공간에 전체 응답을 private-invoice.json으로 저장합니다.
다음 명령을 실행하기 전에 Client Terminal 탭으로 전환합니다.
curl -sS -b session.txt -o private-invoice.json http://invoice-api:8000/api/invoices/inv-208/download
cat은 파일을 출력하여 읽을 수 있게 합니다.
cat private-invoice.json
같은 Morgan 청구서에 invoice_id inv-208, 소유자 morgan, 금액 129.00, 청구 주소가 있어야 합니다. 401 오류나 공유 청구서를 저장했다면 필요할 때 다시 로그인하고 지정 비공개 청구서를 다운로드합니다. -o는 파일을 덮어씁니다.
또는 Invoice Desk 탭으로 전환합니다. Alex로 로그인한 상태에서 inv-208을 입력하고 Download invoice를 선택합니다. 브라우저 클라이언트는 실제 API 요청을 전달하고 수정하지 않은 응답을 /home/student/project/private-invoice.json에 저장합니다. Client Terminal 탭으로 다시 전환하면 이 파일을 읽을 수 있습니다. 두 방법 모두 같은 결과를 충족합니다.
체크포인트를 실행합니다. 저장 바이트를 지정 청구서와 비교하고 서버가 Alex 세션으로 다운로드를 기록했는지 확인합니다. 복사한 주장, 조작한 청구서, 허용된 공유 청구서, 일치하는 고객 다운로드가 없는 파일은 결과를 입증하지 못합니다.
실제 영향은 다른 고객의 구매 내역과 청구 주소 노출입니다. 서버는 다운로드를 포함해 모든 객체 요청에서 현재 사용자의 소유권 또는 명시적 공유 권한을 검사해야 합니다. 링크를 숨기거나 ID 추측을 어렵게 해도 이 검사를 대신할 수 없습니다. OWASP BOLA가 설명하는 객체 수준 인가 문제입니다. 허가된 테스트는 끝났으며 서버 수정은 별도 작업으로 남깁니다.
요약
고객 세션을 만들고 자신의 청구서를 읽었으며 명시적 공유와 비공개 접근을 구분하고 실제 계정 간 응답을 저장했습니다. 서버 접근이나 피해자 자격 증명 없이 노출 데이터와 이를 받은 신원을 모두 검증했습니다.



