HTTP Headers Explained: The Hidden Metadata That Controls Every Web Page
Developer Tools

HTTP Headers Explained: The Hidden Metadata That Controls Every Web Page

IP Pulse Pro TeamMay 5, 202613 min read
Share:

What Are HTTP Headers?

HTTP Headers Request Response CORS Caching Security

HTTP headers are the invisible metadata that accompanies every single request and response transmitted across the web. When you type a URL into your browser and press Enter, your browser does not simply ask for a page — it sends a structured HTTP request that includes a request line (method, URL, HTTP version) followed by a series of key-value pairs called headers. These headers tell the server who you are, what you want, what formats you accept, what languages you prefer, and a wealth of other contextual information. The server responds with its own set of headers that instruct your browser how to handle the content, whether to cache it, how long it is valid, and what security policies apply. Understanding HTTP headers is essential for anyone working with web technologies, from frontend developers debugging CORS errors to security engineers hardening web applications against exploitation.

The HTTP/1.1 specification (RFC 7230-7235, now superseded by RFC 9110-9114) defines headers as flexible, extensible name-value pairs separated by a colon, terminated by a carriage return and line feed (CRLF). A typical HTTP request includes between 5 and 20 headers, while responses commonly carry 10 to 30 or more. The total size of headers in a request can range from a few hundred bytes to several kilobytes, and in pathological cases — such as cookies carrying large session tokens — headers alone can exceed 8 KB. With HTTP/2, headers are compressed using HPACK encoding to reduce this overhead, but the logical structure remains the same. Every header belongs to a category: request headers sent by the client, response headers sent by the server, representation headers that describe the message body, and payload headers that describe transfer encoding.

Headers are arguably the most important control plane of the web. They govern caching behavior (determining whether your browser re-downloads a resource or uses a stored copy), security posture (through headers like Content-Security-Policy, Strict-Transport-Security, and X-Frame-Options), content negotiation (allowing clients and servers to agree on language, encoding, and media type), authentication (carrying tokens and credentials), and cross-origin access control (through the CORS header family). A misconfigured header can break functionality, degrade performance, or create critical security vulnerabilities. According to the OWASP Top 10, security misconfiguration — which frequently involves missing or incorrect HTTP headers — remains one of the most prevalent web application security risks. This guide provides a comprehensive reference for understanding, configuring, and debugging HTTP headers in modern web applications.

Tip: You can inspect the HTTP headers of any website in seconds using browser DevTools. Open the Network panel (F12 → Network), reload the page, and click any request to view both request and response headers. This is the fastest way to debug caching, CORS, and security header issues without installing any additional tools.

Request Headers vs Response Headers

HTTP headers flow in both directions of the client-server communication, and understanding the distinction between request headers and response headers is fundamental to mastering web protocols. Request headers are sent by the client (typically a browser) to the server as part of an HTTP request message. They communicate the client's capabilities, preferences, and context — telling the server what content types it can process, what languages it prefers, what encoding it supports, and what authentication credentials it possesses. Response headers are sent by the server back to the client as part of an HTTP response message. They communicate the server's instructions, metadata about the response body, caching directives, security policies, and session management information.

The asymmetry between request and response headers is significant. Request headers are primarily informational and advisory — they tell the server what the client wants and can handle, but the server is not obligated to honor every request header. For example, a client may send Accept-Encoding: gzip, br to indicate it supports compressed responses, but the server may choose to send uncompressed content anyway. Response headers, by contrast, are often directive and authoritative — they instruct the client how to behave. A Strict-Transport-Security response header compels the browser to use HTTPS for all future requests to that domain. A Content-Security-Policy header restricts what resources the browser is allowed to load. These response headers are security-critical because they shift trust decisions from the application layer to the browser's enforcement engine.

Some headers can appear in both requests and responses but serve different purposes depending on the direction. The Connection header, for instance, can be sent by either party to control whether the TCP connection remains open after the current transaction. The Content-Type header appears in both directions: in requests with a body (like POST), it tells the server what format the request body is in; in responses, it tells the client what format the response body is in. Understanding these dual-use headers requires attention to context and direction. The following comparison panel summarizes the key differences between request and response headers.

Request Headers

Direction: Client → Server

Purpose: Describe client capabilities and preferences

Examples: Accept, User-Agent, Cookie, Authorization

Security Role: Authenticate client, negotiate features

Compliance: Advisory — server may ignore

Typical Count: 5–20 headers per request

Response Headers

