Python › Python for Pentesters

Sending data: parameters, headers, and bodies

4 min read Beginner 5 sections

A GET request that just fetches a page is the start. Real testing means sending things — query parameters, custom headers, POST bodies, JSON. The beautiful part of requests is that each piece of an HTTP request maps directly to a Python argument, and those arguments are dictionaries you already know how to build.

You'll learn to

  • Send query parameters, headers, and bodies
  • Use any HTTP method, including unusual ones
  • See why this control is the whole game for web testing

Each request part is an argument

import requests

# Query parameters (?key=value) — pass a dict, requests builds the URL:
params = {"q": "test", "page": 2}
r = requests.get("https://example.com/search", params=params)
# → https://example.com/search?q=test&page=2

# Custom headers — a dict:
headers = {"User-Agent": "recon/1.0", "X-Forwarded-For": "127.0.0.1"}
r = requests.get("https://example.com", headers=headers)

# POST a form body:
r = requests.post("https://example.com/login", data={"user": "admin", "pass": "x"})

# POST a JSON body (sets Content-Type: application/json automatically):
r = requests.post("https://example.com/api", json={"name": "test"})

The mapping is clean and worth memorising: params= (a dict) becomes the query string; headers= (a dict) sets request headers; data= sends a form body; json= sends a JSON body and sets the right content type. The HTTP method is just the function name — get, post, put, delete.

Any method, including the unusual ones

requests.put("https://example.com/api/item/1", json={"name": "new"})
requests.delete("https://example.com/api/item/1")
requests.request("OPTIONS", "https://example.com")   # any method, even custom

requests.request(method, url) lets you send any verb, including ones a browser never would.

Verb tampering: a concrete example

Many apps protect the obvious method but forget the others. The UI shows a read-only GET, but the endpoint quietly accepts DELETE:

# The app only links GET, but what happens with DELETE?
r = requests.delete("https://example.com/api/users/42", headers=auth_headers)
print(r.status_code)   # 200 here would be a serious finding

Checkpoint

You want to add ?role=admin&debug=true to a GET request. What argument do you pass to requests.get, and in what form?

Try it yourself

Send a POST to https://httpbin.org/post with a JSON body of {"user": "test", "role": "admin"} using the json= argument. Print r.json() — httpbin echoes back what it received, so you can confirm your body and headers went out correctly.

Summary

Every part of an HTTP request maps to a requests argument: params= for the query string, headers= for headers, data= for form bodies, json= for JSON bodies (all dictionaries). The method is the function name, or requests.request(method, url) for any verb. This direct, total control — any header, any body, any method, in a loop — is exactly what makes Python a web-testing tool rather than just a page fetcher.

Key takeaways

  • params=, headers=, data=, json= are all dictionaries you build.
  • data= is form-encoded; json= is a JSON body — don’t mix them up.
  • Any HTTP method is available; verb tampering finds missing access controls.
  • Total request control across a loop is the core of automated testing.

Quick quiz

Next, reading what comes back: parsing JSON responses, which is most of API testing.

Was this lesson helpful?