서버 측 요청 위조

Server-side request forgery

서버가 외부 입력의 URL을 따라가 내부망 자원에 접근하는 일을 막습니다.

···
html
<div class="sd"><div class="sd-head"><strong>SSRF</strong><span id="state">live check</span></div><div class="sd-stage"><div class="tile">URL input</div><div class="path"><div class="tile" id="target">public host</div><div class="bar" id="bar"></div><div class="tile" id="dest">internet</div></div></div><div class="sd-foot"><span id="caption">checking boundary</span><span>tap to step</span></div></div>
css
.sd{box-sizing:border-box;width:min(94vw,700px);height:min(86vh,318px);padding:clamp(9px,2.3vmin,18px);border:1px solid var(--line);border-radius:14px;background:var(--surface);color:var(--fg);display:flex;flex-direction:column;gap:clamp(6px,1.8vmin,12px);font:600 clamp(12px,2.6vmin,16px)/1.25 var(--font-sans, sans-serif)}.sd *{box-sizing:border-box}.sd-head,.sd-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:1.25em}.sd-head strong{color:var(--accent);letter-spacing:.06em}.sd-head span,.sd-foot{color:var(--muted)}.sd-foot{font-size:clamp(12px,2.4vmin,14px)}.sd-stage{position:relative;flex:1;min-height:0;display:flex;align-items:center;justify-content:center;gap:clamp(6px,2vmin,18px);overflow:hidden}.sd .mono{font-family:ui-monospace,monospace}.sd .tile{border:1px solid var(--line);border-radius:8px;background:var(--bg);padding:clamp(5px,1.5vmin,10px);text-align:center}.sd .good{color:var(--accent);border-color:var(--accent)}.sd .bad{color:var(--accent-3);border-color:var(--accent-3)}.sd .arrow{color:var(--muted);font-size:clamp(15px,4vmin,28px)}.sd .active{background:color-mix(in srgb,var(--accent) 16%,var(--surface));border-color:var(--accent)}.sd .blocked{background:color-mix(in srgb,var(--accent-3) 13%,var(--surface));border-color:var(--accent-3)}.sd-stage .path{display:flex;align-items:center;gap:clamp(5px,1.6vmin,10px);width:65%}.path .tile{flex:1;min-width:0}.bar{width:clamp(16px,6vmin,45px);height:4px;background:var(--accent);transition:background .2s}.bar.stop{background:var(--accent-3)}.sd-stage>.tile{width:25%}
js
let n=0;function advance(){n=1-n;document.getElementById('target').textContent=n?'private IP':'public host';document.getElementById('dest').textContent=n?'blocked':'internet';document.getElementById('dest').classList.toggle('blocked',!!n);document.getElementById('bar').classList.toggle('stop',!!n);document.getElementById('state').textContent=n?'destination denied':'destination allowed';document.getElementById('caption').textContent=n?'private destination rejected':'public destination fetched'}advance();setInterval(advance,900);
document.querySelector('.sd').addEventListener('pointerdown',advance);

SSRF는 서버가 사용자 입력으로 받은 URL에 대신 요청할 때 생깁니다. 외부에서 직접 닿지 않는 내부 서비스나 메타데이터 주소도 서버에서는 접근 가능할 수 있습니다.

데모는 공개 주소와 내부 주소를 같은 프록시에 넣고 목적지 검사 결과를 비교합니다. URL의 호스트만 검사하는 것으로 끝내지 말고 DNS 해석 결과, 리다이렉트, 네트워크 경계도 함께 통제해야 합니다.

언제 쓰나

URL 미리보기, 웹훅 검사, 이미지 가져오기처럼 서버가 임의 URL을 요청하는 기능에서 점검합니다.

페이지로 열기 ↗