Direction: Server → Client

Purpose: Deliver server instructions and metadata

Examples: Content-Type, Set-Cookie, Cache-Control, CSP

Security Role: Enforce security policies, control caching

Compliance: Directive — browser must enforce (for security headers)

Typical Count: 10–30+ headers per response

The Most Important HTTP Headers

Hundreds of HTTP headers are defined across various RFCs, vendor specifications, and de facto standards, but a relatively small subset accounts for the vast majority of headers you will encounter in everyday web development and operations. The following reference table catalogs the most important headers, their direction, purpose, and the RFC or specification that defines them. This is not an exhaustive list — the IANA HTTP Header Field Registry contains over 250 entries — but it covers the headers that every web professional should understand.

HeaderDirectionPurposeSpecification
HostRequestSpecifies the target host and port (required in HTTP/1.1)RFC 9110
User-AgentRequestIdentifies the client software making the requestRFC 9110
AcceptRequestDeclares MIME types the client can processRFC 9110
Accept-LanguageRequestDeclares preferred natural languagesRFC 9110
Accept-EncodingRequestDeclares supported content codings (gzip, br, zstd)RFC 9110
AuthorizationRequestContains credentials for authenticating the clientRFC 9110
CookieRequestSends stored cookies to the serverRFC 6265
RefererRequestIndicates the URL of the page that linked to the requestRFC 9110
If-Modified-SinceRequestMakes a request conditional on modification timeRFC 9110
If-None-MatchRequestMakes a request conditional on ETag valueRFC 9110
Content-TypeBothIndicates the MIME type of the message bodyRFC 9110
Content-LengthBothIndicates the size of the message body in bytesRFC 9110
Content-EncodingResponseSpecifies the encoding applied to the response bodyRFC 9110
Set-CookieResponseWrites a cookie to the client's cookie storeRFC 6265
Cache-ControlBothDirectives for caching mechanismsRFC 9111
ETagResponseOpaque identifier for a specific version of a resourceRFC 9110
LocationResponseIndicates the target URL for redirectsRFC 9110
ServerResponseIdentifies the server software handling the requestRFC 9110
X-Request-IDBothCorrelation ID for distributed request tracingDe facto standard

Several of these headers deserve additional commentary. The Host header is the only mandatory request header in HTTP/1.1 — without it, the server cannot determine which virtual host should handle the request, because multiple domains may share a single IP address. The Authorization header carries credentials using schemes like Bearer tokens (RFC 6750) for OAuth 2.0, Basic authentication (base64-encoded username:password), or Digest authentication. The Referer header (note the historical misspelling) is a privacy concern because it can leak sensitive URL parameters; the Referrer-Policy response header was introduced to control how much referrer information is shared. The ETag header enables conditional requests that dramatically reduce bandwidth by allowing clients to verify whether a cached resource is still valid without re-downloading it.

Security Headers Every Website Must Have

Security headers are HTTP response headers that instruct browsers to activate built-in protective mechanisms, creating a defense-in-depth layer that mitigates common web vulnerabilities even when application-level defenses fail. Despite their proven effectiveness — Scott Helme's annual scan of the top 1 million websites consistently shows that sites using security headers have significantly lower rates of XSS, clickjacking, and MITM attacks — adoption remains alarmingly low. As of 2025, only about 30% of the top 1 million sites implement Content-Security-Policy, and fewer than 40% use Strict-Transport-Security. Every website, regardless of size or complexity, should implement the following security headers to protect its users.

Warning: Missing or misconfigured security headers are one of the most common vulnerabilities found in web applications. A missing Content-Security-Policy header leaves your site wide open to cross-site scripting (XSS) attacks, while the absence of Strict-Transport-Security enables SSL stripping attacks that can expose user credentials in plaintext. Always audit your security headers before deploying to production — tools like securityheaders.com and Mozilla Observatory can scan your site for free and grade your configuration.

Strict-Transport-Security (HSTS)

Strict-Transport-Security (HSTS) instructs the browser to only connect via HTTPS for the specified duration, eliminating the possibility of SSL-stripping attacks where a man-in-the-middle downgrades the connection from HTTPS to HTTP. The includeSubDomains directive extends this protection to all subdomains, and the preload directive allows the domain to be included in browser-maintained HSTS preload lists that enforce HTTPS from the very first visit. Without HSTS, even a site that redirects HTTP to HTTPS is vulnerable during the initial redirect — an attacker can intercept this redirect and keep the victim on an HTTP connection. HSTS should be deployed with a max-age of at least 31536000 seconds (1 year), and sites should submit to the HSTS preload list after testing.

