Everything you will ever hack on the web comes down to two things moving back and forth: a request and a response. That is really all there is to it. It does not matter how fancy the app looks on the surface. It might use a React front end, a GraphQL API, WebSockets, or whatever framework is trendy this year. Underneath all of that is HTTP, and HTTP is surprisingly simple. It is just text. Plain, human-readable, typo-prone text, sent over a network connection. You could write a valid HTTP request by hand in a plain text editor. People actually did this for decades, before frameworks came along and hid the details from us.
That simplicity is your biggest advantage as a penetration tester (someone who is hired to attack a system on purpose, to find its weaknesses before a real attacker does). A developer looks at a form on a page and sees a form. You look at that same form and see the request it is about to send, and you know you can send something different instead.
The request line: three things, in order
Every HTTP request starts with one line, and that line always has exactly three parts.
GET /account/settings?tab=security HTTP/1.1
Method: what you want to do. Common methods are GET, POST, PUT, DELETE, and a few others we will cover in the next lesson.
Path: which resource on the server you are asking for, plus any query string tacked onto the end. A query string is the part after the ? that passes extra values to the server.
Version: almost always HTTP/1.1 still. HTTP/2 and HTTP/3 are becoming more common. They send data in binary form instead of plain text, but they still carry the same basic fields underneath.
There is nothing magic in that line. But the path and query string together are where a lot of your testing time will go, because everything after the ? is input the user controls, and the server has to parse it, trust it, and act on it. In ?tab=security, the word security is a variable, something that can be changed. Variables are where bugs live.
Headers: metadata that decides everything
After the request line comes a list of Header-Name: value pairs, one per line. Headers carry extra information about the request, and this is where most of the interesting detail is for a penetration tester. Here are the headers that actually matter in practice, not just the ones a textbook lists to look complete.
Host: tells the server which website you are asking for. One IP address (the numeric address of a server) can host hundreds of different websites at once. This setup is called virtual hosting. The Host header is the only thing that tells the web server which one of those sites you actually want. If this header is missing or wrong, you might get a default site, a certificate error, or, if the app is sloppy about checking it, you might be able to poison password reset links or cache entries by lying about what host you are.
Cookie: carries the session token (a piece of data that proves you are logged in), CSRF token (a value used to stop forged requests, explained later in the course), and often tracking data too, all packed into one header. Once you have a valid cookie, it is usually your key to everything the account can do.
Authorization: carries bearer tokens, JWTs (a type of signed token we cover later in the course), or Basic auth credentials. Basic auth looks like Authorization: Basic base64(user:pass). Base64 is just a way of encoding text so it is not human-readable at a glance. It is not encryption. Do not let the word "Authorization" make you think this is automatically protected.
User-Agent: supposedly tells the server what browser or program you are using. In reality it is just a string of text you can type yourself. Some older firewalls and bot-detection systems still trust this header, which tells you how much you should actually trust it: not much.
Referer: this header name has been misspelled in the official spec since the very beginning, and it has stayed that way permanently. It tells the server which page linked to the current request. It can leak URLs, and sometimes it leaks tokens that were carelessly placed inside a URL.
Content-Type: tells the server how to read the body of the request. The three you will see most are application/x-www-form-urlencoded, application/json, and multipart/form-data. Changing this header while keeping the same endpoint (the same URL that handles the request) is a classic way to slip a payload past a filter that was only ever written to check one of these formats.
Content-Length: states how many bytes the body contains. It sounds boring, but a mismatch between the stated length and the actual body is the root cause of a whole attack category called HTTP request smuggling. We are not covering that attack in this lesson, but it is worth remembering the name.
Origin: tells the server where the request came from, and it is used by CORS checks (CORS is a browser rule about which websites are allowed to talk to which servers; we cover it in a later lesson). It is different from Referer because it only contains the scheme, host, and port, never the path, and browsers attach it more strictly on requests that cross from one site to another.
X-Forwarded-For: added by proxies (servers that sit between the client and the real destination) to say "the real client's IP address was this one." In a lot of setups, a client can set this header themselves, which makes it a favorite tool for getting around IP-based rate limits and access controls.
Gotcha
Never trust a header just because it sounds official. X-Forwarded-For, User-Agent, and even Host in some poorly configured setups, are all just strings that the client typed. If an application makes a security decision based on one of these headers without checking it properly on the server side, that is a real finding, not a minor detail.
The body: only when there is something to say
GET requests usually do not have a body, because there is nothing to send. You are just asking for something. POST, PUT, and PATCH requests usually do carry a body. Its format is whatever the Content-Type header says it is.
http
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=admin&password=test
Or the same login attempt sent as JSON instead:
http
POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 39
{"username":"admin","password":"test"}
Both requests are doing the same thing, just in two different shapes. This matters because a lot of input validation code gets written for one shape and never updated for the other. An application that carefully checks form-encoded input for SQL injection might have a completely separate, much less tested code path for parsing JSON. Always test both formats if the API accepts more than one.
What comes back: the response
The server answers with its own three-part status line, its own set of headers, and usually a body.
The Set-Cookie header in that example is doing a lot of work, and its flags matter more than most people realize. HttpOnly stops JavaScript running on the page from reading the cookie, which removes a chunk of the damage a cross-site scripting attack could otherwise do. Secure means the cookie is only ever sent over HTTPS (the encrypted version of HTTP). SameSite controls whether the cookie gets attached when the request comes from a different site, which is directly relevant to CSRF attacks, covered later in the course. A cookie that is missing all three of those flags is one of the fastest, easiest findings you will ever write up. You will see this same checklist again when we get to session security.
The Server and X-Powered-By headers often leak details about the technology stack: the nginx version, the PHP version, whether the app runs on Express, and so on. This is great news for you when you are trying to identify the target's software, and bad news for the app's security, which is exactly why well-secured deployments remove these headers.
Rendering diagram…
Statelessness: HTTP has amnesia by design
Here is the detail that trips up almost everyone who is new to this: HTTP does not remember you. As far as the protocol itself is concerned, every request is a brand new event with no memory of what came before. The server has no built-in way of knowing that the GET /account request you just sent came from the same person who logged in thirty seconds ago. This is what people mean when they call HTTP "stateless": it keeps no state, no memory, between one request and the next.
Pivot
Every "session" you have ever used on the web is a workaround built on top of HTTP, not a feature that HTTP has natively. The server hands you a cookie, you hand that same cookie back on every later request, and the server uses it to act as if it remembers you. Once you understand that a session is really just state management bolted on afterward, bugs like session fixation, session hijacking, and weak token generation stop feeling mysterious. They start feeling like the obvious result of that workaround.
That same amnesia is also what makes request forgery attacks (known as CSRF) possible at all. The server cannot tell the difference between "the user clicked a button on our own site" and "the user's browser was tricked into sending that same request from some completely different site," because an HTTP request carries no built-in proof of what the user actually intended. Cookies get attached automatically by the browser no matter who triggered the request. We will look at exploiting that gap properly later in the course.
Note
Your browser's developer tools, specifically the Network tab, show you a cleaned-up, reformatted view of all this. It is worth getting comfortable reading raw requests too. Burp Suite's Repeater tab shows you the literal bytes being sent, and that raw view is what you actually want when you are building a payload by hand.
Once you can read a request and a response fluently (the method, the headers, the body, and the status code) you have the foundation for everything else in this course. Every vulnerability class we cover from here on really just comes down to this question: what happens when the server trusts something in this exchange that it should not have trusted? Next, we will turn that fluency into an actual recon methodology (a systematic process for mapping out everything a target application exposes).
Sign in to track progress, submit flags, and take notes.