POST 요청의 네 조각과 requests 옵션 대응표

🛡️ 강사 제공 인가된 실습 환경에서 수행

POST 요청의 전체 구조

POST /dvwa/vulnerabilities/exec/ HTTP/1.1        ← ① 요청 라인
Host: 192.168.10.102                             ← ② 헤더 (필수)
Cookie: security=low; PHPSESSID=abc123...        ← ② 헤더 (인증)
User-Agent: Mozilla/5.0 ...                      ← ② 헤더
Referer: http://192.168.10.102/dvwa/...          ← ② 헤더
Content-Type: application/x-www-form-urlencoded  ← ② 헤더 (본문 형식)
Content-Length: 27                               ← ② 헤더 (본문 길이)
(빈 줄 - CRLF)                                    ← ③ 헤더 끝 신호
ip=127.0.0.1;whoami&submit=submit                ← ④ 본문(body) = 보낼 데이터

순서는 요청 라인 → 헤더들 → 빈 줄 → 본문이다. POST는 GET과 달리 본문에 데이터를 담는다(GET은 URL 쿼리스트링).

① 요청 라인

메서드 + 경로 + HTTP 버전

요소예시의미
메서드POST서버에 데이터를 보내는 요청
경로/dvwa/vulnerabilities/exec/어느 페이지로
버전HTTP/1.1프로토콜 버전

파이썬에선 requests.post(url) 의 url이 호스트+경로를 담당한다.

② 헤더 — 요청의 메타정보

필수 / 중요

헤더역할안 넣으면?
Host어느 도메인/서버로requests가 URL로 자동 처리
Cookie인증/세션 (로그인 증명)로그인 필요한 페이지 접근 불가 (302 튕김)
Content-Type본문 데이터의 형식서버가 본문 해석 못 할 수 있음
Content-Length본문 길이requests가 자동 계산

위장 / 부가 (공격 시 자주 조작)

헤더역할공격 관점
User-Agent클라이언트(브라우저/OS) 정보봇 탐지 회피용 위장, 정보 노출
Referer어느 페이지에서 왔는지검증 우회, 위조 가능
Accept받고 싶은 응답 형식
Accept-Language선호 언어핑거프린팅
Connection연결 유지 방식 (keep-alive)

헤더는 전부 클라이언트가 보내는 값이다. 위조가 가능하므로 서버가 신뢰하면 안 된다.

③ 빈 줄 (CRLF)

헤더가 끝났다는 신호(\r\n\r\n)이고, 이 빈 줄 다음부터가 본문이다. CRLF Injection 취약점의 원리가 여기서 나온다.

④ 본문 — 실제 보낼 데이터

POST의 핵심. 여기에 데이터를 담아 보낸다.

Content-Type본문 형식용도
application/x-www-form-urlencodedkey1=val1&key2=val2일반 폼 (DVWA 로그인/공격)
application/json{"key": "value"}API, JSON 전송
multipart/form-data경계(boundary)로 구분파일 업로드
  • form 형식: ip=127.0.0.1;whoami&submit=submit
  • JSON 형식: {"items": [{"dir": "/var/www/", "name": "index.php"}]}

파이썬 requests에서 각 요소 대응

requests.post(
    url,                    # ① 요청 라인 (호스트+경로)
    headers={               # ② 헤더
        "Cookie": "...",
        "User-Agent": "...",
        "Content-Type": "...",
    },
    data={                  # ④ 본문 (form 형식)
        "ip": "127.0.0.1;whoami",
        "submit": "submit"
    },
    # 또는
    json={"items": [...]},  # ④ 본문 (JSON 형식) - Content-Type 자동 설정
    cookies={"PHPSESSID": "..."},   # ② Cookie (headers 대신 여기로도 가능)
    verify=False,           # SSL 검증 무시 (프록시 가로채기용)
    allow_redirects=False,  # 리다이렉트 자동추적 끄기 (302 확인용)
    proxies={"http": "http://127.0.0.1:8080"}  # Burp 경유 (디버깅)
)

data 와 json 의 차이

data=json=
본문 형식key=val&key=val{"key": "val"}
Content-Typex-www-form-urlencodedapplication/json (자동)
용도일반 폼 (DVWA)API / 서버 전송 (Flask)

자주 쓰는 옵션

옵션역할언제 씀
data=본문에 폼 데이터일반 POST
json=본문에 JSONAPI 전송
headers=헤더 지정위장 / 인증
cookies=쿠키 지정세션 유지
verify=FalseSSL 검증 끄기프록시 가로채기, 자체서명 인증서
allow_redirects=False리다이렉트 안 따라감302 확인, 중간 응답 분석
proxies=프록시 경유Burp로 요청 확인 / 디버깅

세션 유지 — requests.Session()

여러 요청에서 쿠키를 자동으로 이어서 쓰려면 이렇게 한다.

s = requests.Session()      # 쿠키를 들고 다니는 객체
s.post(login_url, data=...) # 로그인 → 쿠키 자동 저장
s.post(exec_url, data=...)  # 같은 s → 쿠키 자동 첨부

브라우저가 자동으로 하던 쿠키 관리를 Session이 대신 해주는 것이다.

정리

POST 요청 = 요청라인 + 헤더 + 빈줄 + 본문

  1. URL — 어디로 보낼지
  2. 헤더 — 메타정보 (Cookie=인증, Content-Type=본문형식, User-Agent/Referer=위장)
  3. 본문 (data / json) — 실제 보낼 데이터. POST의 핵심
  4. 옵션 — verify(SSL), allow_redirects(302), proxies(디버깅)

GET과 POST의 핵심 차이는 하나다. GET은 데이터를 URL에, POST는 데이터를 본문에 담는다.