Content-Security-Policy (CSP)

Content-Security-Policy (CSP) is the most powerful security header, allowing you to specify precisely which sources of content the browser is allowed to load for a given page. A well-crafted CSP prevents cross-site scripting (XSS) by blocking inline scripts and restricting script sources to trusted origins, prevents data exfiltration by controlling which domains can receive data via img, form, and connect directives, and prevents clickjacking by restricting frame-ancestors. However, CSP is also the most complex header to implement correctly — an overly permissive policy provides no real protection, while an overly restrictive policy breaks functionality. Start with a report-only mode (Content-Security-Policy-Report-Only) to identify violations before enforcement, then gradually tighten the policy.

X-Content-Type-Options

X-Content-Type-Options: nosniff prevents MIME-type sniffing, a browser behavior where the browser guesses the content type of a response instead of respecting the declared Content-Type. Without this header, an attacker who finds a way to upload a file containing executable content (like HTML with JavaScript) to your server could trick the browser into executing it, even if the Content-Type header says it is an image or text file. This simple one-value header eliminates an entire class of content injection attacks.

X-Frame-Options

X-Frame-Options prevents your page from being embedded in iframe elements on other domains, which is the primary mechanism for clickjacking attacks. Although the CSP frame-ancestors directive is the modern replacement, X-Frame-Options should still be included for backward compatibility with older browsers. Use DENY to prevent all framing, or SAMEORIGIN to allow framing only by pages on the same domain.

Permissions-Policy

Permissions-Policy (formerly Feature-Policy) allows you to selectively enable or disable browser features and APIs on your site, such as the camera, microphone, geolocation, fullscreen mode, and USB access. By restricting features to only the origins that need them, you reduce the attack surface available to compromised scripts and reduce the risk of unauthorized data access through exploited browser APIs.

HSTSCritical
CSPCritical
X-Content-Type-OptionsHigh
X-Frame-OptionsHigh
Referrer-PolicyHigh
Permissions-PolicyMedium
COOPMedium
CORPMedium
Security HeaderPurposeRisk Without ItRisk LevelRecommended Value
Strict-Transport-SecurityForce HTTPS connectionsSSL stripping, MITM attacksCriticalmax-age=31536000; includeSubDomains; preload
Content-Security-PolicyControl resource loadingXSS, data exfiltration, injectionCriticaldefault-src 'self'; script-src 'self'; style-src 'self'
X-Content-Type-OptionsPrevent MIME sniffingContent type confusion attacksHighnosniff
X-Frame-OptionsPrevent clickjackingUI redress attacksHighDENY or SAMEORIGIN
Referrer-PolicyControl referrer leakageURL parameter leaks to third partiesHighstrict-origin-when-cross-origin
Permissions-PolicyRestrict browser APIsUnauthorized API accessMediumcamera=(), microphone=(), geolocation=(self)
Cross-Origin-Opener-PolicyIsolate browsing contextCross-origin information leaksMediumsame-origin
Cross-Origin-Resource-PolicyControl cross-origin readsCross-origin data theft via SpectreMediumsame-origin

CORS Headers

Cross-Origin Resource Sharing (CORS) is the mechanism that allows web applications running at one origin to request resources from a different origin. By default, browsers enforce the Same-Origin Policy (SOP), which prevents a script on origin A from reading responses from origin B. This is a critical security boundary — without SOP, any website you visit could read your private data from any other website you are logged into. However, the modern web is inherently cross-origin: frontend applications hosted on one domain need to call APIs on another, CDNs serve static assets from different domains, and web fonts are loaded from specialized type foundries. CORS provides a controlled, opt-in mechanism for relaxing the Same-Origin Policy where it is necessary, while preserving it where it is not.

The CORS protocol works through a set of HTTP headers that the server includes in its responses to indicate which origins, methods, and headers are permitted for cross-origin requests. For simple requests (GET, HEAD, or POST with standard content types), the browser adds an Origin request header, and the server responds with Access-Control-Allow-Origin to grant or deny access. For "preflighted" requests — those using methods other than GET/HEAD/POST, or those with custom headers — the browser first sends an OPTIONS request to check whether the actual request is allowed. The server responds to the preflight with headers indicating the permitted methods, headers, and credentials, and only if the preflight passes does the browser send the actual request. This two-step process protects against cross-origin requests that could modify data on the server.

