🎯 미션 아래 버튼으로 화면을 띄운 뒤, Proxyman을 열어 방금 나간 요청을 찾아라. 요청의 응답 본문(JSON)까지 들여다볼 수 있는 상태로 만드는 것이 목표다.
💡 힌트
- HTTPS 트래픽은 암호화돼 있어 그냥은 본문이 안 보인다.
- Proxyman의 어떤 기능을 켜야 암호화가 풀려 보일까?
✅ 정답 · 해설
- SSL Proxying 활성화 + 루트 인증서 설치, 대상 도메인 허용
- 설정되면 요청이
HTTPS로 잡히고 본문이 복호화되어 보인다 - Response 탭에서
{ success, data }JSON 이 그대로 보이면 성공
🎯 미션 쿠폰 화면이 어딘가 깨져 있다. Proxyman으로 응답을 들여다보고 원인을 찾아라. 그리고 서버 코드는 못 고치는 상황에서, 화면이 정상으로 보이도록 만들어라.
- successboolean
- dataobject
- couponCodestring"12345678"8자리 · 앞자리 0 가능
- titlestring
- discountinteger
- minOrderPriceinteger
- expireAtstring<date>
💡 힌트
- 위 명세 와 Proxyman에 잡힌 실제 응답 을 나란히 비교해 보라.
- 특히 각 필드의 “타입” 에 주목 — 값에 따옴표가 있는가 없는가?
- 응답 값을 원하는 대로 바꿔 내려주려면 Map Local 을 쓴다.
✅ 정답 · 해설
- 증상: 카드는 뜨는데 쿠폰 코드 칸이 텅 비어 깨져 보인다
- 원인: 명세상
couponCode는string인데 서버가number로 응답 (따옴표 없음) - 클라가 코드를 한 글자씩(
code[0],code[1]…) 인덱싱하는데 숫자엔 안 먹어 전부 빈 칸 - 해결: Map Local로
"couponCode": "12345678"(문자열)로 바꿔 내려주면 정상 렌더
🎯 미션 이 주문 상태 화면은 응답에 따라 모습이 바뀐다. 그런데 서버는 한 가지 상태만 준다. 서버를 고치지 않고 나머지 모든 주문 상태의 화면을 직접 띄워 확인하라.
💡 힌트
- 응답 안에 주문 상태를 나타내는 값이 하나 있다. 그 값만 바꾸면 화면이 달라진다.
- Map Local 로 그 값을 바꿔 새로고침해 보라.
- 어떤 값들이 올 수 있는지는 명세를 확인.
✅ 정답 · 해설
data.status 를 Map Local로 아래 값들로 바꿔 각 UI 확인 (기본값 COOKING):
PENDING주문 접수 대기ACCEPTED주문 접수 완료COOKING조리 중 (기본 응답)DELIVERING배달 중 (라이더 정보 표시)DELIVERED배달 완료CANCELED주문 취소 (취소 사유 표시)
🎯 미션 상품 카드는 지금 멀쩡해 보인다. 하지만 어떤 데이터가 들어오면 이 UI가 깨질까? 카드가 깨지는 상황을 직접 만들어 이 화면의 약점을 찾아내라.
💡 힌트
- 디자이너가 준 “예쁜 데이터” 말고, 현실의 데이터를 떠올려 보라.
- 텍스트 길이 · 개수 · 특수문자 · 이상한 숫자…
- Map Local 로 응답을 바꿔 극단적인 값을 넣어 보라.
📋 기준 응답 (이 값들을 극단적으로 바꿔보세요)
{
"success": true,
"data": {
"name": "황금올리브치킨 세트 (순살)",
"summary": "바삭한 황금올리브 순살치킨 + 치즈볼 4개 + 콜라 1.25L",
"price": 23000,
"originalPrice": 28000,
"badges": ["베스트", "1+1 이벤트"],
"rating": 4.7,
"reviewCount": 1820
}
}
✅ 정답 · 깨뜨려볼 케이스
name을 50자 이상 아주 길게 → 한 줄 말줄임 vs 줄바꿈badges를 10개 이상 → 칩이 넘치는지 / 줄바꿈 되는지summary에 이모지·특수문자 폭탄 🔥🔥🔥price를 음수/엄청 큰 수/문자열로 → 포맷 깨짐- 필드를 아예 빼서 → 빈 값/undefined 처리되는지
🎯 미션 결제는 항상 성공한다. 그렇다면 ‘결제 실패’ 화면은 제대로 만들어져 있을까? 서버 장애를 일으키지 않고 실패 상황을 재현해서 오류 UI를 검증하라.
💡 힌트
- 성공 응답과 실패 응답은 본문 구조가 다르다 (
success값을 보라). - 실제로 실패하길 기다릴 필요 없이, Map Local 로 실패 응답을 내려주면 된다.
✅ 정답 · Map Local로 내려줄 오류 응답 (예: 400)
{
"success": false,
"error": {
"code": "PROXYMAN_INSUFFICIENT_BALANCE",
"message": "잔액이 부족합니다. 다른 결제수단을 선택해 주세요."
}
}
🎯 미션
리뷰 화면이 정상 동작하지 않는다(현재 501 미구현). 서버가 아직 이 API를 안 만들었다.
아래 명세만 보고, 그에 맞는 응답을 직접 만들어 서버 없이 이 화면을 완성하라.
- successboolean
- dataobject
- averageRatingnumber4.6
- totalCountinteger
- reviewsarray<object>
- idinteger
- authorstring
- ratinginteger1~5
- contentstring
- menusstring[]
- createdAtstring<date>
💡 힌트
- 서버에 없는 응답을 Map Local 로 가짜로 만들어 내려주면 된다.
- 값은 명세 타입만 맞으면 아무 내용이나 넣어도 화면이 그려진다.
✅ 정답 예시 · Map Local로 내려줄 응답 (200 OK)
{
"success": true,
"data": {
"averageRating": 4.6,
"totalCount": 3,
"reviews": [
{
"id": 101,
"author": "치킨러버",
"rating": 5,
"content": "바삭하고 양도 많아요. 치즈볼은 항상 진리!",
"menus": ["황금올리브치킨", "치즈볼"],
"createdAt": "2026-05-24"
},
{
"id": 102,
"author": "강남직장인",
"rating": 4,
"content": "맛은 좋은데 배달이 살짝 늦었어요. 그래도 따뜻하게 왔습니다.",
"menus": ["황금올리브치킨"],
"createdAt": "2026-05-23"
},
{
"id": 103,
"author": "야식헌터",
"rating": 5,
"content": "늦은 밤에 시켰는데 빠르게 왔어요 👍 콜라 시원했음",
"menus": ["콜라 1.25L"],
"createdAt": "2026-05-22"
}
]
}
}
🎯 미션 이 홈 화면은 ‘웹 전용’ 혜택을 보여준다. URL은 그대로 둔 채, ‘앱 전용’ 혜택 화면을 받아내라.
- 요청 헤더
User-Agent에BaeminApp이 포함 → 앱으로 판단 (platform: "APP") - 포함되지 않음 → 웹으로 판단 (
platform: "WEB")
💡 힌트
- 응답이 아니라 요청을 바꿔야 한다 → Map Local 말고 Scripting.
- 요청이 나가기 전에 헤더를 끼워 넣을 수 있는 단계가 있다.
- 화면 하단 “서버가 인식한 User-Agent” 로 주입 여부를 확인.
✅ 정답 · 해설
서버는 User-Agent 에 BaeminApp 포함 여부로 WEB/APP을 가른다.
Proxyman Scripting 의 Request 단계에서 주입:
function onRequest(context, url, request) {
request.headers["User-Agent"] =
"BaeminApp/1.0 " + (request.headers["User-Agent"] || "");
return request;
}
새로고침 → platform: "APP" 으로 바뀌고 앱 전용 배너가 노출.
🎯 미션 이 화면에는 로딩 상태(스켈레톤)가 있다. 평소엔 너무 빨라서 보이지 않는다. 로딩 UI를 천천히 눈으로 검증할 수 있게 만들어라.
💡 힌트
- 응답 “내용” 을 바꾸는 문제가 아니다. “속도” 를 바꾸는 문제다.
- Proxyman Tools 중 네트워크 환경을 흉내 내는 기능을 찾아보라.
✅ 정답 · 해설
- Tools >
Network Conditions활성화 - 프리셋을
2G/Edge등 느린 값으로 선택 - 또는 Latency를
3000ms이상으로 직접 설정 - 새로고침 → 스켈레톤이 길게 노출되는지 확인
🎯 미션 ‘일일 보상 받기’ 버튼은 하루 한 번만 눌리고, 받고 나면 비활성화된다. 버튼을 다시 누르지 않고 보상을 한 번 더 받아내라.
- 버튼 클릭 →
POST /reward→ 보상 지급 - 지급 후 버튼은 클라이언트에서 disable (오늘 다시 못 누름)
💡 힌트
- 버튼이 막혔을 뿐, 요청 자체는 한 번 성공해서 Proxyman에 남아 있다.
- 그
POST /reward요청을 Repeat 해보면?
✅ 정답 · 해설
- Proxyman에서 성공한
POST /reward우클릭 → Repeat (또는 Edit & Repeat) - 서버가 중복 요청을 막지 않으므로 보낼 때마다 보상이 또 지급됨
- 교훈: 클라이언트 disable은 보안이 아니다. 1일 1회는 서버가 검증해야 함
🎯 미션 이 설문 폼은 입력값을 깐깐하게 검사한다. 폼에서는 막히는 값(이모지·음수·초과 글자수)을 서버에 그대로 접수시켜라.
nickname: 2~10자, 이모지·특수문자 불가age: 1~120 정수, 음수 불가comment: 최대 50자
💡 힌트
- 먼저 정상 값으로 한 번 제출해서
POST /survey요청을 만들어라. - Proxyman에서 그 요청을 Edit & Repeat → 본문(JSON)을 규칙 위반 값으로 고쳐 재전송.
✅ 정답 · 해설
- 정상 제출 → Proxyman에서
POST /survey우클릭 → Edit & Repeat - Body를
{"nickname":"🔥😈","age":-5,"comment":"(51자 이상)"}처럼 바꿔 전송 - 서버가 그대로 접수 → 결과 화면/응답에 위반 값이 찍힘
- 교훈: 클라 유효성 검사는 UX용일 뿐. 서버에서도 반드시 검증해야 함
🎯 미션
이 주문의 결제 금액은 23,000원이다. 결제하기 를 누르면 그 금액으로
포트원 테스트 결제창이 뜬다. 결제창이 100원으로 뜨게 만들어 결제를 완료하라.
- 결제하기 →
GET /checkout-info로 결제 금액(amount)을 받아온다 - 받은 금액으로 포트원
requestPayment({ totalAmount })결제창을 띄운다
💡 힌트
- 결제창에 들어가는 금액이 어디서 오는지 보라 — 네트워크 응답에 있다.
GET /checkout-info응답을 Map Local(또는 Breakpoint)로 바꾸면 결제창 금액도 바뀐다.
✅ 정답 · 해설
- Proxyman에서
GET /checkout-info에 Map Local 적용 →"amount": 100으로 변경 - 결제하기 → 포트원 결제창이 100원으로 뜨고 테스트 결제 완료
- 교훈: 결제창 금액은 클라가 받은 값이라 변조된다. 서버가 결제 후 포트원 API로 실제 결제금액을 재검증해야 함
주문 결제
- 황금올리브치킨 × 120,000원
- 콜라 1.25L × 13,000원
🎯 미션 지금은 내 주문(ORD-1001) 만 보인다. 서버를 건드리지 않고 다른 사람의 주문 정보를 꺼내 보라.
GET /myorder?orderId=ORD-1001로 주문을 조회- 주문에는 이름·전화번호·주소 등 개인정보가 포함된다
💡 힌트
- 요청에
orderId가 그대로 노출돼 있다. 이 값을 바꾸면? - Proxyman에서 Edit & Repeat 으로
orderId를ORD-1002,ORD-1003… 으로 바꿔 전송.
✅ 정답 · 해설
GET /myorder를 Edit & Repeat → 쿼리orderId를 남의 번호로 변경- 소유자 검증이 없어 타인의 개인정보가 그대로 조회됨 (IDOR)
- 교훈: 서버가 “이 주문이 요청자 소유인지” 를 반드시 확인해야 함