|
| 1 | +--- |
| 2 | +title: Glossary |
| 3 | +layout: wide |
| 4 | +toc: true |
| 5 | +--- |
| 6 | + |
| 7 | +## What is an RFC? |
| 8 | + |
| 9 | +An **RFC** (Request for Comments) is a formal document published by the [Internet Engineering Task Force (IETF)](https://www.ietf.org/) that defines the standards and protocols that power the internet. Despite the informal-sounding name, RFCs are the authoritative specifications that all implementations must follow for interoperability. |
| 10 | + |
| 11 | +HTTP/1.1 is defined by two key RFCs: |
| 12 | + |
| 13 | +- **[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110)** — *HTTP Semantics*. Defines the meaning of HTTP methods, status codes, headers, and content negotiation. This is the "what" of HTTP. |
| 14 | +- **[RFC 9112](https://www.rfc-editor.org/rfc/rfc9112)** — *HTTP/1.1 Message Syntax and Routing*. Defines the wire format: how requests and responses are framed as bytes on a TCP connection. This is the "how" of HTTP/1.1. |
| 15 | + |
| 16 | +RFCs use specific keywords defined in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119): |
| 17 | + |
| 18 | +| Keyword | Meaning | |
| 19 | +|---------|---------| |
| 20 | +| **MUST** | Absolute requirement. Violating this means the implementation is non-compliant. | |
| 21 | +| **MUST NOT** | Absolute prohibition. | |
| 22 | +| **SHOULD** | Recommended but there may be valid reasons to deviate in particular circumstances. | |
| 23 | +| **MAY** | Optional behavior. | |
| 24 | + |
| 25 | +When a test in Http11Probe references `RFC 9112 §5.1`, it means the test validates a specific requirement from section 5.1 of that document. |
| 26 | + |
| 27 | +## What is HTTP Request Smuggling? |
| 28 | + |
| 29 | +HTTP request smuggling is an attack that exploits disagreements between HTTP processors about where one request ends and the next begins in a TCP byte stream. |
| 30 | + |
| 31 | +### How it works |
| 32 | + |
| 33 | +In a typical web architecture, requests flow through multiple layers: |
| 34 | + |
| 35 | +``` |
| 36 | +Client --> CDN / Load Balancer --> Application Server |
| 37 | + (front-end) (back-end) |
| 38 | +``` |
| 39 | + |
| 40 | +Both the front-end and back-end must parse the HTTP stream to determine request boundaries. HTTP/1.1 provides two mechanisms for this: |
| 41 | + |
| 42 | +1. **Content-Length** — an explicit byte count of the body |
| 43 | +2. **Transfer-Encoding: chunked** — the body is sent in length-prefixed chunks |
| 44 | + |
| 45 | +When a request contains **both** headers, or contains them in ambiguous forms, different servers may disagree on the body length. This disagreement lets an attacker hide a second request inside the body of the first. |
| 46 | + |
| 47 | +### CL.TE Smuggling Example |
| 48 | + |
| 49 | +The attacker sends a request where the front-end uses `Content-Length` and the back-end uses `Transfer-Encoding`: |
| 50 | + |
| 51 | +```http |
| 52 | +POST / HTTP/1.1 |
| 53 | +Host: example.com |
| 54 | +Content-Length: 13 |
| 55 | +Transfer-Encoding: chunked |
| 56 | +
|
| 57 | +0\r\n |
| 58 | +\r\n |
| 59 | +SMUGGLED |
| 60 | +``` |
| 61 | + |
| 62 | +**Front-end** (reads Content-Length: 13): sees 13 bytes of body (`0\r\n\r\nSMUGGLED`), forwards the whole thing as one request. |
| 63 | + |
| 64 | +**Back-end** (reads Transfer-Encoding: chunked): reads chunk size `0`, which signals end-of-body. The remaining bytes (`SMUGGLED`) are left in the TCP buffer and interpreted as the **start of the next request**. |
| 65 | + |
| 66 | +The attacker has now injected a request that bypasses the front-end entirely. |
| 67 | + |
| 68 | +### TE.CL Smuggling Example |
| 69 | + |
| 70 | +The reverse: the front-end uses `Transfer-Encoding` and the back-end uses `Content-Length`: |
| 71 | + |
| 72 | +```http |
| 73 | +POST / HTTP/1.1 |
| 74 | +Host: example.com |
| 75 | +Content-Length: 3 |
| 76 | +Transfer-Encoding: chunked |
| 77 | +
|
| 78 | +8\r\n |
| 79 | +SMUGGLED\r\n |
| 80 | +0\r\n |
| 81 | +\r\n |
| 82 | +``` |
| 83 | + |
| 84 | +**Front-end** (chunked): reads chunk of size 8 (`SMUGGLED`), then chunk of size 0 (end). Forwards everything. |
| 85 | + |
| 86 | +**Back-end** (Content-Length: 3): reads only 3 bytes of body (`8\r\n`). The rest (`SMUGGLED\r\n0\r\n\r\n`) becomes the next request. |
| 87 | + |
| 88 | +### Why servers must reject ambiguous requests |
| 89 | + |
| 90 | +The only safe behavior is to **reject** any request with ambiguous framing: |
| 91 | + |
| 92 | +- Both `Content-Length` and `Transfer-Encoding` present → **400** |
| 93 | +- Duplicate `Content-Length` with different values → **400** |
| 94 | +- Obfuscated `Transfer-Encoding` (e.g. `xchunked`, `chunked `) → **400** |
| 95 | + |
| 96 | +A server that "guesses" which header to use is a smuggling vector waiting to happen. |
| 97 | + |
| 98 | +### Real-world impact |
| 99 | + |
| 100 | +HTTP smuggling has been used to: |
| 101 | +- **Bypass authentication** — smuggle requests that skip WAF/auth layers |
| 102 | +- **Poison web caches** — inject responses that get cached and served to other users |
| 103 | +- **Hijack sessions** — prepend attacker-controlled headers to other users' requests |
| 104 | +- **Exfiltrate data** — redirect internal responses to attacker-controlled endpoints |
| 105 | + |
| 106 | +## Test Definitions |
| 107 | + |
| 108 | +Every test ID links back here from the result tables. Click a test name in any results table to jump to its definition. |
| 109 | + |
| 110 | +<div id="glossary-tests"><p><em>Loading...</em></p></div> |
| 111 | + |
| 112 | +<script src="/Http11Probe/probe/data.js"></script> |
| 113 | +<script src="/Http11Probe/probe/render.js"></script> |
| 114 | +<script> |
| 115 | +(function () { |
| 116 | + if (!window.PROBE_DATA) { |
| 117 | + document.getElementById('glossary-tests').innerHTML = '<p><em>No probe data available yet.</em></p>'; |
| 118 | + return; |
| 119 | + } |
| 120 | + var ctx = ProbeRender.buildLookups(window.PROBE_DATA.servers); |
| 121 | + var names = ctx.names, lookup = ctx.lookup, testIds = ctx.testIds; |
| 122 | + |
| 123 | + var categories = [ |
| 124 | + { key: 'Compliance', title: 'Compliance Tests' }, |
| 125 | + { key: 'Smuggling', title: 'Smuggling Tests' }, |
| 126 | + { key: 'MalformedInput', title: 'Malformed Input Tests' } |
| 127 | + ]; |
| 128 | + |
| 129 | + var html = ''; |
| 130 | + categories.forEach(function (cat) { |
| 131 | + var tests = testIds.filter(function (tid) { |
| 132 | + return lookup[names[0]][tid] && lookup[names[0]][tid].category === cat.key; |
| 133 | + }); |
| 134 | + if (tests.length === 0) return; |
| 135 | + |
| 136 | + var scored = tests.filter(function (tid) { return lookup[names[0]][tid].scored !== false; }); |
| 137 | + var unscored = tests.filter(function (tid) { return lookup[names[0]][tid].scored === false; }); |
| 138 | + |
| 139 | + html += '<h3>' + cat.title + '</h3>'; |
| 140 | + html += '<div style="margin-bottom:1.5rem;">'; |
| 141 | + |
| 142 | + function row(tid) { |
| 143 | + var r = lookup[names[0]][tid]; |
| 144 | + if (!r) return ''; |
| 145 | + var rfc = r.rfc ? ' <span style="color:#656d76;font-size:11px;">(' + r.rfc + ')</span>' : ''; |
| 146 | + return '<div id="test-' + tid + '" style="display:flex;gap:8px;align-items:baseline;padding:6px 0;border-bottom:1px solid #f0f0f0;">' |
| 147 | + + '<div style="min-width:260px;"><code style="font-size:12px;">' + tid + '</code>' + rfc + '</div>' |
| 148 | + + '<div style="min-width:60px;text-align:center;">' + ProbeRender.pill(ProbeRender.EXPECT_BG, r.expected) + '</div>' |
| 149 | + + '<div style="flex:1;font-size:13px;">' + r.reason + '</div>' |
| 150 | + + '</div>'; |
| 151 | + } |
| 152 | + |
| 153 | + scored.forEach(function (tid) { html += row(tid); }); |
| 154 | + if (unscored.length > 0) { |
| 155 | + html += '<div style="padding:8px 0;font-weight:700;font-size:12px;color:#656d76;border-bottom:1px solid #d0d7de;margin-top:4px;">Not scored (RFC-compliant behavior)</div>'; |
| 156 | + unscored.forEach(function (tid) { html += row(tid); }); |
| 157 | + } |
| 158 | + html += '</div>'; |
| 159 | + }); |
| 160 | + |
| 161 | + document.getElementById('glossary-tests').innerHTML = html; |
| 162 | +})(); |
| 163 | +</script> |
0 commit comments