CORS Preflight Flow Browser (app.example.com) API Server (api.example.com) STEP 1: Preflight Request OPTIONS /api/data HTTP/1.1 Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type, Authorization STEP 2: Preflight Response HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 86400 STEP 3: Actual Request POST /api/data HTTP/1.1 Origin: https://app.example.com | Content-Type: application/json STEP 4: Actual Response Access-Control-Allow-Origin: https://app.example.com

The key CORS headers include Access-Control-Allow-Origin (specifies which origins are permitted — never use the wildcard * for credential-bearing requests), Access-Control-Allow-Methods (lists allowed HTTP methods), Access-Control-Allow-Headers (lists allowed request headers), Access-Control-Allow-Credentials (indicates whether cookies and authorization headers can be included in cross-origin requests), Access-Control-Max-Age (specifies how long the preflight result can be cached), Access-Control-Expose-Headers (lists response headers the browser should make available to JavaScript), and Access-Control-Request-Method/Access-Control-Request-Headers (used in preflight requests to declare the intended method and headers).

Common CORS misconfigurations create severe security vulnerabilities. Setting Access-Control-Allow-Origin to * when credentials are involved causes the browser to reject the response entirely — but some servers work around this by reflecting the request's Origin header directly into the response, which effectively allows any origin to make authenticated cross-origin requests. This "Origin reflection" vulnerability is one of the most dangerous CORS misconfigurations, as it completely defeats the Same-Origin Policy. Always explicitly enumerate the origins you trust, and never reflect the Origin header without validation. Use a server-side allowlist of permitted origins, and only set Access-Control-Allow-Origin to values from that allowlist.

Warning: The most dangerous CORS misconfiguration is "Origin reflection" — when the server blindly copies the request's Origin header into the Access-Control-Allow-Origin response header. This completely defeats the Same-Origin Policy and allows any website to make authenticated cross-origin requests to your API. Always use an explicit server-side allowlist of trusted origins instead.

Caching Headers

HTTP caching is one of the most impactful yet poorly understood aspects of web performance. Properly configured caching can reduce server load by 70-90%, cut bandwidth costs dramatically, and make pages load in milliseconds instead of seconds by eliminating redundant network round trips. Improperly configured caching, on the other hand, can serve stale content to users, break application functionality, and create confusing debugging scenarios where changes are not visible. The caching system is governed by two primary headers — Cache-Control and ETag/Last-Modified — along with supporting headers like Vary, Expires, and Age.

The Cache-Control header is the most important and versatile caching header, supporting a rich set of directives that control both who can cache a response and for how long. The max-age directive specifies the maximum time in seconds that a response is considered fresh — for example, Cache-Control: max-age=86400 means the response can be served from cache for 24 hours without revalidation. The s-maxage directive overrides max-age for shared caches (like CDNs) while allowing browsers to use their own max-age. The no-cache directive forces revalidation before use (despite its name, it does not prevent caching — it requires the cache to check with the server before serving the stored copy). The no-store directive truly prevents caching — the response must not be stored anywhere. The private directive restricts caching to the browser only (disallowing CDN caching), which is essential for personalized or sensitive content. The public directive explicitly allows shared caching, even if the response would normally be uncacheable (e.g., responses with Authorization headers).

Conditional request headers work in tandem with Cache-Control to provide efficient revalidation. When a cache entry expires, the browser sends a conditional request using If-None-Match (with the previously received ETag value) or If-Modified-Since (with the previously received Last-Modified date). If the resource has not changed, the server responds with 304 Not Modified — saving the bandwidth of re-transmitting the full resource body while confirming the cached copy is still valid. ETags are preferred over Last-Modified because they provide more granular validation (ETags change whenever the content changes, whereas Last-Modified has only 1-second resolution). The Vary header tells caches which request headers affect the response variant — for example, Vary: Accept-Encoding means the server may return different content for different compression methods, and the cache must store separate entries for each variant. Incorrectly omitting Vary can cause the cache to serve a compressed response to a client that cannot decompress it, or vice versa.

