IIS Request Filtering: Limits, Hidden Segments, and Logging Rejections

By the time a request reaches an ASP.NET worker process it has already consumed threads, memory, and possibly a database connection. IIS Request Filtering runs earlier in the pipeline and rejects malformed or hostile requests before the application pays for them. It is not a replacement for a WAF, but it removes an entire class of noise — oversized headers, path traversal attempts, forbidden verbs — at near-zero CPU cost. This article covers the concrete limits to set, how they interact with web.config, and how to log rejections so tuning is evidence-based. The configuration applies to any IIS host, so pick a plan with headroom on the Windows VPS server comparison before you baseline it under load.

Why Filter Early

A worker thread handling a 2 MB POST that will fail model validation is wasted. Under a burst — a scanner, a misconfigured client, or a small DoS — those wasted threads are what push response times up for legitimate users. Request Filtering rejects at the HTTP.sys layer for the cheapest checks and at the URL authorization stage for the rest, keeping the ASP.NET thread pool clean.

The Limits That Matter

SettingDefaultRecommended for typical web appsAttack it blocks
maxAllowedContentLength28.6 MBSet per route: 4–10 MBLarge-body floods, filler uploads
maxUrl40961024Long-URL buffer abuse
maxQueryString2048512Query-string floods
Max header size16 KB8 KBHeader padding
allowDoubleEscapingfalsefalse (keep)Encoded traversal (%2e%2e)
verbs allowedallGET, HEAD, POST (+PUT/DELETE only where needed)odd verb probing

Applying Limits in web.config

Put content-length limits where they do not break legitimate uploads. Set a strict global maxAllowedContentLength in the requestFiltering section, then override it for a specific upload path using a location tag:

<requestLimits maxAllowedContentLength="4194304" /> caps every request at 4 MB. For the one route that accepts documents, add <location path="api/upload"> with a larger limit and a matching authorization rule so the exemption is not open to anonymous users.

Remember that maxAllowedContentLength (IIS/HTTP.sys, in bytes) and ASP.NET Core’s MultipartBodyLengthLimit are separate knobs. Set both, or the lower one silently wins and produces a confusing 413.

Blocking Hidden Segments and Extensions

  • Add web.config, .git, .env, and App_Data to Hidden Segments so they return 404 even if deployed by mistake.
  • Deny extension list should include .bak, .config, .log, and any source-map or editor backup pattern your build emits.
  • Keep allowDoubleEscaping=false — enabling it is a common misconfiguration that reopens traversal.

Logging Rejections

Rejections land as HTTP 404.13 (content length), 404.14 (URL too long), 404.15 (query string too long), and 404.5 (URL sequence denied). Enable failed-request tracing or simply parse the IIS access log for those substatus codes. A sudden rise in 404.14 usually means an application is generating pathological URLs, not that you are under attack — the log tells you which.

SubstatusMeaningTypical trigger
404.5URL sequence deniedPath traversal attempt
404.7File extension deniedRequest for .config or .bak
404.8Hidden namespaceRequest for web.config or App_Data
404.13Content length too largeOversized upload
404.14URL too longRunaway generated URLs
404.15Query string too longMalformed client request

Deny Rules vs Allow Rules

Request Filtering is deny-by-default for the hidden-segments and forbidden-sequence lists, but permissive for verbs and extensions unless you act. Two habits keep the surface small:

  • Deny the verbs you do not use — TRACE, TRACK, DEBUG, and OPTIONS if CORS is handled at the app layer. TRACK is a legacy cross-site tracing vector.
  • Allow extensions explicitly rather than blocking bad ones. An allowlist survives new attack files; a denylist does not.

Tuning Without Breaking Clients

Roll limits out in report-only mode first if you are unsure: set generous values, watch the logs for a week, then tighten. Aggressive limits applied blindly break legitimate integrations — GraphQL, rich-text editors, and mobile SDKs are frequent offenders. After tightening, re-test your largest real payload and a query string at your new ceiling. A dashboard that sends a 600-character filter string, for instance, will fail the moment you drop maxQueryString to 512 without checking.

Where It Fits in the Stack

Request Filtering handles cheap syntactic rejection at the earliest point in the pipeline. It is not a WAF: it does not understand SQL injection semantics, encoded XSS payloads inside a well-formed body, or behavioral anomalies. Pair it with application-level validation, a signature-or-heuristic WAF for payload inspection, and network controls for volumetric attacks. Each layer stays simple because each does one job.

The practical value is resource protection. On a small VPS every rejected oversized request is a worker thread, a buffer, and often a database call that never happens. That headroom is what keeps legitimate traffic fast during a scanner sweep. Once the rules are stable, confirm the host is not the bottleneck under your real request profile — the specs and price tiers are listed on the Windows VPS provider comparison.

Leave a Comment