Cache-Control DirectiveEffectUse CaseExample
max-age=<seconds>Cache is fresh for N secondsStatic assets with hash filenamesmax-age=31536000
s-maxage=<seconds>Overrides max-age for shared cachesCDN-specific TTLss-maxage=86400, max-age=300
no-cacheRevalidate before using cached copyHTML documents that change frequentlyno-cache
no-storeNever cache the responseSensitive data, banking pagesno-store
privateOnly browser can cache (no CDN)Personalized user contentprivate, max-age=300
publicAllow shared cachesPublic resources behind authpublic, max-age=3600
must-revalidateMust revalidate once stalePrevents serving stale contentmax-age=3600, must-revalidate
immutableContent never changes while freshVersioned static assetsmax-age=31536000, immutable
stale-while-revalidateServe stale while refreshing in backgroundNon-critical API datamax-age=60, stale-while-revalidate=300

A practical caching strategy for modern web applications follows a simple pattern: cache immutable static assets (JavaScript, CSS, images, fonts with content-hash filenames) aggressively with Cache-Control: public, max-age=31536000, immutable, cache HTML documents conservatively with Cache-Control: no-cache (forcing revalidation on every visit), and cache API responses according to their volatility. The immutable directive is particularly powerful — it tells the browser that the resource will never change during its freshness lifetime, eliminating the revalidation request that browsers typically send when a user refreshes the page. For content-hash filenames (like app.a3f7b2c4.js), this is safe because any change to the content produces a new filename, making the old cache entry irrelevant.

How to Inspect HTTP Headers

Inspecting HTTP headers is an essential skill for debugging web applications, verifying security configurations, and understanding how servers and clients communicate. Every modern browser includes Developer Tools that provide detailed visibility into HTTP traffic, but the level of detail and presentation varies across tools. The most common method is using Chrome DevTools or Firefox Developer Tools: open the Network panel (F12 > Network), reload the page, and click on any request to see both the request and response headers in the Headers tab. Chrome DevTools displays headers grouped by category (General, Request Headers, Response Headers), and you can toggle between parsed and raw views. Firefox provides similar functionality with a slightly different layout, and includes a "Headers" tab that shows both sent and received headers with color-coded security indicators.

Step 1: Open Browser DevTools

Press F12 (or right-click → Inspect) and navigate to the Network tab. Reload the page to capture fresh requests — you will see a list of every HTTP request made by the page.

Step 2: Select a Request

Click on any request in the Network panel to view its details. The Headers tab shows both request headers (sent by the browser) and response headers (sent by the server) in organized sections.

Step 3: Check Security Headers

Look for critical security headers in the response: Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, and X-Frame-Options. If any are missing, your site may be vulnerable to XSS, clickjacking, or MITM attacks.

Step 4: Use curl for Quick Checks

Run curl -I https://example.com in your terminal to see response headers instantly, or use curl -v for the full request and response including TLS handshake details.

Step 5: Scan with Online Tools

Paste your URL into securityheaders.com or observatory.mozilla.org for a comprehensive security header audit with grades and specific recommendations for improvement.

For more advanced inspection, command-line tools offer greater flexibility and scripting capability. curl is the most widely used tool for HTTP debugging — curl -v https://example.com shows the full request and response headers along with the TLS handshake details. The -I flag sends a HEAD request to see only the response headers without the body, while -H allows you to add custom request headers for testing. httpie (the http command) provides a more user-friendly alternative with syntax highlighting and JSON formatting by default. For analyzing security headers specifically, tools like securityheaders.com (Scott Helme's online scanner) and observatory.mozilla.org (Mozilla Observatory) evaluate your headers against best practices and provide a grade with specific recommendations. These tools are invaluable for verifying that your security headers are correctly configured and that no headers are missing.

For programmatic inspection, you can use server-side logging, network monitoring tools, and browser extensions. On the server side, most web frameworks provide middleware for logging request headers — Express.js has morgan, Django has django-extensions, and Go's net/http package allows direct header inspection via r.Header. Network monitoring tools like Wireshark capture raw TCP traffic including HTTP headers, which is useful for debugging at the network layer. Browser extensions like HTTP Header Live (Firefox) and ModHeader (Chrome) allow real-time header inspection and modification, which is particularly useful for testing CORS configurations and authentication flows. Whichever method you choose, make header inspection a regular part of your development workflow — catching misconfigured headers early prevents security vulnerabilities and performance problems in production.

Inspect HTTP Headers

Check any website's headers for security, caching, and CORS configuration in seconds.

Try It Free →

Try HTTP Header Checker

Inspect HTTP request and response headers for any URL — check security, caching, and CORS configuration.

Use Tool

Frequently Asked Questions

Cookie Preferences

We use essential cookies for authentication and security. On blog pages, Google AdSense may set advertising cookies for free-tier visitors to show relevant ads. You can manage your preferences below.