# Bridge WAF — full text Every published page of bridge-waf.com, in build order. Generated from the same sources as the site. --- https://bridge-waf.com/ --- # Bridge WAF A firewall you can watch before you let it refuse anything. Bridge WAF has three modes and nothing hidden between them: `off`, `monitor`, and `block`. Monitor mode records what would have been refused, against your real traffic, so the decision to enforce is made with evidence rather than hope. ## The three modes A mode is the whole configuration surface. There are three of them, they mean exactly what their names say, and there is nothing else to set. **`off`.** Inspection does not run. Nothing is examined, nothing is recorded, and traffic reaches your origin as it otherwise would. **`monitor`.** Requests are inspected and matches are recorded, and nothing is refused. This is the mode that answers the question every security change should start from: what would this have done to my traffic last week? **`block`.** Requests that match are refused rather than forwarded, and they continue to be recorded. The order matters more than the list. Turning enforcement on without having watched first means discovering the false positives from customers, which is the most expensive way available to learn what a rule does. ## Watch before you enforce Monitor mode exists because a firewall's real risk is not the traffic it misses. It is the traffic it refuses that should have been served. Every filtering decision has two failure modes, and they are not symmetrical. Missing an attack is a problem you can usually see, measure, and respond to. Refusing a customer is a problem that reports itself through nobody: the person leaves, assumes the site is broken, and does not come back to explain. A rule set that has never been observed against real traffic is a set of guesses about which of those you are choosing. Running in monitor first converts that guess into a list. You see which of your own requests would have been caught, which integrations would have broken, and whether the pattern you were worried about actually appears in your traffic at all. ## Rate limiting per domain Rate limiting is applied per domain, which is the unit the limits are defined and counted against. This is worth stating precisely, because rate limiting is described in many different granularities elsewhere and the difference decides how you use it. Limits here belong to a domain rather than being derived from something about individual callers, so the question to answer before setting one is what volume the domain as a whole should be prepared to accept. The general subject, including why limits set per client behave differently from limits set elsewhere and what over-limiting costs you, is covered in the documentation on [application-layer attacks](/attacks/application/). ## The activity log Flagged requests appear in a security activity log close to the moment they are flagged: entries are delivered in batches, with sub-second latency. Two things follow from that, and the second is the more useful. The first is that monitor mode is worth running because you can actually read the result while it is still relevant, rather than reviewing yesterday. The second is what the log is for: it records requests the firewall flagged. It is therefore not a traffic overview, not a view of volumetric attack statistics, and not a general analytics surface. Those are different questions with different answers, and a log that tried to be all of them would be worse at the one thing this is for. ## What there is no setting for Deliberately, and it is a design position rather than an omission. There is no numeric level to raise or lower, no aggressiveness score to trust, and no dial whose meaning is left for you to infer. The configuration is the three modes above. This makes the system less adjustable and considerably more predictable, and it removes the class of change where somebody moves a control by one step and nobody can say what that changed. ## What this is not Three handoffs, stated so that nobody discovers them later. **Bot and AI-agent delivery is a different layer.** Serving prerendered content to crawlers and AI agents is what [BotBridge](https://botbridge.io/) does, and it is a delivery question rather than a filtering one. This page does not restate that story. **Volumetric attacks are not stopped here.** Traffic that saturates a link never becomes a request, so nothing at this layer can examine it. The distinction, and what does address each family, is set out on [attack layers](/attacks/layers/). **Caching, naming, and certificates belong elsewhere.** Each is its own subject with its own failure modes, handled by the neighbouring layers of the network. ## Understand what you are filtering This documentation is useful whether or not you ever become a customer, which is the only reason worth writing it. - **[DDoS attack types](/attacks/)** sorts attacks by what they exhaust: the link, the tables that track connections, or the application itself. Each family has a different answer, and only one of them is a firewall. - **[Malicious bots](/bots/)** covers scrapers, credential stuffing, spam submissions, and the detection signals people rely on, including what each signal costs when it is wrong. ## How this is priced The firewall layer is included with Bridge CDN rather than sold separately, so there is no separate plan to choose and nothing to add. Current terms live where signup does, at [Bridge CDN](https://bridge-cdn.com/). ## Who runs this, and how to start Bridge WAF is the filtering layer of the BotBridge network, which covers the infrastructure between a visitor and a server: naming, delivery, certificates, and traffic filtering. Filtering is part of serving your site, so setting it up means setting up delivery. Everything starts at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What do the three modes do?** `off` runs no inspection at all. `monitor` inspects requests and records what matched without refusing anything. `block` refuses matching requests and keeps recording them. That is the entire configuration surface, so there is no fourth state and nothing to calibrate between the three. **Why start in monitor mode?** Because the expensive mistake is refusing a customer, not missing an attack. A missed attack is visible and can be answered; a refused customer leaves silently, assumes the site is broken, and does not come back to explain. Monitor mode turns that risk into a list you can read first. **What granularity does rate limiting use?** Limits are applied per domain, which is the unit they are counted against. That is worth checking against your expectations, because rate limiting is described at several different granularities elsewhere, and the granularity decides what question you should be answering when you set a limit. **How quickly do flagged requests appear?** Close to immediately. Entries are delivered in batches with sub-second latency, which is what makes monitor mode practical rather than academic: you can read the result while the traffic that produced it is still current, instead of reviewing a report about what happened yesterday. **Is the activity log a view of attack statistics?** No. It records requests the firewall flagged, which is a different question from how much traffic arrived or where it came from. Volumetric attack figures and general traffic analytics are separate surfaces, and a log attempting to serve all three would serve each of them badly. **Does this handle search crawlers and AI agents?** No, and that is deliberate. Delivering content to crawlers and AI agents is a delivery problem rather than a filtering one, and it belongs to BotBridge rather than here. Keeping the two apart is why neither has to compromise about what it treats as unwanted traffic. --- https://bridge-waf.com/attacks/ --- # DDoS attack types: the complete map Denial-of-service attacks divide into three families by what they exhaust: your bandwidth, your connection state, or your application. The distinction is not academic. Each family is stopped at a different layer, by different equipment, and an answer that works against one is useless against another. ## The three families **Volumetric attacks** fill the pipe. They send more traffic than the connection can carry, and the traffic itself is often meaningless: what matters is its volume in bits per second. Because the link saturates before anything reaches your server, nothing running on the server can help. **Protocol attacks** exhaust state rather than bandwidth. Every connection a server, firewall, or load balancer tracks occupies a table entry, and those tables are finite. An attack that opens connections and never completes them fills the table with entries that will never be used, leaving no room for real ones. Traffic volume can stay modest. **Application attacks** exhaust the application. Requests are valid, arrive over a completed connection, and ask for something expensive: a search, a report, a page that hits the database several times. Volume in bits per second is unremarkable. What is remarkable is cost per request. A fourth category is cross-cutting rather than technical: attacks accompanied by an extortion demand, covered on [ransom DDoS](/attacks/ransom-ddos/), because the response there is a set of decisions, and configuration plays little part. ## Which layer stops which | Family | Exhausts | Measured in | Stopped by | |---|---|---|---| | [Volumetric](/attacks/volumetric/) | Link capacity | Bits per second | Upstream capacity and scrubbing | | [Protocol](/attacks/protocol/) | Connection state | Packets per second | Network stack tuning, stateless filtering upstream | | [Application](/attacks/application/) | Backend resources | Requests per second | Rate limiting and layer 7 filtering | The row that matters most is the first, and it is the one most often misread. A web application firewall inspects requests, which means a request must arrive before it can be inspected. When the link is already saturated, the firewall never sees the traffic that is causing the problem, because that traffic did not need to reach it in order to succeed. This single fact reorganises how the rest of the material is arranged, and it is set out in full on [attack layers](/attacks/layers/), the place to start before choosing any defence. ## How to tell which one you are seeing The symptoms overlap enough that guessing is common, and three checks separate them quickly. **Look at where the failure appears.** If the site is unreachable and your own outbound connections from the same network are slow, the link is saturated and the problem is upstream. If the server is reachable but refuses new connections while showing low processor usage, state is exhausted. If the server is busy, processing requests, and simply cannot keep up, the attack is at the application. **Compare bandwidth against request count.** A large amount of traffic carrying few requests points to the first family. A modest amount of traffic carrying many expensive requests points to the third. **Check whether the traffic is well formed.** Volumetric and protocol attacks frequently involve packets that no legitimate client would send. Application attacks look like ordinary requests, because that is what they are, which is why they are the hardest to separate from real users. ## Why the categories decide your response Each family is handled by a different party, and knowing which one you face tells you who to call. Volumetric traffic must be absorbed or filtered before it reaches your link, which makes it a matter for whoever provides that link or for a provider with capacity to spare. Nothing you configure on the server changes the outcome. Protocol attacks are addressed partly by the network stack, through mechanisms designed to hold minimal state until a connection proves itself, and partly by filtering upstream. Some of this is tuning you control. Application attacks are where request inspection earns its place. Requests arrive complete, they can be examined, and decisions can be made per request: rate limits by client and endpoint, challenges for suspect clients, and rules that recognise abusive patterns. ## Before you classify anything Classification is a decision aid, not a first step. During an incident the order that helps is narrower. **Confirm the failure from outside your own network.** A site that is unreachable from one office and fine from elsewhere is a different problem from one that is unreachable everywhere, and the two get confused constantly. **Ask upstream whether the link is saturated.** This single answer decides whether anything you do on the server can matter, and it comes from whoever provides your connectivity rather than from your own graphs, which stop being delivered once the link is full. **Capture what you have before changing anything.** Connection counts, request rates, and a sample of the traffic. Mitigation changes the evidence by design, and reconstructing what happened afterwards is far harder than saving a few minutes of counters now. **Resist broad blocks made under pressure.** Blocking a country or a large network stops the attack and stops customers with it, and blocks added during an incident are the ones nobody remembers to remove. Narrow measures that expire beat wide ones that persist. ## What the categories do not tell you Two limits, because taxonomies invite more confidence than they deserve. Real incidents frequently combine families. A volumetric flood that saturates the link while an application flood exhausts the backend is one event from the outside and two problems to solve. Classifying an attack is useful for choosing defences, not for describing what happened. And the categories say nothing about intent. The same technique appears in extortion, in competitive sabotage, and in traffic that is not an attack at all: a misconfigured client retrying without limit produces a pattern indistinguishable from a small flood, and the response differs entirely. ## Mitigation, honestly stated The defences that matter are layered, and no single product covers all three families. Capacity and upstream filtering handle what saturates links. Network stack behaviour and stateless filtering handle what exhausts state. Request inspection and rate limiting handle what exhausts the application. A provider that terminates traffic on your behalf can supply the first and the third; the second sits partly with your own configuration. Bridge WAF filters at the application layer: requests are inspected before they reach your origin, rate limiting is applied per domain, and abusive patterns are blocked without a rule for every variation. What that does not do is stop traffic that saturates a link before it arrives, and any product claiming otherwise is describing a different layer than the one it operates on. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What are the main types of DDoS attack?** Three families, distinguished by what they exhaust: volumetric attacks fill the link, protocol attacks exhaust the tables devices use to track connections, and application attacks exhaust the backend with requests that are individually valid. The resource under pressure decides which defence applies. **Does a WAF stop all DDoS attacks?** No, and any claim otherwise is describing a bundle of services rather than request inspection. A web application firewall works on complete requests, so traffic that saturates the link never reaches the layer where it could be examined at all. **How do I know which type is hitting me?** Compare bandwidth against request count, then look at how the failure presents. Unreachable points at the link, refusing connections points at connection state, and reachable but overloaded points at the application. Those three symptoms map cleanly onto the three families. **Which type is hardest to defend against?** Application attacks, because every individual request is valid and indistinguishable from one a real customer might send. There is no malformed packet to discard and no threshold that is obviously wrong, so defence becomes a question of rate and behaviour rather than of correctness. **Can one attack be more than one type?** Yes, and combined events are common enough that classification is a diagnostic aid rather than a category. This is the practical argument for layered defences: whichever family you prepared for, the one you did not prepare for can arrive alongside it. **Is a small flood always an attack?** No, and assuming otherwise causes real damage. A misconfigured client retrying without limit, or a partner integration in a loop, produces exactly the same pattern with no intent behind it. That is one reason blocking decisions deserve a look before they become permanent. --- https://bridge-waf.com/bots/ --- # Malicious bots: what actually needs blocking Automated traffic is not one thing, and treating it as one is the most common mistake here. Some automation is why your site appears in search results and why your monitoring wakes you at night. Other automation copies your content, tries stolen passwords, or takes your inventory. The useful question is never whether traffic is automated, but what it costs. ## Where the line runs Three properties separate harmful automation from the rest, and none of them is "it is a bot". **It takes something.** Content, inventory, data, advertising budget, or the ability of real customers to be served. **It hides what it is.** Legitimate automation identifies itself and can be verified. Harmful automation copies browser characteristics precisely because being recognised would end it. **It ignores what you asked.** Instructions about which parts of your site may be crawled are followed by the automation that respects them, which is the automation that was never a problem. Automation that identifies itself, is verifiable, and behaves within limits is a different subject with a different answer. The catalogue of that kind, including the crawlers that read sites for search and answer engines, is maintained at [BotBridge](https://botbridge.io/). ## The taxonomy | Type | What it does | What it costs | |---|---|---| | Content scrapers | Copy pages at scale | Duplicated content, load, competitive exposure | | Spam bots | Submit forms and comments | Moderation effort, reputation, mail deliverability | | Credential stuffing | Try leaked passwords against accounts | Compromised accounts, support load | | Account takeover automation | Operate accounts once inside | Fraud losses, customer trust | | Scalpers | Buy or hold limited inventory | Lost sales, angry customers | | Click fraud | Generate advertising clicks | Advertising budget | | Botnets | Provide distributed capacity for other attacks | Availability | | Fake search crawlers | Impersonate verified crawlers | Access to what you allow crawlers | | Carding automation | Test stolen payment cards | Processor penalties, fees | | Vulnerability scanners | Search for known weaknesses | Reconnaissance against you | Each type has its own signals and its own cost of being wrong, which is why they are documented separately. ## Why detection is probabilistic Accept this first: it decides which methods are appropriate. Nothing in a request proves it came from a person. Every characteristic a browser announces can be reproduced, every timing pattern can be varied, and every source address can be changed. What remains is evidence rather than proof: behaviour across many requests, consistency between what a client claims and how it acts, and whether a source has a history. The consequence is that decisions are made under uncertainty. A method's value is therefore not only how much automation it identifies, but what it costs when it is wrong, and those two frequently point in opposite directions. ## The cost of being wrong Every blocking decision has a failure mode on each side, and they are not symmetrical. **Blocking a customer** loses a sale and, more expensively, a person who now believes your site is broken. They do not file a report. They leave, and nothing in your logs records what did not happen. **Blocking legitimate automation** is quieter and often worse. Search crawlers stop indexing, monitoring stops reporting, payment callbacks stop arriving, and integrations partners depend on fail silently. Each of these surfaces days or weeks later, disconnected from the change that caused it. **Allowing harmful automation** costs whatever that type takes, which is usually gradual rather than catastrophic. The asymmetry explains the shape of every recommendation in this material: prefer measures that ask rather than refuse, prefer measures that expire, and know what legitimate automation calls you before enforcing anything. ## Before you block anything Two pieces of preparation make everything afterwards safer. **Inventory your own automation.** Monitoring, uptime checks, payment callbacks, partner integrations, internal jobs, and anything a colleague built years ago. Each looks exactly like the traffic you are about to block: no browser, no session, regular timing. **Give expected automation identity.** A credential or a key ties access to a known party, which survives address changes and lets you exempt it deliberately rather than by accident. Guessing from addresses fails the first time a provider renumbers. ## Where the damage actually appears Bot traffic rarely announces itself as an availability problem, which is why it runs for a long time before anyone investigates. **In your costs.** Bandwidth, database load, and capacity provisioned for traffic that never buys anything. The bill grows smoothly, so it reads as success rather than as a problem. **In your data.** Analytics that include automation describe a customer base that does not exist. Decisions get made on those numbers, which makes this the most expensive quiet failure in the list. **In your customers' experience.** Inventory that is never available, forms full of spam, and accounts whose owners are locked out. None of these appears in an uptime graph, and all of them are visible to the people you depend on. That is the argument for treating this as ordinary operational work rather than as an incident response. The costs accumulate instead of arriving. ## Methods, ordered by what they cost when wrong **Instructions for well-behaved automation** are a courtesy, not a control: they work only for automation that chooses to read them. Useful for managing load from cooperative crawlers, worthless against anything hostile. **Identification by what a client claims to be** is trivially bypassed, since the claim is set by the client. It removes lazy automation and nothing else. **Reputation of the source** carries useful signal and misfires on shared addresses, which is common on mobile networks and behind corporate egress. **Behavioural analysis** looks at what a client does across requests rather than at what it declares, and it is the most reliable signal available, at the cost of needing enough requests to judge. **Challenges** ask the client to do something automation finds expensive, and they are the safest measure at low confidence, because a customer who passes is inconvenienced rather than refused. ## Handling this as part of the stack Bridge WAF takes a narrower slice of this than the list above, and says so: bot classification works on declared identity — the first and weakest of the five signals — and rate limiting is applied per domain. Matches are recorded in the activity log, so monitor mode shows what enforcement would have refused before anything is refused; reputation scoring and behavioural analysis are not part of this layer. What no system removes is the judgement about which automation you want, which is why the inventory above comes first. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What counts as a malicious bot?** Automation that takes something from you, conceals what it is, or ignores limits you published. The distinction is behaviour rather than being automated at all, because most of the automation reaching your site is either yours, a partner's, or something you would be worse off without. **Should I block all bots?** No, and the reason is the failure mode. Search crawlers, monitoring, payment callbacks, and partner integrations are automation you depend on, and when a rule catches them nothing reports it: the callback simply stops arriving and the fault surfaces days later as a business problem. **Can I reliably tell bots from people?** No method proves it, and treating any signal as proof is where most damage begins. Decisions rest on evidence accumulated across many requests, which means every decision carries a probability of being wrong, and the cost of being wrong should shape how forceful the response is. **What is the cheapest first step?** Writing down the automation that legitimately calls you, and giving each entry an identity of its own so it can be exempted deliberately rather than by accident. This costs nothing, has to happen eventually, and is what stops the first enforcement attempt from breaking something. **Do robots instructions stop bad bots?** No. They are a convention honoured only by automation that chooses to honour it, which is precisely the automation you were not worried about. Listing sensitive paths there also announces those paths to anything reading the file for the opposite purpose. **Which measure is safest when uncertain?** A challenge, because its failure mode is survivable. A customer who is challenged and passes has been mildly inconvenienced and is still a customer; a customer who is blocked is gone, usually without ever telling you why, and usually without trying again. --- https://bridge-waf.com/glossary/ --- # WAF glossary: the words behind the rules Four terms that come up in every filtering conversation and have no section of their own here. Each entry answers what the thing is; what to do about it lives in the sections, and every definition points at the right one. ## Terms defined here **Web application firewall** is a layer that inspects requests before they reach an application and decides whether to pass them on. The information question, what one is and what it can and cannot do, is answered on its own page here. **Layer 7** names the level at which requests are meaningful as requests rather than as packets: methods, paths, headers, and bodies. It is the level a request-inspecting layer works at, and the reason it cannot see what never becomes a request. How attacks divide by level is on [attack layers](/attacks/layers/). **Virtual patching** is blocking the traffic that exploits a known weakness while the weakness itself is still there. It buys time rather than fixing anything, and treating it as a fix is where the practice goes wrong. **Zero-day** describes a weakness for which no fix is available yet, from the point of view of whoever has to defend against it. The term says something about the state of the fix, not about how sophisticated the attack is, and an unremarkable technique against an unpatched weakness qualifies just as much as an ingenious one. ## Definitions here, decisions in the sections Keeping those apart is what stops a definition from becoming a bad guide. An entry here tells you what a word means. What attacks look like and how they divide is under [attacks](/attacks/), which rules apply and where they come from under [rules](/rules/), automated traffic under [bots](/bots/), and the question of how to introduce filtering without breaking anybody under [operations](/operations/). A term with a section of its own is not repeated here, which is why this list is short. Everything about denial-of-service traffic belongs to the attacks section, and everything about recognising automation to the bots section. A glossary that duplicated them would compete with the pages that cover them properly, and the reader would land on whichever version the engine happened to prefer. --- https://bridge-waf.com/operations/ --- # How to introduce filtering without breaking anything Turning filtering on takes a moment. Turning it on without refusing your own customers takes a sequence, and the sequence exists because the expensive failure here is silent: somebody legitimate is stopped, does not report it, and the log entry looks exactly like a defence that worked. ## The order that works Three positions, and the value is entirely in not skipping the middle one. **Off.** Nothing is inspected. This is the starting state, and the state to return to if something is badly wrong. **Monitor.** Requests are inspected and matches are recorded, and nothing is refused. Everything you learn about your own traffic is learned here, at no cost to anybody. **Block.** Matching requests are refused rather than forwarded, and they continue to be recorded. Going straight from the first to the third is the mistake this whole section exists to prevent. It means discovering your false positives from customers, which is the slowest and most expensive way available to learn what a rule set does to your particular site. ## What monitor mode is actually for Not for finding attacks. For finding the requests your own site generates that happen to resemble one. That distinction matters because it changes what you look at. Attacks in the record are reassuring and tell you little. The useful entries are the ones you recognise: a search containing text that looks like an injection attempt, a partner integration posting a payload that trips a rule, a support form where customers paste error messages full of code, your own monitoring hitting an endpoint faster than a person would. Read the record asking one question of every entry: would refusing this have been correct? Everything that answers no is work to do before enforcing, and it is invisible from every other vantage point. Run it long enough to include an unusual day. A week of ordinary traffic tells you about ordinary traffic, and the entries that matter often arrive on the day somebody runs a campaign, a partner does a bulk import, or somebody in another timezone starts their working week. ## False positives are the expensive failure Both failure modes are real and they are not symmetrical, which decides everything above. A missed attack is visible eventually. Something happens, you investigate, you respond, and the record helps. A refused customer produces nothing at all: no error report, no support ticket, no entry that reads as a problem. They leave, and your log shows a request that was successfully blocked. That asymmetry means unmeasured filtering drifts in one direction only. It never drifts toward being too permissive, because that failure announces itself; it drifts toward confident, invisible harm, because that one does not. ## Exceptions need an expiry Every specific exception should carry a date on which somebody looks at it again. Exceptions accumulate. Each is added for a good reason during an incident or a launch, and each outlives the circumstance that justified it. After a year nobody remembers which are still needed, and the safe assumption becomes leaving all of them, which is how a filtering layer quietly becomes a list of holes nobody can audit. The rule that works is simple: anything narrow enough to be called an exception is narrow enough to expire. Broad, permanent decisions belong in configuration, where they are visible; narrow ones belong on a review date. ## Tuning without dials There is no scale to slide and no aggressiveness level to raise, and that shapes how tuning works here. The configuration is the three positions above. What you adjust instead is the specific: which rules apply, which requests are exempted, and which limits are set where. That makes tuning slower to think about and far easier to explain, because every change is a statement about something concrete rather than a step on a scale whose meaning nobody can define. The practical consequence is that a tuning change can always be described in a sentence. If it cannot, it is probably not a tuning change. ## What the activity log is and is not It records requests the firewall flagged, with enough context to decide whether the decision was right. It is not a traffic overview, not a view of volumetric attack figures, and not a general analytics surface. Those are separate questions answered by separate things, and a log attempting all three would be worse at the one job that makes monitor mode work. Reading it as a measure of how much traffic you receive will mislead you in both directions. ## After an incident The part that gets skipped, because by then the pressure is off. Emergency measures are taken quickly and correctly under pressure: a broad block, a tight limit, an exemption to unstick something. Every one of them was right for that hour and almost none of them is right permanently. The review afterwards is what separates a system that learned from one that accumulated. Write down what was changed while it was happening, because nobody reconstructs it afterwards. Then decide, for each item, whether it becomes permanent, becomes an exception with a date, or is removed. ## What this section covers The pages below work through each stage: what [monitor mode](/operations/monitor-mode/) shows and how to read it, [turning enforcement on in stages](/operations/staged-rollout/) rather than at once, finding and measuring [false positives](/operations/false-positives/) without switching everything off, [exceptions](/operations/exceptions/) and their expiry dates, what [the activity log](/operations/activity-log/) contains and what it does not, handling [an incident](/operations/incident/) and unwinding it afterwards, and [tuning](/operations/tuning/) when there are no dials to turn. ## Getting started with Bridge WAF Bridge WAF has three modes, `off`, `monitor`, and `block`, and nothing between them. Flagged requests appear in a security activity log in batches with sub-second latency, which is what makes reading the monitor record practical while the traffic that produced it is still current. Rate limiting is applied per domain, covered on [rate limiting](/rate-limiting/). See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **How long should I stay in monitor mode?** Long enough to include an unusual day, which means at least one full business cycle rather than a quiet week. The entries that matter often arrive when somebody runs a campaign, a partner does a bulk import, or another timezone starts work. **What should I look for in the monitor record?** Not attacks. Look for requests you recognise as your own: searches containing code-like text, partner integrations, support forms where people paste error messages, your own monitoring. Ask of each whether refusing it would have been correct, and fix everything that answers no. **Why do exceptions need expiry dates?** Because they accumulate and nobody removes them. Each is added for a good reason and outlives it, and after a year the safe assumption becomes keeping all of them. A review date turns that into a decision somebody makes rather than a default nobody notices. **How do I tune filtering when there is no dial to turn?** By changing specifics rather than a scale: which rules apply, what is exempted, and where limits sit. It is slower to think about and much easier to explain, because every change describes something concrete instead of a step on a scale whose meaning nobody can define. **What do I do after an incident?** Write down what was changed while it was happening, since nobody reconstructs it later. Then decide per item whether it becomes permanent, becomes an exception with a review date, or is removed. Skipping this is how emergency measures become architecture. --- https://bridge-waf.com/rate-limiting/ --- # Rate limiting explained: what it protects and what it breaks A rate limit refuses traffic deliberately, which means the only question that matters is whether it refuses the right traffic. Everything difficult about the subject follows from that: the mechanism is simple, and every hard decision is about who gets counted, over what period, and what happens to somebody the count was wrong about. ## What a rate limit actually does It counts requests against something and refuses them past a threshold. That is the whole mechanism, and its simplicity is misleading, because a limit does not distinguish between traffic you wanted to stop and traffic that merely resembles it. This makes rate limiting different from every other filtering decision on this site. A rule that matches malformed input refuses something that was already wrong. A rate limit refuses requests that are individually perfectly valid, on the grounds that there have been too many of them, and "too many" is a judgement you made in advance about circumstances you had not seen yet. ## The four decisions behind any limit Every limit answers these, whether deliberately or by accident. **What is counted.** Requests are the obvious unit and often the wrong one, because they differ enormously in what they cost you to answer. A hundred cached pages and a hundred searches are the same number and not remotely the same load. **Against what subject.** An address, an account, a credential, or the domain as a whole. This choice decides who suffers when the limit is wrong, and it is the decision people give least thought to. **Over what window.** A minute, an hour, a day, and whether the count resets abruptly or slides. The window shapes what ordinary use looks like to the counter. **What happens at the threshold.** Refusal, delay, or a reduced response. These are not interchangeable, and the difference decides whether a misjudged limit costs you a complaint or a customer. ## Why counting by address misleads The most common subject is the least reliable one, and the reason is structural rather than technical. A single address routinely carries an entire office, a mobile network's users, a school, or a university. Limiting by address means those people share a budget none of them knows about, and the busiest of them exhausts it for everybody else. Meanwhile anything with a reason to avoid the limit moves between addresses freely, because addresses are cheap and plentiful to whoever is deliberately spreading traffic. The result is a control that constrains your customers reliably and its intended target barely. Where identity is available, counting against a credential or an account is both fairer and harder to evade, and where it is not, the limit should be set expecting the sharing. ## Why a flat limit breaks ordinary clients Real traffic is not evenly spaced, and a limit that assumes it is refuses people behaving normally. A page load fetches many things at once. A person returning after lunch opens six tabs. An integration wakes on a schedule and does its work in a burst, then sleeps. Each is ordinary, and each looks identical to a counter watching a narrow window. A limit tight enough to catch abuse in that window is tight enough to catch all three. The usual answer is to allow a short burst above the sustained rate, which matches how genuine clients behave without raising the long-run ceiling. ## Telling the client what happened A refusal that explains itself is answered correctly; a refusal that does not is retried immediately. The status code exists to say that the limit, rather than the request, is the problem, and a well-behaved client treats it differently from an error. Alongside it, telling the client when to come back is what turns a retry storm into a pause. Without that, a client with nothing to go on assumes the fastest reasonable thing, which is to try again at once, and the refusals you are issuing become load of their own. ## Before you turn one on Three steps, in order, and the first is the one that gets skipped. **Watch before enforcing.** Record what the limit would have refused against real traffic for long enough to include a quiet day and a busy one. This is the same argument the whole filtering layer rests on, and it applies more sharply here because the traffic being refused is valid. **List your own automation first.** Monitoring, deployment tooling, partner integrations, and scheduled jobs all look like abuse to a counter. Exempting them by credential rather than by address is what keeps the exemption working after infrastructure changes. **Decide what a wrong decision costs.** If refusing a genuine customer is expensive and missing some abuse is not, the limit belongs looser than instinct suggests, and the response belongs gentler than refusal. ## What this section covers The pages below take each decision apart: the counting algorithms and how they differ in behaviour rather than in name, the status codes a blocked client actually sees, limits set per endpoint according to what each costs, the choice between address, account and credential, bursts and smoothing, telling a client when to return, which state to expose in headers and which to withhold, exempting your own automation safely, testing a limit without taking down your own service, what to watch after enforcing, and why counters on separate nodes disagree. ## Rate limiting with Bridge WAF Bridge WAF applies rate limiting per domain, which is the unit limits are defined and counted against. That granularity is worth checking against your expectations before planning around it, since the subject of the count decides what a limit can and cannot express. Requests are inspected at the edge, so traffic that exceeds a limit is refused before reaching your origin rather than after. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is rate limiting?** Counting requests against something and refusing them past a threshold. The mechanism is simple; the difficulty is entirely in choosing what to count, which subject to count it against, over what period, and what to do at the threshold, because those four decide who gets refused wrongly. **Should I limit by IP address?** Only where nothing better is available, and knowing what it costs. One address routinely carries an office, a school, or a mobile network, so those users share a budget they cannot see, while anything deliberately spreading traffic simply moves between addresses. **What should a rate limit return?** The status code meaning the limit rather than the request was the problem, together with an indication of when to come back. Without the second, a client assumes immediately, and the refusals themselves become load, which is the failure mode this is designed to prevent. **How do I stop a limit blocking my own systems?** List your automation before enforcing anything, and exempt each entry by a credential rather than by an address. Credentials survive infrastructure changes and addresses do not, so an exemption written against an address quietly stops matching and nobody notices until something fails at an inconvenient hour. **Do rate limits stop DDoS attacks?** Only the application-layer kind, where requests genuinely arrive and are individually valid. Traffic that saturates a link never becomes a request at all, so nothing counting requests can see it, let alone refuse it. The distinction is set out on [attack layers](/attacks/layers/). --- https://bridge-waf.com/rules/ --- # WAF rules explained: what they match and what they miss A rule looks for a pattern in a request and acts when it finds one. That is the entire mechanism, and both its usefulness and its limits follow from it: a rule catches what somebody knew to describe in advance, and it is blind in the same proportion to anything nobody thought to write down. ## What a rule actually does It examines a request and decides whether some part of it matches a description. The description might concern the address requested, the headers, the parameters, the body, or a combination. What matters is that the decision is made on the request alone. A rule knows nothing about who is asking, what they asked for previously, whether they are signed in, or what your application does with the value once it arrives. It sees text and compares it against a description of text that somebody believed indicates trouble. This is why rules pair naturally with [rate limiting](/rate-limiting/): one judges the content of a single request, the other judges the volume across many, and neither can do the other's work. ## Where rule sets come from Almost nobody writes a rule set from nothing, and understanding what you are inheriting matters more than the rules themselves. Public rule sets are maintained by security communities and describe patterns associated with well-known classes of attack. They exist because those classes recur across every application, so the same descriptions are useful to everybody, and because keeping them current is more work than any one team should repeat. The trade is visible from the start. A shared rule set knows nothing about your application, so it is written for the general case and errs toward catching things. What is normal traffic for your site may be exactly what somebody else's rule was written to stop, and neither party is wrong. ## Why matches are scored rather than absolute Treating every match as proof produces a system nobody can run, so mature rule sets do something more careful. A single suspicious pattern is weak evidence. Text that resembles an injection attempt appears legitimately in search boxes, in support tickets, in code samples, and in any field where people write about software. Acting on one match would refuse all of that, constantly. The alternative is to treat matches as contributions to a total, and to act only when enough of them accumulate on the same request. That converts a binary question into a threshold you can move, which is what makes a shared rule set usable on a real site without rewriting it. It also means the threshold, rather than the rules, is where most of your tuning happens. ## The two ways a rule set fails Both are inevitable and they are not equally expensive, which decides how to set everything above. **It refuses something legitimate.** A customer, a partner integration, or your own automation is stopped by a rule written about somebody else's threat. This failure is silent from your side: the person does not report it, they leave, and the log entry looks like a successful defence. **It misses something.** An attack passes because nobody described that pattern, or because it was spread thin enough to stay below the threshold. This failure is visible eventually and can be responded to. The asymmetry is the whole argument for caution. One failure mode you find out about and one you do not, which means an unwatched rule set drifts toward confident, invisible harm. ## What rules cannot reach Three categories, and no threshold setting brings them into range. **Authorisation.** Whether this person may see this record is a question about your data and your permissions. The request asking for it is entirely well formed, and nothing in it distinguishes the legitimate reader from somebody who changed a number in the address. **Business logic.** Ordering at a price that should not exist, or using a workflow in an order nobody anticipated, produces requests that are valid individually and wrong in sequence. A rule sees one request. **Design decisions.** A missing check, an operation that can be replayed, a secret in a place it should not be. These are properties of the application, and a filtering layer in front of it cannot supply what was never built. Knowing this is not an argument against rules. It is what stops a rule set being treated as a substitute for the work it cannot do. ## Watch before you enforce The same discipline the whole layer rests on, and it matters most here because rule matches are the hardest to predict. Run a shared rule set in observation first, against your own real traffic, for long enough to include the unusual days. What you are looking for is not attacks; it is the requests your own site generates that happen to resemble somebody else's threat. Every one of those is a customer you would have refused, and you can only find them before enforcement, never after. ## The reference material behind them Three pieces of reference material sit behind most rule sets: the widely used community list of application security risks, with the positions on it a filtering layer can genuinely address; the maintained rule set built around those risks, with its own scoring and severity settings; and the equivalent list for interfaces used by other software rather than by people, which fails differently and is covered on [API abuse](/attacks/application/api-abuse/). This page does not reproduce them. It covers what any rule set built from them can see, and what it cannot. ## FAQ **What are WAF rules?** Descriptions of patterns in a request, together with what to do when one matches. The mechanism examines the request alone, so a rule knows nothing about who is asking or what your application will do with the value, which is both why it is fast and why it misses whole categories of problem. **Should I write my own rules or use a public set?** Start with a maintained public set, because the classes of attack it describes recur everywhere and keeping the descriptions current is continuous work. Write your own only for something specific to your application that no general set could know about. **Why does a rule set block legitimate traffic?** Because it was written for the general case and knows nothing about your site. Text that looks like an attack appears legitimately in search boxes, support tickets, and anything discussing software, so a set tuned for everybody refuses some of what is normal for you. **Do rules stop every attack?** No, and three categories are entirely out of reach: whether somebody is allowed to see what they asked for, whether a sequence of valid requests adds up to something wrong, and anything that follows from how the application was built rather than from what a request contains. **What is the difference between rules and rate limiting?** A rule judges the content of one request; a limit judges how many requests arrived. Neither substitutes for the other, and the failures they address barely overlap, which is why a filtering layer that offers only one of them leaves an obvious gap. --- https://bridge-waf.com/tools/ --- # WAF tools: check headers, addresses and reputation Five checks, each answering one question about a site or an address. Each runs with ordinary means: a command in a terminal, the network panel of a browser, or the lookup a list operator publishes. Every one is paired with the page explaining what its answer means, since a result on its own tells you what is true without telling you what to do about it. ## What is here **Security headers.** Request the page and read the protective headers in the response, with `curl -I` or in the browser's network panel: what is present, what is missing, and what each one is for. The rules behind them are covered under [rules](/rules/). **Address reputation.** Reputation services publish what they have observed from an address. That record is the input behind most reputation-based decisions, not a verdict about the address itself. Paired with [IP reputation](/bots/ip-reputation/). **Blocklist check.** A narrower question: whether an address appears on public lists. Each list answers for itself, through a lookup its operator publishes. That is a different question from reputation, and the two are worth keeping apart, because presence on a list is a fact while reputation is an interpretation. **Botnet association.** Threat-intelligence feeds record addresses tied to known automated networks. Worth checking when a pattern in your logs comes from somewhere you do not recognise and you need to know whether it deserves a closer look. **Firewall in the path.** Response headers, cookies set on first contact, and the page returned for a refused request usually show whether a site sits behind a filtering layer. Useful mostly when inheriting infrastructure nobody documented, where the first question is what is already in the path. ## What is not here, and why One thing is missing on purpose. There is no attack test. A tool that generates load against a site you name is indistinguishable from the thing it claims to help you defend against, and running one against infrastructure you do not own is not ours to offer. Testing resilience is a legitimate need and belongs in an arrangement where both sides know it is happening, not behind a button on a public page. What these checks do instead is describe what is observable: what a site returns, what is published about an address, and what a pattern resembles. Deciding what to do about it is covered under [operations](/operations/). ## FAQ **Do these checks need an account?** No. Each uses a standard command, a browser's own developer tools, or a list operator's public lookup, and none of them runs through this site. The address checks report what public sources say rather than anything about your own site. --- https://bridge-waf.com/vs/ --- # WAF vs other defences: what each one actually sees The categories in this comparison are not competitors so much as instruments pointed at different things. What separates them is the level they observe at, and almost every argument about which one you need is really a question about which level your problem lives on. ## The one distinction that explains the rest Each defence can only act on what it can see, and they see different amounts of the same traffic. A network firewall works with addresses, ports, and protocols. It knows that a connection was attempted from somewhere to somewhere on some port, and it decides on that. It does not know what the request inside was asking for, because at that level there is no request yet, only a connection that might carry one. A request-inspecting layer works with the request as a request: the method, the path, the headers, the body, and the pattern across several of them. It knows what was asked for and can refuse it on that basis. What it cannot do is act on traffic that never becomes a request, which is where its limit sits. An intrusion-detection system sits between those, watching traffic for known signatures and behaviour across a network rather than for the meaning of one request to one application. Its strength is breadth: it sees patterns that no single request reveals. Its weakness is the same thing, since a pattern matching many things is less precise about any one of them. The practical consequence: a defence cannot protect against what it cannot observe, and no amount of configuration changes what a category is able to see. That boundary is set out per attack type on [attack layers](/attacks/layers/). ## Which question do you actually have Three questions, and the right instrument follows from which one you are asking. **"Something is reaching a port that should not be open."** That is addresses and ports, and it belongs to a network firewall. A request filter would never see it, because the traffic is not requests. **"Requests are arriving that my application should never have to handle."** That is the request level: injection attempts, abuse of an expensive endpoint, automated traffic hammering a form. This is what a request filter is for, and the tell is that each request is individually well formed while being something you would never want served. **"Something is happening across my network that looks like a known pattern."** That is detection across traffic rather than judgement of a single request, and it is what intrusion systems are built for. The signal here is that no individual event looks wrong while the sequence does, which is precisely what a per-request decision cannot capture. Most sites have all three questions at different times, which is why the categories coexist rather than replace one another, and why the honest answer to "which one do I need" is usually a question back rather than a recommendation. What matters is not choosing one but knowing which one your current problem belongs to, because the wrong instrument produces confident silence instead of an answer. ## Where the categories blur Two places to know before reading anybody's comparison. **Bundling.** Vendors combine categories into single offerings, so a product name says little about which capabilities are present. The useful question is never what a thing is called but what it inspects, and that question has an answer for every product regardless of how it is marketed. This is also why comparison tables age badly. A row saying a category does or does not do something describes a market at a moment, while the underlying distinction, what each level can observe, does not move at all. Reading the distinction first makes any table easier to judge, including ours. **Deployment.** The same category exists as software you run and as a service in front of you, and that difference changes operations far more than it changes capability: who patches it, what happens under load, and whether traffic terminates before your infrastructure or on it. A comparison that treats those as the same product with a different delivery method misses the part that affects your week. Both are covered here rather than on pages of their own. The comparison with a page of its own is the one people confuse most often: [WAF vs firewall](/vs/waf-vs-firewall/), the line between a request filter and the network firewall in front of it. ## What none of them do Comparisons rarely state this plainly. None of these categories fixes an application. A missing authorisation check, an operation that can be replayed, or data returned to whoever asks are properties of your code, and traffic filtering can make them harder to reach without making them absent. Anything promising otherwise is describing a delay rather than a repair, which is the point made under [virtual patching](/glossary/virtual-patching/). They also do not decide policy for you. What to allow, what to refuse, and what to watch first are choices, and the discipline for introducing them without breaking anybody is under [operations](/operations/). And none of them removes the need to know your own traffic. Every category works from what it observes, so a defence configured against an idea of your traffic rather than the traffic itself will be wrong in ways nobody notices until it refuses something that mattered. ## FAQ **Is a WAF the same as a firewall?** No. A network firewall decides on addresses, ports, and protocols, while a web application firewall decides on the content of requests. They answer different questions, and a site can need both: one keeps traffic away from ports, the other refuses requests the application should never handle. **Do I need a WAF if I already have a firewall?** They cover different levels, so having one says nothing about the other. If your problem is requests that reach the application and misbehave there, a network firewall cannot see them at all, because it is deciding before there is a request to look at. **What is the difference between a WAF and an IPS?** An intrusion system watches traffic across a network for known signatures and behaviour, while a request filter judges individual requests against an application. The first is broader and less specific; the second is narrower and understands what a request means. **Does a WAF replace fixing my code?** No. Filtering can make a weakness harder to reach, and that buys time, but the weakness stays in the application and remains reachable by any route the rules do not describe. Treating filtering as the repair is the mistake that makes it dangerous. --- https://bridge-waf.com/attacks/application/ --- # Application layer attacks: when valid requests are the weapon Application attacks send requests the server cannot refuse to process. Each one is well formed, arrives over a completed connection, and asks for something expensive. Volume stays low enough to look ordinary, and the site falls over because the work behind those requests exceeds what the backend can do. ## Quick facts | | | |---|---| | **Layer** | Application (7) | | **Vector** | Valid requests targeting expensive operations | | **Goal** | Exhaust processing, memory, or the database | | **In your logs** | Logs fill rather than empty; response times climb | | **Does a WAF stop it?** | **Yes**, though by limiting and pricing requests rather than by recognising bad ones | That qualifier matters. There is no signature for a request that is identical to one a customer would send, so defence here works by controlling how many such requests a client may make and how much each costs, not by telling good from bad. ## Why volume stays low The economics are inverted compared with the other families. A flood that fills a link needs bandwidth the attacker must have. A flood that exhausts an application needs only requests that are expensive for you and cheap for them. A search across a large table, a report, a page assembled from several database queries, an endpoint that resizes an image: each costs the sender one request and costs you real work. The consequence is that this family is available to attackers without resources, and that the traffic graph stays unremarkable while the site becomes unusable. Anyone watching bandwidth alone sees nothing. ## What makes a request expensive Four properties, and knowing them tells you which of your own endpoints are exposed. **It cannot be cached.** Anything personalised, anything reflecting a parameter, anything behind a login. Cached responses cost almost nothing to serve, which is why attacks avoid them. **It touches the database.** Especially with a query whose cost grows with the data, such as an unbounded search or a filter across a large table. **It does work before checking anything.** An endpoint that parses, decodes, or resizes before deciding whether the caller is allowed has already spent the resource. **It fans out.** One request that triggers several internal calls multiplies the cost, which is common in interfaces assembled from multiple services. ## The vectors in this category | Vector | Mechanism | Distinguishing property | |---|---|---| | [HTTP flood](/attacks/application/http-flood/) | Many ordinary requests, often to one path | Indistinguishable per request; only the pattern shows | | [Slowloris](/attacks/application/slowloris/) | Connections held open by sending headers slowly | Very few requests, very little traffic | | [Low and slow](/attacks/application/low-and-slow/) | Requests or bodies delivered at minimal rate | Designed to sit below rate thresholds | | [Carpet bombing](/attacks/application/carpet-bombing/) | Traffic spread across many addresses and paths | Each source stays under any per-source limit | | [API abuse](/attacks/application/api-abuse/) | Legitimate endpoints called in illegitimate volume | Lever per call, so volume can stay low | Two of these deserve a note, because they defeat the obvious defence. Spreading traffic across many sources keeps every individual source below a per-client threshold while the total is overwhelming, and delivering requests slowly keeps the rate low by design. Both attack the assumption that abuse looks like a burst. ## Recognising it The signature is the opposite of a volumetric attack. **Logs fill rather than empty.** Requests arrive, are processed, and are recorded. The evidence you need is in front of you, which is a genuine advantage of this category. **Response times climb before failures start.** The backend saturates gradually rather than refusing outright, so the first symptom is slowness and the outage arrives later. **Traffic concentrates oddly.** One expensive path receiving a share of requests unlike its usual share, a client population whose behaviour is too uniform, or a sudden absence of the ordinary variety in browsing patterns. **Cache effectiveness drops.** Requests engineered to miss the cache show up as a falling hit ratio while total requests rise. ## Mitigation by layer Four defences, and unlike the other families they are things you or your provider control directly. **Limit by client and by endpoint.** Not one global rate, but different allowances for different costs: an expensive search deserves a tighter limit than a static page. This is the first line and the most effective single measure. **Challenge rather than block.** Where a client is suspect but not proven, asking it to do something a browser does easily and automation does not separates populations without denying anyone outright. Cheaper in false positives than a block. **Make expensive things cheaper.** Caching what can be cached, bounding what a query may return, and checking authorisation before doing work removes the lever the attack depends on. **Absorb what remains at the edge.** Requests filtered before reaching your origin cost your infrastructure nothing, which changes the arithmetic that made the attack viable. ## When it is not an attack at all This family has a twin that looks identical and needs a different response. A misconfigured client retrying without limit, a partner integration that suddenly polls every second, a crawler that discovered a calendar with infinite dates: each produces the pattern of an application layer attack and none of it is hostile. The traffic is real, the requests are valid, and the cost to you is the same. Telling them apart is often possible from the outside. Accidental load usually comes from few sources, keeps a regular rhythm, and stops when the other side is told about it. Deliberate load adapts: sources multiply, timing shifts, and paths change when one stops working. The practical reason to check is that the fix differs entirely. An integration that needs a phone call should not be met with a permanent block, and an attacker will not be fixed by an email. ## The cost of getting it wrong Every defence here can refuse a customer, and that risk is inherent rather than a sign of poor configuration. Rate limits set on the assumption of one user per address will misfire where many users share one, which is normal on mobile networks and in offices. Challenges break automation that you asked for: monitoring, payment callbacks, and integrations. Blocks placed during an incident outlive it. The practical rule is that measures here should expire on their own and should be observable: a limit whose effect nobody can see is a limit nobody will remove. Where a decision is uncertain, slowing a client is safer than refusing it, because a delay that hits a customer is an annoyance and a block that hits a customer is a lost one. ## Where the platform sits This is the family Bridge WAF is built for, and the claim is narrower than it sounds. Requests are inspected before reaching your origin, rate limiting is applied per domain, and abusive patterns are handled without writing a rule for each variation. Because filtering happens at the edge, the requests that never arrive cost your servers nothing. What this does not address is anything that saturates a link, which is a different layer entirely. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a layer 7 DDoS attack?** An attack assembled from valid requests that ask for expensive work, so what runs out is the application's capacity rather than the network's. Nothing in the traffic is malformed, which removes the usual basis for discarding it and makes the defence a question of rate rather than correctness. **Does a WAF stop application layer attacks?** This is the one family where it genuinely applies, since complete requests exist to inspect and to count. The defence works by limiting how much any client may consume rather than by recognising bad requests, because there is no such thing as a bad request here. **Why is traffic volume low during one?** Because the cost falls on your backend rather than on the link. A request that costs a few hundred bytes to send can start a search, a report, or a write that occupies a worker for seconds, so bandwidth graphs stay calm while the application does not. **Why are these attacks hard to filter?** Because each request is identical to one a customer might send, so no single request contains the evidence. The distinguishing information exists only across many of them, in rate, sequence, and cost consumed, which means filtering has to reason about clients rather than packets. **Do rate limits solve it?** Partly, and their limits are known to whoever is sending. Traffic spread across many sources, or delivered slowly by each of them, is arranged specifically so that no individual client crosses a per-client threshold while the total comfortably exceeds capacity. **What is the risk of over-blocking?** Losing the customers you are protecting. Shared office addresses, mobile networks that place many users behind one address, and your own monitoring all produce traffic resembling what you want to stop, and none of them complains in a way that reaches you quickly. --- https://bridge-waf.com/attacks/application/api-abuse/ --- # API abuse: the endpoint works exactly as intended API abuse means using an interface the way it was built to be used, at a volume or in a sequence nobody designed for. There is no broken request and no exploit. A single call is indistinguishable from a legitimate one because it is one, which makes the decision a question of intent rather than of validity. ## Quick facts | | | |---|---| | **Layer** | Application (7) | | **Vector** | Valid calls to working endpoints, in volume or in unexpected sequences | | **Goal** | Exhaust resources, extract data, or exploit business logic | | **In your logs** | Successful responses; the anomaly is in pattern, not in status | | **Does a WAF stop it?** | **Yes** for the volume side, through limits and authorisation. Design flaws behind an endpoint are fixed in the application | Industry estimates of how large a share of incidents involve interfaces require a cited report with a date. Until one is confirmed, no proportion and no claim of growth appears here. ## Why it looks different from a flood A flood is about quantity of the same thing. Abuse is often about the shape of the interaction. Interfaces built for programs are more generous than pages built for people: they return structured data, they accept parameters that select what to return, and they are designed to be called repeatedly. Each of those properties is useful and each of them is also a lever. A call that returns one record can be made many times to return everything, and a parameter that selects a page of results can select a much larger one. The consequence is that abuse frequently arrives at rates that would never alarm anyone, because the lever per call is high enough that volume is unnecessary. ## The three shapes **Resource abuse.** Calling an expensive endpoint often enough to exhaust what is behind it: a search, a report, an operation that fans out into several internal calls. This is the form closest to a flood and the one limits address directly. **Data extraction.** Retrieving far more than any single user needs, one legitimate response at a time. Nothing in any individual call is wrong; the total is the problem, and totals are not what most defences measure. **Logic abuse.** Using the sequence rather than the volume: repeating an operation that was meant to happen once, taking a step out of order, or exploiting the gap between two calls that were assumed to be adjacent. Rates here can be trivially low. The third form is where filtering helps least and where the actual fix belongs to whoever designed the endpoint. ## What separates abuse from use Four properties, and none is decisive alone. **Breadth against depth.** Real clients look at what concerns them. Access that walks systematically across identifiers or ranges is a different behaviour from access that returns to the same few. **Absence of the rest of the application.** Interfaces are usually called alongside something else: a session, an interface, a workflow. Calls arriving without any of that context are automation, which is not automatically abuse but is worth knowing. **Timing that no person produces.** Even intervals, or bursts arriving faster than an interface could reasonably drive. **Cost per client wildly out of line.** The most reliable signal available, because it does not depend on guessing intent: a client consuming far more work than any plausible user is a fact rather than an inference. ## Where the real fix lives Filtering is often applied to problems it cannot solve. If an endpoint returns records belonging to whoever asks, the defect is authorisation, and no rate limit repairs it: a limit slows extraction without preventing it. If an operation can be replayed to produce an effect twice, the defect is in the operation, and limiting how fast it can be replayed leaves it replayable. The classes of flaw behind these are documented in the material on application security rules, and that is the right place for them. What belongs on this page is the traffic-side answer, which is narrower and honest about its narrowness. ## Mitigation by layer Four measures, and the first two do most of the work. **Limit per endpoint and per client, weighted by cost.** A uniform limit across an interface either throttles cheap calls needlessly or leaves expensive ones open. The general approach to designing such limits belongs with the material on rate limiting. **Bound what a single call may return.** Maximum page sizes and ranges turn extraction into something that needs many calls, which is what limits can then see. **Require identity for anything expensive.** Authenticated access ties consumption to an account rather than to an address, which survives distribution across many sources, and it makes revocation possible. **Watch totals per account, not just rates.** Extraction is a sum, not a rate. A client whose weekly total is unlike every other client is visible in a way that per-minute counters never show. What does not help on its own: blocking by address, since interfaces are called from infrastructure rather than from browsers, and matching request content, since the content is correct. ## The cost of getting it wrong Every measure here can break an integration that someone is paying for. Partner systems and internal automation look exactly like abuse: no browser, no session, even timing, high volume. Limits applied without knowing who legitimately calls you produce a failure that is invisible on your side and highly visible on theirs, often arriving as a support ticket days later. Two things reduce the risk. Know which clients are expected before enforcing anything, which usually means issuing them identity instead of guessing from addresses. And prefer measures that slow rather than refuse, because a slowed integration retries and a blocked one fails. ## Where the platform sits Bridge WAF inspects requests before they reach your origin and applies rate limiting per domain, which addresses the volume side. What it does not do is repair an endpoint that returns data to whoever asks, or an operation that can be replayed for effect. Those are application defects, and any product claiming to fix them from outside is describing something else. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is API abuse?** Using endpoints exactly as designed, at volumes or in sequences nobody anticipated. Nothing is broken into and nothing malfunctions, which is what makes it awkward: the system behaves correctly throughout, and the damage comes from the correct behaviour being repeated. **How is it different from an HTTP flood?** A flood works through quantity, so it is visible in any rate measurement. Abuse works through what each call is worth, extracting or costing a great deal every time, so it can achieve its purpose at rates that trigger no alarm and appear in no graph as unusual. **Does a WAF stop API abuse?** It addresses the volume and extraction sides, through limits per client and through requiring identity. What it cannot address is a missing authorisation check or an operation that can be replayed, because those are properties of the application and have to be fixed there. **Why do address blocks not work?** Because interfaces are called from infrastructure rather than from personal devices, and infrastructure changes addresses trivially while sharing them widely. Blocking one address removes a caller for a few minutes and may remove several unrelated legitimate callers permanently, which is the worse half of that trade. **What is the most reliable signal?** Cost consumed per identified client, because it is a measurement rather than an inference. Headers, addresses, and traffic shape all invite guesses about who someone is; what an endpoint costs to answer is a fact you already possess and can act on defensibly. **How do I avoid breaking partners?** Three habits, in order. Establish which clients are expected before you enforce anything, give each of them an identity so limits can be set per client rather than per address, and prefer slowing a caller down to refusing it, since a slowed integration reports the problem while a refused one breaks. --- https://bridge-waf.com/attacks/application/carpet-bombing/ --- # Carpet bombing: staying under every limit at once Carpet bombing splits an attack across many addresses so that no single one receives enough traffic to cross a threshold. The total is overwhelming and every individual measurement looks ordinary, which is the point: defences that decide per address, per source, or per endpoint have nothing to react to, because each of those views is below the line. ## Quick facts | | | |---|---| | **Layer** | Classically network (3); the same principle appears at layer 7 | | **Vector** | Traffic spread thinly across many targets or many sources | | **Goal** | Exceed capacity in aggregate while staying under every per-entity limit | | **In your logs** | Often nothing unusual, because your address is only one of many | | **Does a WAF stop it?** | **Partly.** It sees the application-layer form through aggregate analysis; the network form is not visible to it at all | That last row deserves the honesty. The classic version of this technique is a network-layer problem, and a page filed under application attacks should say so rather than imply that request inspection answers it. ## The principle Nearly every automatic defence is a threshold attached to an entity: this many requests from one client, this much traffic to one address, this many errors on one endpoint. The entity is what makes the rule practical, since a limit has to apply to something. Distribution attacks the entity, not the limit. If a hundred addresses each receive a modest share, every per-address view is unremarkable while the link carrying all of them is not. Nothing needs to be hidden, and no technique needs to be clever: the traffic is simply arranged so that the question your defences ask returns a reassuring answer. ## Two forms of the same idea **Spread across destinations.** The classic version, aimed at whoever carries traffic for a range of addresses. Each address in the range gets too little to trigger anything, while the router or link serving the range saturates. The victim is the infrastructure rather than any single site, and the operators of the individual sites may see nothing at all until their connectivity fails. **Spread across sources and paths.** The application-layer analogue: many sources, each making few requests, distributed across endpoints so that no path and no client stands out. Per-client rate limits are blind by construction, since the design assumption behind them is that abuse concentrates somewhere. The second form is where request inspection can help, and only when it is looking at totals rather than at individuals. ## Why thresholds are blind here Three reasons, and they are structural rather than a matter of tuning. **A threshold needs a subject.** Whatever you count, you count it per something, and the technique arranges for that something to look normal. Lowering the threshold does not fix this; it produces false positives long before it catches a distributed sender. **Averages hide it.** A total that is unremarkable for the whole system can be composed of many small anomalies, and averaging is the operation that removes them from view. **The evidence may not be yours.** In the network form, the only party who can see the aggregate is the one carrying the whole range. Your own logs are a slice too small to contain the pattern, which is why an operator can truthfully report that nothing is wrong with their site while being part of an event. ## What actually sees it Detection has to change subject: from entities to totals, and from absolute values to deviations. **Aggregate baselines.** Total requests, total connections, and total traffic compared against what is normal for the time of day and day of week. A pattern invisible per client is often obvious in the total. **Cross-endpoint correlation.** Many endpoints each slightly busier than usual, at the same time, from populations with nothing in common. Each alone is noise; together they are a shape. **Population novelty.** A large number of sources that have no history is a stronger signal than any of them individually exceeding a limit. The general approach behind these belongs to how limits are designed and is covered where rate limiting is discussed in full, not here. ## Mitigation by layer Four measures, and the first is a phone call rather than a configuration change. **Ask whoever carries your traffic what the aggregate looks like.** In the network form this is not optional: they hold the only view that contains the pattern, and they can filter at a level you cannot reach. **Limit on totals as well as on individuals.** A ceiling on concurrent work for an endpoint, independent of who is asking, catches distributed load that per-client limits miss. **Price requests rather than count them.** Where the cost of serving a request is what matters, a budget expressed in work instead of requests is harder to spread under, because the total cost is the thing being constrained. **Prefer challenges to blocks at low confidence.** With distributed traffic, confidence about any individual source is low by construction, so measures that ask rather than refuse cost less when they land on a customer. What does not help on its own: per-source rate limits, address blocking, and lowering thresholds. The first two are the mechanism being defeated, and the third trades a missed attack for refused customers. ## The trade-off in aggregate limits This is the cost of the main recommendation above. A limit on totals cannot tell which contributor to refuse. When it engages, it applies to whoever arrives next, which includes customers, and it does so precisely during the busiest moments, since that is when totals are highest. A genuine surge and a distributed attack look the same to a counter that only knows the total. That is why aggregate ceilings work best as protection against collapse rather than as everyday enforcement: set where the system would fail anyway, they trade a degraded experience for an outage. Set close to normal traffic, they become an outage of their own. ## Where the platform sits Bridge WAF inspects requests before they reach your origin and applies rate limiting per domain, which addresses the application-layer form when combined with attention to totals rather than to individual sources. The network form, where traffic is spread across a range of addresses to saturate the infrastructure carrying them, is not something request inspection can see, and it belongs with whoever provides that connectivity. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is carpet bombing in a DDoS context?** Traffic spread deliberately across many addresses or sources so that no single one of them ever crosses a detection threshold, while the sum comfortably exceeds what the target can carry. It defeats the measurement rather than the capacity, which is why it survives defences that work against concentrated traffic. **Why do per-client rate limits miss carpet bombing?** Because a limit applies to one entity at a time, and the traffic is arranged so that every individual entity looks entirely ordinary. The pattern exists only in the sum, and a mechanism that examines clients one at a time has no way to see a sum. **Can I see it in my own logs?** Frequently not. In the network form the traffic is spread across a whole range of addresses, so the pattern exists only in an aggregate held by whoever carries traffic for that range. Your logs contain your slice, and your slice looks normal. **Does a WAF stop carpet bombing?** Partly, and the split matters. The application-layer form is visible if you analyse traffic in aggregate rather than per client, which request inspection can do. The network form never becomes requests at all and is therefore outside its reach entirely. **Should I lower my thresholds?** That is the instinctive response and it fails in a specific way: it starts refusing genuine customers long before it approaches traffic engineered to sit beneath any threshold. Change what you measure, moving to aggregates, rather than how strictly you measure the same thing. **What is the single most useful step?** Asking whoever carries your connectivity what the aggregate looks like. They hold the only view in which this pattern is visible, and no amount of work on your own systems reconstructs it, because the information was never in your logs to begin with. --- https://bridge-waf.com/attacks/application/http-flood/ --- # HTTP flood: valid requests that take a whole site down An HTTP flood sends ordinary requests in quantities the application cannot serve. Each is well formed, arrives over a completed connection, and asks for something a real visitor might ask for. There is no malformed input to reject and no signature to match, which makes this the hardest family to filter and the one where filtering applies. ## Quick facts | | | |---|---| | **Layer** | Application (7) | | **Vector** | Large numbers of valid requests, often to a few paths | | **Goal** | Exhaust processing, memory, or the database behind the site | | **In your logs** | Logs fill; response times climb before failures start | | **Does a WAF stop it?** | **Yes**, by limiting and pricing requests rather than by recognising bad ones | That qualifier is the whole subject of this page. Defence works on aggregate behaviour, because no individual request is distinguishable from one a customer would send. ## Two shapes, different costs **Requests that only read** are the cheaper form for the sender: no body to construct, no session to maintain. Their effectiveness depends entirely on choosing paths that cost you something, which is why an attack on a search or a filtered listing does more damage than one on a static page. **Requests that submit** are more expensive for both sides. They force parsing, validation, and often a write, and writes are the operations least able to be scaled away by caching or read replicas. A modest rate against a submission endpoint can outweigh a much larger rate against a page that only reads. The choice between them tells you something about the sender's intent: a flood aimed at reads is usually about volume, while one aimed at writes is usually about finding your most expensive operation. ## Why per-request filtering fails A request carries a method, a path, headers, and possibly a body. Every one of those fields can hold exactly what a browser would send, because there is nothing preventing it. One consequence is where most defensive effort is wasted: any rule that describes what a bad request looks like will either miss traffic that copies a browser or block customers whose requests happen to match. The distinguishing information does not exist inside a single request. It exists across many of them. ## What the aggregate shows The evidence is in the shape of traffic rather than in its contents. ```text # Illustrative access log extract; values are shape, not measurements. # Addresses per RFC 5737, host per RFC 2606. 198.51.100.x GET /search?q=... HTTP/1.1 200 ua="" ref="-" 198.51.100.x GET /search?q=... HTTP/1.1 200 ua="" ref="-" 203.0.113.x GET /search?q=... HTTP/1.1 200 ua="" ref="-" 203.0.113.x GET / HTTP/1.1 200 ua="" ref="example.com" ``` Four properties separate the two kinds of line above. **Path concentration.** Real populations spread across a site. A flood concentrates, usually on whatever is expensive. **Uniform timing.** Human traffic is irregular: people read, pause, and leave. Generated traffic tends toward even intervals unless deliberately varied. **Missing context.** Requests arriving without the accompanying assets a page would load, or without the referrer chain that browsing produces, are not browsing. **Population uniformity.** A client base that all announces itself identically, or that all appeared within the same minute, is not a client base. ## The signal everyone over-trusts A single repeated User-Agent string looks conclusive and is not. That header is set by whoever sends the request, so it proves nothing on its own: it can copy a current browser exactly, and it frequently does. Meanwhile a genuine population contains large groups sharing identical strings, because that is what a popular browser version looks like. Treat it as one weak input among several. Blocking on it alone is a decision that removes real visitors and stops working the moment the sender changes one line. ## Where the traffic comes from Requests at scale usually originate from many compromised or rented machines rather than from one place, which is why source-based blocking runs out quickly: each address contributes little, and there are many. That property is the reason limits work better per client than in aggregate, and the reason challenges matter: they ask each source to spend something, and the economics of the attack depend on each source being cheap. ## Mitigation by layer Four measures, and unlike the other families these are yours to apply. **Limit per endpoint, not just per site.** The expensive path deserves a tighter allowance than the cheap one, and a single global rate either throttles normal browsing or leaves the expensive path unprotected. **Challenge before blocking.** Asking a client to demonstrate it is a browser separates populations without denying anyone outright, and it costs far less in false positives than a block. **Cache what can be cached.** A request served from cache removes the lever entirely. Attacks concentrate on what cannot be cached precisely because of this. **Bound the expensive operations.** Limiting what a search may return or what a report may span reduces the cost per request, which changes the rate at which an attack becomes viable. ## When the flood is your own success Check this before any of the above: the response differs and the symptoms do not. A campaign that worked, a link that spread, or a partner sending traffic they did not warn you about all produce a sudden concentration of requests on a few paths. So does a search engine indexing a section it had not seen before. Each looks like an attack in every graph you have, and each is revenue rather than an emergency. Two checks usually settle it. Look at whether the traffic converts or behaves like people once it arrives: real visitors load assets, follow links, and leave in a distribution. And look at whether the sources have histories, since a population that existed yesterday is different from one that appeared at once. The reason to check first is that the measures on this page work equally well against customers. A limit that ends an attack also ends a launch, and the graph looks the same either way. ## The cost of getting it wrong Every measure here can refuse a customer. Address-based limits misfire where many people share one address, which is normal on mobile networks and in offices. Challenges break the automation you asked for: monitoring, payment callbacks, and integrations. Rules written during an incident stay in place afterwards and quietly remove traffic nobody is watching. The rule that holds: measures should expire on their own, and where a decision is uncertain, slowing a client is safer than refusing it. A delay annoys a customer; a block loses one. ## Where the platform sits This is the layer Bridge WAF exists for. Requests are inspected before reaching your origin, rate limiting is applied per domain, and abusive patterns are handled without writing a rule for each variation. Requests that never arrive cost your servers nothing. What this does not address is traffic that saturates a link, which belongs to a different layer entirely. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is an HTTP flood?** An attack that sends large numbers of ordinary, valid requests in order to exhaust the application rather than the network. It is the most direct member of this family: no cleverness in any individual request, simply more of them than the backend can complete. **Does a WAF stop HTTP floods?** This is the layer where it applies, since complete requests exist to count and to limit. The defence is quantitative rather than qualitative: it restricts how much any one client may consume, because no rule can identify a request that is wrong in itself. **Why can I not just block the bad requests?** Because there are no bad requests to block. Each one is well formed and plausible, and the only distinguishing information lives across many of them: how fast they arrive, from how many places, and what they cost you to answer. **Is a repeated User-Agent proof of an attack?** No, on two separate grounds. The header is chosen by whoever sends the request and can say anything at all, and large populations of genuine browsers legitimately share identical strings, so a match is evidence of neither the sender's identity nor their intent. **Are POST floods worse than GET floods?** Usually, because submissions force parsing and writing, and writes are the operations hardest to serve from a cache or spread across more machines. A request that reads can be absorbed by capacity; a request that writes has to be handled where the data lives. **What should I limit first?** The endpoints that cost the most to answer, with a tighter allowance than the rest of the site. Search, report generation, and anything that writes deserve their own limits, because a uniform limit across the site is set either too loosely for those or too tightly for everything else. --- https://bridge-waf.com/attacks/application/low-and-slow/ --- # Low and slow: attacks built to stay under the threshold Low and slow is the class of attacks that succeed by never looking like too much. [Slowloris](/attacks/application/slowloris/) is the best-known member and holds connections open with headers it never finishes; this page covers the family it belongs to, because the same principle produces several techniques, and a defence tuned against one of them frequently misses the others. ## Quick facts | | | |---|---| | **Layer** | Application (7) | | **Vector** | Requests delivered or consumed at deliberately minimal rates | | **Goal** | Occupy connections, workers, or buffers rather than capacity | | **In your logs** | Long-lived connections, few completed requests, low throughput | | **Does a WAF stop it?** | **Yes**, by requiring progress and buffering complete requests, not by limiting rate | The qualifier is the point of the class: every measurement of "too much" is a rate, and these attacks are designed to stay below whatever rate you measure. ## The principle they share Defences against abuse mostly count things per unit of time: requests per second, connections per minute, bytes per interval. Each threshold encodes an assumption that abusive traffic is more traffic. These techniques invert it. They send less, not more, and occupy a resource by holding it rather than by exhausting it with volume. A threshold set high enough not to inconvenience real users is necessarily far above what these attacks generate, so the counter never trips and the site goes down with the dashboards showing nothing unusual. Three shapes follow from the principle, distinguished by which part of the exchange is stretched. ## Slow headers The request line arrives, then headers appear one at a time, never reaching the marker that ends them. The connection stays legitimately open because the server cannot know whether the next line is coming. This is the technique covered in full on [Slowloris](/attacks/application/slowloris/), including which server architectures reach their ceiling first. ## Slow body: the R.U.D.Y. shape The same principle, applied one stage later. Where a form or an API accepts a submission, the client announces how much data it intends to send and then sends it at a trickle. The server, having been told a body is coming, waits for it. A submission endpoint that would normally complete in a moment instead holds a worker for as long as the sender chooses. Two things make this variant awkward. Submission endpoints are usually the expensive ones, so each occupied worker costs more than it would elsewhere. And uploads are legitimately slow, which means the naive fix, refusing requests that take a long time to arrive, breaks the exact feature being abused. ## Slow read The mirror image, and the one most often forgotten. Here the request completes normally and the response is what stalls: the client accepts data at a minimal rate, so the server holds the response and its buffers while it waits for the recipient to take delivery. From the server's perspective the request was served; from the resource's perspective it is still occupied. The signal is a set of responses in progress for far longer than the content they carry would explain, with the process itself idle. ## Why the usual measures miss it Three reasons, and they explain why this class survives in environments that are otherwise well defended. **Rate limits do not see it.** Nothing exceeds a rate. Counting requests per source produces small numbers, because each source makes few requests and simply never finishes them. **Content rules do not see it.** Everything sent is well formed. There is no payload, no anomaly, and nothing a signature could describe. **Monitoring often does not see it.** Bandwidth graphs stay flat, processor usage stays low, and error rates rise only at the end when new visitors are refused. The failure appears fully formed rather than as a trend. ## Mitigation by layer Four measures, and they share a shape: require progress rather than enforce speed. **Demand forward progress on incomplete requests.** A connection that has not advanced meaningfully is a different thing from a connection that is slow. Where a server can express that distinction, it closes the abusive case and leaves the legitimate one alone. **Bound header time separately from body time.** Headers do not legitimately take long. Bodies do, and treating them under one deadline either lets attacks through or breaks uploads. **Buffer complete requests in front of the application.** A layer that accepts the whole request before forwarding absorbs slow delivery, which is the same structural defence that answers the header variant. **Cap concurrent incomplete exchanges per source.** Both delivery and collection benefit. It misfires on shared addresses, which is the usual trade-off in this category. What does not help: request rate limits, content rules, and larger servers. The resource being consumed is occupancy, and adding capacity moves the ceiling without changing the mechanism. ## Before you set aggressive deadlines **Warning:** the reflexive fix is a short absolute time limit on requests, and it removes real users along with the attack. Slow clients exist and are not doing anything wrong: mobile networks with poor coverage, distant regions, and anyone sending a large file over a constrained link. A deadline treats them as it treats deliberate delay, because from the server's side the two look identical. The distinction that works is progress, not elapsed time. A client sending steadily but slowly is behaving; a client sending the minimum required to stay connected is not. Where a server or an edge can express that, it should, and where it cannot, header time is the safer thing to constrain, since no genuine client needs minutes to finish sending headers. ## Where the platform sits Bridge WAF sits in front of your origin and accepts complete requests before forwarding them, so slow delivery is absorbed at the edge rather than occupying your application. Rate limiting is applied per domain, which bounds the volume a domain accepts rather than what any single source may hold open. What this does not address is traffic that saturates a link, which is a different layer. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a low and slow attack?** An attack that occupies connections, workers, or buffers by operating at a minimal rate rather than by generating volume. It succeeds precisely by staying beneath every threshold designed to catch excess, which is why it tends to be diagnosed late. **Why do rate limits miss a low-and-slow attack?** Because nothing exceeds a rate at any point. Each source makes very few requests and simply never completes them, so a limit that counts requests per client sees a perfectly unremarkable client, while the resource actually being consumed is counted by nothing at all. **What is the R.U.D.Y. shape?** The slow-body variant. The client announces a submission of a given size and then delivers it at a trickle, holding a worker for as long as it chooses. It targets submission endpoints specifically, which are the expensive ones and often the ones without their own limits. **What is a slow read attack?** The mirror image. The request itself completes normally, and then the client accepts the response so slowly that the server must retain both the response and the buffers holding it. Requiring a complete request achieves nothing against this, because the request was complete. **Does a WAF stop these?** When it buffers complete requests and can require forward progress in both directions, yes. Rules that match on content do not help at all here, since the content is ordinary and the abuse lies entirely in the timing of its delivery. **Will a short request timeout fix it?** It will also disconnect mobile users on poor connections and interrupt legitimate uploads, which is a self-inflicted version of the outage you are preventing. Require forward progress instead, and constrain the time allowed for headers separately from the time allowed for a body. --- https://bridge-waf.com/attacks/application/slowloris/ --- # Slowloris: an outage with almost no traffic Slowloris takes a site down by opening many connections and never finishing the requests on them. Each connection sends part of a request, then keeps trickling just enough to avoid being closed as idle. The server holds every one of them open, waiting for a request that never completes, until it has nothing left to hold. ## Quick facts | | | |---|---| | **Layer** | Application (7), consuming connection slots | | **Vector** | Many connections carrying deliberately unfinished requests | | **Goal** | Occupy every slot the server can serve from | | **In your logs** | Many open connections, very few bytes, almost no completed requests | | **Does a WAF stop it?** | **Yes**, though by architecture rather than by rules: a layer that buffers the whole request absorbs it | That qualifier matters. Nothing about the traffic is recognisably hostile; what defeats it is where the incomplete request is held. ## The mechanism A request is not a single event. It arrives as a series of lines, and the server knows it is complete only when it sees the marker that ends the headers. Until then, the connection is legitimately in progress, and closing it would break clients on slow networks. An attack exploits that patience. It sends the opening line, then one header at a time, spaced out enough to stay under any idle timeout and slow enough that the request never finishes. Multiply that across as many connections as the server will accept, and every slot is occupied by something that will never become a request. Two properties make this unusual. **Bandwidth is negligible.** The whole attack can run from a single ordinary connection, because volume is not the resource being consumed. A network graph shows nothing. **Nothing sent is invalid.** Every byte is a well-formed part of a legitimate request. There is no malformed input, no signature, and no threshold of requests per second to trip, because requests are never completed and therefore never counted. ## Why some servers barely notice The difference is architectural, and it explains why the same attack ends one site and leaves another unaffected. Servers that dedicate a worker to each connection have a hard ceiling: when workers are occupied, new visitors wait regardless of how idle the machine is. Servers built around an event loop hold connections as cheap entries instead, so the ceiling is far higher and an attack needs proportionally more connections to reach it. Neither design is immune. The second raises the cost enough that the technique usually stops being practical, which is a different statement from immunity, and the difference matters when someone says their stack is not vulnerable. ## What you see ```text # Illustrative connection picture; values are shape, not measurements. Open connections high: far above the usual concurrency Bytes transferred very low relative to the connection count Connection age long: many sitting in the same state for minutes Completed requests near zero; access log barely grows Processor / memory normal: nothing is being processed ``` The distinguishing combination is high connection count with near-zero throughput. A genuine traffic surge raises both. This raises one and leaves the other flat, which is the single most reliable indicator. Where the server logs timed-out requests, those entries appear in numbers that do not match any plausible client behaviour. Their absence proves nothing, since not every configuration records them. ## Before you tighten timeouts **Warning:** the standard fix is to shorten how long a server waits for a request to arrive, and set too aggressively it disconnects real people. The clients that suffer first are the ones already having a difficult time: mobile connections in poor coverage, distant regions with high latency, and anyone uploading a large file over a slow link. Those requests are also slow to arrive, and a timeout cannot tell the difference between a slow client and a deliberate one, because there is no difference in what is sent. So the useful form of the measure is narrower than "reduce the timeout". Limit the time allowed for headers, which no legitimate client needs to spend minutes on, and treat the body separately, since uploads legitimately take time. Where a server supports requiring a minimum data rate rather than an absolute deadline, that expresses the intent better: it closes connections that are not making progress instead of connections that are merely slow. ## Mitigation by layer Four measures, most effective first. **Put a buffering layer in front.** Where a proxy accepts the whole request before passing it on, the incomplete ones are held there and your application never sees them. This is the defence that removes the problem rather than tuning around it, and it is why sites behind a terminating edge are largely unaffected. **Limit concurrent connections per source.** An attack from few addresses runs into this immediately. It helps less against many sources, and it misfires where many users share an address, which is the usual trade-off. **Bound header time and require progress.** As described above, applied to headers rather than to whole requests. **Prefer an event-driven front end.** Raising the ceiling does not solve the mechanism, and it converts an outage into a non-event at the volumes this technique can reach. What does not help: request rate limits, since requests are never completed, and rules matching request content, since the content is ordinary. ## Telling it apart Two lookalikes to rule out before acting. **A slow upstream or database** produces long-lived connections too, but with processing behind them: workers are busy, not waiting, and processor usage reflects it. **Legitimate slow clients** appear in small numbers, spread across different paths, and complete eventually. The attack shows many connections in the same state, opened close together, that never complete at all. ## Why it survived being famous The technique has been documented for many years, which raises the question of why it still works anywhere. Part of the answer is that the vulnerable design is not a defect. Serving each connection from its own worker is a reasonable architecture with real advantages, and the ceiling it imposes only becomes a problem when someone deliberately holds slots empty. The rest is that the defence lives in a component many deployments do not have. A site served directly by an application server, without anything buffering in front, is exposed by its shape rather than by its configuration, and that shape is common in internal tools, staging environments, and anything assembled quickly. Those are also the systems least likely to be watched, which is why the symptom is usually reported by a person who could not load a page rather than by monitoring. ## Where the platform sits This is a case where the platform's structure matters more than any rule. Requests reach your origin through the platform's edge, which accepts a complete request before forwarding it, so connections held open with unfinished requests are absorbed there rather than occupying your server. Rate limiting is applied per domain, which bounds the volume accepted for the domain as a whole. What this does not address is traffic that saturates a link, which belongs to a different layer. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a Slowloris attack?** An attack that opens many connections and sends each request so slowly that none of them ever finishes, occupying every slot the server has available. The server is not overloaded in any conventional sense; it is simply fully booked by clients that never leave. **Why does it use so little bandwidth?** Because the resource being consumed is connection slots rather than capacity, and holding a slot open costs the sender almost nothing to sustain. That asymmetry is the whole point of the technique: the defender's limit is reached long before the sender's is approached. **Does a WAF stop Slowloris?** When it buffers the complete request before passing anything backwards, yes, because the slow connection then terminates at something built to hold very many of them at once. Content-matching rules contribute nothing here, since everything sent is valid and merely unfinished. **Are all servers vulnerable?** Not equally. Architectures that dedicate a worker to each connection reach their limit first, because that limit is small and every held connection consumes one of them. Event-driven designs raise the cost considerably without being immune, since connection slots remain finite in any design. **Will shorter timeouts fix it?** Partly, and a flat deadline set aggressively enough to help will disconnect mobile users and interrupt large uploads. The better shape is to require forward progress and to constrain the time allowed for headers separately from the time allowed for a body. **How do I recognise it?** By a combination that occurs in no other situation: a high count of open connections, almost no bytes transferred across them, almost no completed requests, and a machine whose processor and memory readings look entirely untroubled while the service is unreachable. --- https://bridge-waf.com/attacks/layers/ --- # Layer 3, 4 and 7 attacks: what a firewall can actually stop Attacks are described by the layer they operate on because that is what decides where they can be stopped. Network-layer floods succeed before any application sees them. Application-layer floods succeed by making the application do work. The same defence cannot address both, and the most common misunderstanding in this field comes from assuming it can. ## The claim worth correcting A web application firewall does not stop DDoS attacks at every layer. It stops attacks at the application layer, and the reason is structural rather than a matter of product quality. Request inspection requires a request. Before one exists, a connection has to be established, and before that, packets have to arrive over a link with capacity to carry them. A flood that saturates the link never becomes a request, because it did not need to: the damage was done by consuming bandwidth, and nothing that inspects requests was ever in a position to see it. Products marketed as protection against both are usually two services sold together, with the network-layer part handled by capacity and filtering somewhere upstream. That combination is legitimate and common. What is not accurate is describing the request-inspection part as the thing that stops the flood. ## Where each attack does its damage **Network layer.** Traffic addressed to your network in volumes the link cannot carry. The link is the resource being exhausted, and it is exhausted regardless of whether anything answers. Only something between the attack and your link can help. **Transport layer.** Connection attempts that consume state on anything tracking them: the server, a firewall, a load balancer. The tables that track connections are finite, and filling them denies entry to legitimate clients while bandwidth remains unremarkable. **Application layer.** Complete, valid requests that ask for expensive work. Every one arrives over an established connection and looks like a user. Here the resource being exhausted is processing, memory, or the database behind it. Only the third kind is visible to something that inspects requests, because only the third kind produces requests. ## What a firewall sees, and what it does not "It cannot stop that" is often heard as "it is not useful". A request-inspecting layer sees the method, the path, the headers, the body, and the client's behaviour across requests. That is enough to apply rate limits per client and endpoint, to challenge clients that behave unlike browsers, and to recognise patterns of abuse against expensive routes. Against application-layer floods, this is the right instrument, and it works because the attack has to identify itself as traffic in order to do harm. What it does not see is anything that failed to become a request: saturating packet floods, malformed traffic dropped by the network stack, and connection attempts that never completed. Those are handled before the request layer exists, which is why they belong to a different part of the defence. ## What stops network-layer attacks instead Three mechanisms, none of which involve reading requests. **Capacity.** Absorbing more traffic than the attack can generate. This is why network-layer defence is a property of infrastructure scale rather than of software. **Filtering upstream.** Dropping traffic before it reaches the link, based on properties visible in packets rather than in requests. Effective and blunt: the decisions available at that layer are coarse. **Distribution.** Spreading traffic across many locations so that no single link carries the whole attack. This changes the arithmetic of a flood rather than filtering it. All three sit outside the application. Where a provider terminates traffic for you, they are typically supplying some combination of these alongside request inspection, and it is reasonable to ask which part does what. ## The practical consequence Two questions follow, and they are the ones to ask a provider. **Where is traffic terminated?** If requests reach your origin directly, your origin's link is the constraint, and no amount of request inspection downstream changes that. If traffic terminates at a provider's edge, the question moves to their capacity and filtering. **Which layer does each part of the product cover?** A single label often covers several distinct services. Asking what stops a saturating flood, and separately what stops a flood of valid requests, produces a clearer picture than any datasheet. The reason this material separates attacks by family, described on [DDoS attack types](/attacks/), is that the separation is the only reliable way to tell whether a defence addresses your problem. ## Why the layers get conflated Not merely a marketing habit, though it is partly that. From outside, the symptom is identical. The site does not load. The difference between a saturated link and an exhausted database is invisible to a visitor and often to the owner, and both feel like the same emergency. The mitigations also arrive bundled: a provider that terminates traffic gives you capacity, filtering, and inspection at once, so the layers appear to be one product. That is convenient until something fails, when knowing which layer was covered decides where to look. ## Mitigation, honestly stated Layered defence is not a slogan here. It is a description of the fact that one layer cannot cover another. Bridge WAF operates at the application layer: requests are inspected before reaching your origin, rate limiting is applied per domain, and abusive patterns are handled without a rule for each variation. Because traffic terminates at the edge rather than at your server, the capacity in front of you is the platform's rather than your link's, which is the part that addresses the network layer. Asking which component covers which layer is a fair question to put to any provider, including us. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **Does a WAF stop DDoS attacks?** It addresses application-layer attacks, which arrive as complete requests and can therefore be examined. It cannot address floods that saturate a link, because that traffic never becomes a request, and inspection has no object to work on before the congestion happens. **What is the difference between layer 3, 4 and 7 attacks?** The lower two exhaust bandwidth or connection state before an application is involved at all, which is why they are stopped by capacity and filtering. The upper one exhausts the application itself with requests that are valid, so it has to be stopped by rate and behaviour instead. **Why do products claim to stop both?** Because such a product is usually several services under one name, and the network-layer half is capacity and upstream filtering rather than request inspection. The claim is accurate about the bundle and misleading about the firewall inside it, which is worth knowing when comparing. **What stops a network-layer flood?** Three things, none of them running on your server: capacity larger than what arrives, filtering applied upstream of your link, and traffic distributed across locations so no single connection carries the whole event. All of them belong to whoever provides your connectivity. **How do I tell which layer I am facing?** Ask whether the link is saturated or the server is merely busy, because the two look similar from a browser and identical in a complaint. Saturation is a network problem you cannot solve locally; a busy server is an application problem you can. **Does this mean request inspection is unnecessary?** No. It is the only measure that addresses attacks made of valid requests, and those are the hardest kind to separate from real customers. Capacity absorbs volume; nothing but inspection distinguishes a request that should be served from one that should not. --- https://bridge-waf.com/attacks/protocol/ --- # Protocol attacks: exhausting connection state Protocol attacks consume the memory that devices use to track connections, not the bandwidth that carries them. Every connection in progress occupies an entry in a table, and those tables are finite. Fill them and legitimate clients are refused, while the traffic graph shows nothing unusual. ## Quick facts | | | |---|---| | **Layer** | Transport (4), sometimes network (3) | | **Vector** | Connection attempts that are never completed | | **Goal** | Fill connection tracking tables | | **In your logs** | Connections in a half-open state; few or no requests | | **Does a WAF stop it?** | **No.** No connection completes, so no request exists | The reason for that last row is the same one described on [attack layers](/attacks/layers/): request inspection needs a request, and here the attack succeeds precisely by never producing one. ## How a connection consumes state Opening a connection is a three-step exchange. The client asks, the server answers and waits, the client confirms. Between the second and third steps the server holds a half-open connection: memory allocated, an entry in a queue, a timer running. That waiting state is the resource. It exists to tolerate slow networks, which means it must persist for a while before being discarded. An attacker who starts connections and never confirms them fills the queue with entries that will time out eventually and are useless in the meantime. New clients arrive, find no room, and are refused. Two consequences follow, and both explain why this family is often misdiagnosed. **Bandwidth stays unremarkable.** The packets involved are small. A connection attempt costs almost nothing to send and costs the recipient memory and a timer, which is an asymmetry the attacker is exploiting. **Everything in the path is a target.** The server is not the only device tracking connections. Firewalls and load balancers maintain their own tables, and whichever has the smallest one fails first, sometimes taking down services that were not the intended target. ## The vectors in this category | Vector | Mechanism | Distinguishing property | |---|---|---| | [SYN flood](/attacks/protocol/syn-flood/) | Connection requests never completed | Half-open entries accumulate in the queue | | [ACK flood](/attacks/protocol/ack-flood/) | Packets claiming to belong to sessions that do not exist | Forces a table lookup for every packet | | [RST flood](/attacks/protocol/ack-flood/) | Reset packets against non-existent sessions | Same lookup cost, plus a risk to live sessions | The second and third share a mechanism that is less intuitive than the first. A stateful device receiving a packet that claims to be part of an existing conversation must search its table to find that conversation. The search happens whether or not the session exists, so packets referring to nothing still cost processing. Here the resource being exhausted is lookup capacity rather than table space. Netscout: TCP flood share of all attacks. Report edition and date required before any figure appears here. ## Recognising it Three observations separate this family from the others. **The server is reachable but refuses connections.** Processor usage is low, memory is fine, and yet new clients cannot connect. Nothing is overloaded in the ordinary sense: a table is full. **Connection counts are high while request counts are low.** Application logs stay quiet because the requests that would have been logged never happened. Compare this with an application-layer flood, where logs fill. **Half-open connections dominate.** Standard tooling on the server shows connections stuck in the intermediate state of the handshake, in numbers that do not correspond to any plausible user population. ## Whose table filled first Establish this first: the answer decides where any fix belongs. If services unrelated to the one under attack also stop working, the device in front of them ran out of state first. A shared firewall or load balancer failing takes everything behind it, and the symptom of an attack on one site becomes an outage across several. If only the targeted service is affected and the machine hosting it shows free memory and idle processors, the limit reached was the connection queue of that service rather than anything shared. The distinction matters because tuning the wrong device changes nothing. Enlarging a queue on a server whose firewall is the bottleneck produces no improvement and hides the real constraint, which is the sort of change that gets made under pressure and never revisited. ## Mitigation by layer Four defences, in the order they usually apply. **Hold no state until the connection proves itself.** Operating systems can answer a connection request without allocating memory, encoding what they need into the reply and reconstructing it when the client confirms. Legitimate clients complete the exchange and get their connection; attackers who never reply cost nothing. This mechanism is the direct answer to the largest vector in the category and is available on current systems. **Tune the queue and its timers.** A larger queue and a shorter wait both reduce the window an attacker exploits, within limits: too short a timeout starts refusing genuinely slow clients, which is a real trade-off on mobile networks. **Filter upstream, statelessly.** Devices that inspect packets without tracking sessions can drop malformed or clearly forged traffic without accumulating state themselves. Anything that tracks state to filter this attack is vulnerable to the attack it is filtering. **Terminate connections somewhere with capacity.** Where connections are established at a provider's edge rather than at your server, their tables absorb the attempts and your origin sees only completed sessions. What does not help is anything that reads requests: rules, challenges, and request rate limits operate on a stage this attack never reaches. ## The trade-off nobody mentions Defences here are tuning, and tuning has a cost paid by real users. Shortening the time a server waits for a client to confirm reduces exposure and also drops clients on slow or lossy connections, which is not an even distribution: it falls on mobile users and on networks far from your servers. Raising the queue size consumes memory that the application would otherwise use. That is why the mechanism that holds no state until the connection proves itself matters more than the numbers around it. It removes the trade-off rather than adjusting where it lands, and it is the change to make before touching any timer. ## Where the platform sits Bridge WAF operates on requests, which places it after the stage this family attacks, and saying otherwise would be inaccurate. What applies instead is termination: when connections are established at the platform's edge, the connection tables under attack are the platform's rather than your origin's, and your server sees sessions that already completed. Which component covers which layer is a fair question to ask any provider. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a protocol DDoS attack?** An attack that fills the tables network devices use to track connections. New clients are refused while bandwidth readings stay unremarkable, which is why it is often misdiagnosed: the resource being exhausted is memory rather than capacity, and memory does not appear on a traffic graph. **Does a WAF stop protocol attacks?** No. The connections never complete, so no request is ever formed for a firewall to inspect. Worse, a firewall that tracks connection state can itself be the device whose table fills, which makes it part of the problem rather than the defence. **Why is bandwidth normal during one?** Because a connection attempt is a very small packet, and the cost of it falls on the recipient rather than the sender. Each one occupies an entry in a table that is finite, so a stream too small to register on a graph can still exhaust the resource that matters. **What is the main defence?** Answering connection requests without reserving memory until the client proves it is really there, which moves the cost back onto the sender. This behaviour is standard on current operating systems and generally engages automatically once the pending queue comes under pressure. **Can my firewall stop it?** Only if it does not need to track connection state to make the decision. A device that tracks connections has a table of its own, and the same traffic exhausts it just as readily as it exhausts the server, so the protection fails before the thing it protects. **How do I confirm it?** Look for the combination rather than any single reading: many connections in a half-open state, processor usage that is low rather than high, and an application log showing few requests. Together those three rule out both a volumetric flood and an ordinary traffic surge. --- https://bridge-waf.com/attacks/protocol/ack-flood/ --- # ACK flood: exhausting lookups rather than memory An ACK flood sends packets that claim to belong to conversations already in progress. The difference from a [SYN flood](/attacks/protocol/syn-flood/) is where the cost lands: that one fills the queue of pending connections, while this one makes every device tracking sessions search its table for one that does not exist. Nothing is allocated; the search happens anyway. ## Quick facts | | | |---|---| | **Layer** | Transport (4) | | **Vector** | Packets referencing sessions that were never established | | **Goal** | Consume lookup capacity on anything tracking state | | **In your logs** | High packet rates, no new sessions, application idle | | **Does a WAF stop it?** | **No.** No request exists; the traffic is below that layer | The reasoning is on [attack layers](/attacks/layers/). ## Why a lookup is a resource Devices that track connections keep a table of active sessions. When a packet arrives claiming to be part of one, the device has to find the matching entry before it can decide anything: whether to forward the packet, whether it is in sequence, whether it belongs to a permitted flow. That search is the cost. It happens before the device learns that the session does not exist, which means traffic referring to nothing still consumes the same work as traffic referring to something. Multiply by a sufficient packet rate and the device spends its capacity looking things up. Three consequences follow, and they explain why this vector persists alongside better-known ones. **Defences aimed at connection setup do not apply.** The mechanism that avoids allocating memory for pending connections addresses a different stage. These packets do not ask to establish anything. **The target is often not the server.** Firewalls, load balancers, and address translation devices all maintain session tables, and they are frequently the component with the least headroom. The server behind them can be entirely healthy while nothing reaches it. **Bandwidth may be unremarkable.** The load is packets per second rather than bits per second, which is the same distinction described on [volumetric attacks](/attacks/volumetric/): a link can look far from full while the equipment carrying it is saturated. ## RST floods: the same cost, plus a second risk The mechanism is identical, and only the second-order effect differs. A reset tells the other side that a conversation is over. Sent in volume toward sessions that do not exist, it produces the same lookup cost as the traffic above, and the defence is the same. The additional concern is narrower. A reset that matches an existing session closely enough will terminate it, which turns the flood into an interruption of working connections rather than only a load problem. Protocol implementations validate resets strictly for this reason, and the validation is what makes the outcome unlikely but not impossible. The practical consequences are two: long-lived connections are the ones with exposure to consider, and encrypted transports that carry their own session integrity are less affected than plain ones. ## Recognising it Three signals, and the combination is what distinguishes this from its neighbours. **Packet rate is high while bandwidth is moderate.** The ratio is the signature. Many small packets, not much data. **No new sessions are being established.** Unlike a connection flood, the half-open state is not filling. Unlike a genuine traffic increase, the established count does not rise either. **Load appears on network equipment rather than on the server.** Processor usage climbs on the firewall or balancer, and the application behind it reports nothing unusual because nothing is arriving. That third signal is the one that misdirects investigations. Everything on the server looks correct, which sends people looking at the application while the constraint is a device they may not administer. ## Mitigation by layer Four measures, and the order matters more here than usual. **Drop non-matching packets as early as possible.** The cheapest place to discard traffic referring to no session is the furthest point upstream that can make the decision. Each device it passes pays the lookup. **Prefer filtering that does not itself keep state.** As on any attack in this family, a device that must track sessions to filter has the same exhaustible resource as the one it is protecting. **Ask upstream for a packet rate limit.** Because the load is measured in packets rather than bits, a limit expressed in bandwidth may not engage at all while the equipment is already saturated. The limit has to be in the right unit to help. **Terminate connections where capacity is larger.** Where sessions are established at an edge, the tables and the lookups under attack belong to that edge rather than to your equipment. What does not help: request rules and challenges, since this traffic never reaches the stage where a request exists. ## Why it is often part of something larger Rarely the whole event, and knowing that changes what you look for. Because the technique targets a different resource from a connection flood and a different one again from a bandwidth flood, combining them is straightforward and effective: one component fills the queue, another consumes lookups, a third fills the link. Each has a different remedy, and addressing one while the others continue produces the impression that nothing worked. The practical response is to identify which resource is actually exhausted before choosing a measure, which is the point made on [DDoS attack types](/attacks/), and the one to return to whenever a mitigation appears to have no effect. ## Where the platform sits Bridge WAF operates on requests, which is above the layer this attack targets. What applies is termination: when sessions are established at the platform's edge, the session tables and the lookups under attack are the platform's rather than your equipment's, and your origin receives traffic that already belongs to valid sessions. Which component covers which layer is a fair question to ask any provider. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is an ACK flood?** An attack that sends packets claiming to belong to sessions which do not exist. Every one forces the devices in the path to search their session tables before concluding there is nothing to match, and the search is the cost, whatever the answer turns out to be. **How is it different from a SYN flood?** A SYN flood fills the queue of connections awaiting completion, and the defences for it work at connection setup. An ACK flood consumes the capacity to perform lookups instead, arriving after setup would have happened, so none of those defences apply to it. **Does a WAF stop ACK floods?** No. This traffic sits below the layer at which requests exist, so there is nothing for inspection to examine. The load also tends to land in front of the application rather than on it, which is why the server can look untroubled throughout. **Why does my server look fine?** Because the cost falls on whatever tracks sessions in front of it, typically a firewall or load balancer, and very little reaches the server itself. The machine you would naturally investigate is the one part of the path that is not under pressure. **Are RST floods the same thing?** The lookup cost is the same, and resets add a second concern on top of it. A reset that matches an existing session closely enough will end that session, so alongside the exhaustion there is the possibility of legitimate connections being torn down. **Will a bandwidth limit stop it?** Not reliably, and this catches people out. The pressure here is measured in packets per second while the limit is usually expressed in bits per second, so a flood of very small packets can exhaust the lookup capacity without ever approaching the configured threshold. --- https://bridge-waf.com/attacks/protocol/syn-flood/ --- # SYN flood attack: half-open connections, explained A SYN flood sends connection requests that are never completed. Each one makes the server hold a partially established connection while it waits for a confirmation that will not arrive. The queue holding those connections is finite, and once it is full the server refuses everyone, including the customers whose confirmations would have arrived. ## Quick facts | | | |---|---| | **Layer** | Transport (4) | | **Vector** | Connection requests with no completing reply | | **Goal** | Fill the queue of connections awaiting completion | | **In your logs** | Many connections in the half-open state; few requests | | **Does a WAF stop it?** | **No.** No connection completes, so no request exists | The mechanism behind that answer is on [attack layers](/attacks/layers/). ## How the handshake is turned into a resource Establishing a connection takes three messages. The client asks to connect. The server replies that it is willing and starts waiting. The client confirms, and the connection becomes usable. Between the second and third messages the server is committed: it has allocated an entry, recorded what it needs to remember about the pending connection, and started a timer. That entry stays until the confirmation arrives or the timer expires, and the timer is deliberately generous, because networks lose packets and slow clients are legitimate. An attacker sends requests and never sends confirmations. Nothing needs to be exploited and no packet needs to be malformed. The server behaves exactly as designed and runs out of room. Two details make it cheap for the sender. **No state is kept on their side.** A connection request costs one packet and no memory, while it costs the recipient memory and a timer. **Source addresses can be forged.** Because the sender never intends to complete the exchange, they do not need to receive the reply. The addresses in your counters may belong to hosts that sent nothing. ## What you see The evidence is in connection states rather than in application logs. ```text # Illustrative connection-state summary; any system prints an equivalent. # Counts are shape, not measurements. SYN_RECV dominant: the queue of connections awaiting confirmation ESTABLISHED unusually few for the volume of arriving traffic TIME_WAIT normal: leftovers from connections that did complete ``` Three readings of that picture matter. **Half-open entries dominate.** Requests arrive, replies are sent, confirmations never come. **Completed connections are scarce.** The ratio between the two states is the signal, more than any absolute count. **Processor and memory look fine.** Nothing is overloaded in the ordinary sense, which is why this is misdiagnosed as a network problem or as an application fault. ## SYN cookies: removing the resource being attacked The defence that addresses the mechanism rather than its symptoms works by not allocating anything until the connection proves itself. Instead of storing what it needs to remember about a pending connection, the server encodes that information into the reply it sends back, in a field the client is required to echo when it confirms. Nothing is kept locally. If the confirmation arrives, the server reconstructs the connection state from what came back and proceeds. If it never arrives, nothing was spent. The effect is that a flood of unanswered requests costs the server nothing beyond the replies themselves, while legitimate clients are unaffected because they complete the exchange as they always did. **The honest trade-off.** The space available for encoding is small, so some optional connection features negotiated during the handshake may not survive when the mechanism engages. Implementations differ in how much they preserve. This is why the mechanism is typically applied only when the queue is under pressure rather than at all times: normal traffic keeps the full feature set, and the degradation applies only while it is needed. ## Other measures, and their limits **Enlarging the queue** raises the volume required to fill it and consumes memory that the application would otherwise have. It buys time rather than solving anything. **Shortening the wait** frees entries sooner and drops clients on slow or lossy paths, which falls unevenly on mobile networks and distant regions. **Stateless filtering upstream** removes traffic before it reaches anything that tracks connections. Note the requirement: a device that itself tracks state to filter this attack has the same table and the same limit. **Terminating connections at an edge with capacity** moves the queue under attack somewhere with more of it, leaving your origin to see only sessions that already completed. ## Why it persists despite a known defence The mechanism above has been standard for a long time, which raises a fair question: why is this attack still worth a page. Three reasons, and they are all about where the defence is not. **The server is not the only thing holding state.** Firewalls, load balancers, and address translation devices in the path track connections too, and the protection on the server does nothing for them. Whichever device has the smallest table and no equivalent mechanism fails first. **The reply still costs something.** Answering a request is cheap, but at sufficient volume the replies themselves consume outbound capacity and packet-processing headroom. The queue survives; the link may not, which turns the event into the volumetric problem instead. **Attackers can complete the handshake.** Where connections are finished and then abused, the attack moves up a layer and becomes an application problem, which is a different defence entirely. The mechanism here removes one technique rather than the whole category. ## Telling it apart from things that look similar Two lookalikes, and both are common. A genuine traffic spike produces many connections that do complete: the established count rises alongside the half-open count. In a flood the second rises alone. A broken client or a failing network path produces the same half-open pattern from a small number of sources, with a steady rhythm, and it stops when the other side is fixed. The distinction is the number of distinct sources and whether the pattern adapts when you change something. ## Where the platform sits Bridge WAF operates on requests, which places it after the stage this attack targets. What applies is termination: connections are established at the platform's edge, so the queue absorbing unfinished handshakes is the platform's rather than your origin's, and your server sees sessions that already completed. Which component covers which layer is a fair question to ask any provider. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a SYN flood?** An attack that opens connections and never finishes them, filling the queue a server keeps for connections awaiting completion. Once that queue is full, further clients are refused, and the ones being refused are the legitimate ones still trying to finish properly. **Does a WAF stop SYN floods?** No. The connections never complete, so no request is ever produced for inspection to read. The defence sits in the operating system's handling of pending connections and in upstream filtering, both below the layer a firewall of this kind operates on. **What are SYN cookies?** A mechanism that removes the resource being attacked. Instead of reserving memory for a pending connection, the server encodes what it would have stored into its own reply, and reconstructs the state only when the client returns it. A sender that never returns costs nothing at all. **Do SYN cookies have a downside?** A small one. Some optional parameters negotiated while the connection is being established cannot be carried through the mechanism, so connections made while it is active may lose them. That is why systems generally engage it only once the queue is under pressure. **Why does my server look idle during one?** Because nothing is actually being processed. The exhausted resource is a queue with a fixed size, and a full queue produces no processor load, no disk activity, and no application log entries. Every conventional health indicator reads normal while the service is unreachable. **Can I block the addresses a SYN flood comes from?** Usually not to any effect. The sender never needs to receive the reply, so the addresses in the packets can be forged freely and will differ from one packet to the next. Blocking them denies service to whoever genuinely holds those addresses. --- https://bridge-waf.com/attacks/ransom-ddos/ --- # Ransom DDoS: why paying does not end the threat at all Ransom DDoS is an extortion demand attached to a denial-of-service threat. Sometimes an attack accompanies it, sometimes a short demonstration precedes it, and sometimes there is nothing behind the message at all. The technical side is whatever family the traffic belongs to. What is different is that you are being asked to make a decision under time pressure. ## Quick facts | | | |---|---| | **Layer** | Any: the demand is separate from the technique | | **Vector** | A message, with or without traffic behind it | | **Goal** | Payment, not disruption | | **In your logs** | Possibly nothing; the demand arrives by email | | **Does a WAF stop it?** | It addresses the attack, not the demand | That last row is the honest framing. No product resolves an extortion attempt. What defences do is remove the lever the demand relies on. ## The three shapes it takes **A threat with nothing behind it.** A message announcing an attack on a future date unless payment arrives. Sending these costs nothing and they can be sent to thousands of organisations at once, so the sender does not need any capability for the approach to be profitable. Most recipients of this kind never see an attack. **A demonstration followed by a demand.** A short burst of traffic, enough to be noticed, then a message referring to it. This is more serious, because capability has been shown, though the size of a demonstration says little about what can be sustained. **A demand during an ongoing attack.** The pressure is real and immediate, and it is also the situation where a decision made in the first hour is most likely to be wrong. ## Judging whether a demand is credible Four questions separate a bulk message from a targeted one. **Is anything specific to you in it?** Bulk extortion mentions no detail that could not be scraped: your domain, an industry, a generic sum. Targeted messages reference infrastructure the sender had to look at. **Was anything demonstrated?** A claim with no traffic behind it is a claim about the future made by someone with an incentive to exaggerate. **Is the timeline structured to prevent thinking?** Short deadlines and escalating penalties are a pressure technique rather than an operational necessity. **Does the same message exist elsewhere?** Bulk campaigns are widely reported, and the text is often identical between recipients. Checking whether others received the same message costs nothing and settles most cases. ## Why paying does not resolve it Four reasons, and they hold regardless of what the message promises. **Nothing is delivered in exchange.** There is no product being sold. A payment buys a promise from an anonymous party with no obligation and no reputation to protect, and the only enforcement available to you is hoping. **It identifies you as someone who pays.** That information has value to the recipient and to anyone they share it with. Organisations that pay are approached again, sometimes by different parties, sometimes with the previous payment cited as evidence that the approach works. **It funds the capability being used against you.** Extortion continues because it is profitable, and each payment sustains the infrastructure that makes the next threat credible. **It changes nothing about your exposure.** Whatever made you a viable target still applies the day after the payment clears. The absence of an attack afterwards is indistinguishable from an attack that was never coming. There is also a legal dimension that depends entirely on where you are and who the recipient turns out to be. Payments to sanctioned parties carry consequences separate from anything in the threat itself, which is a question for a lawyer before it is a question for an engineer. ## What to do instead Five steps, in order. **Do not reply.** A response confirms the address is live and the recipient is engaged, which is the qualifying signal a bulk campaign is looking for. **Preserve the message.** Full headers included. It is evidence, and it is also what lets anyone else determine whether the campaign is known. **Tell whoever carries your traffic.** Your connectivity provider and any platform in front of you can prepare capacity and filtering before a deadline rather than during an incident. This is the single most useful call to make. **Report it.** Extortion is a criminal matter in most jurisdictions, and reports are how bulk campaigns get identified as bulk. **Check what would actually happen.** The deadline is a free opportunity to review capacity, rate limits, and whether anyone knows who to call. That work has value whether or not anything arrives. ## Preparing without panicking The useful posture is unglamorous and mostly consists of decisions made in advance. Know where traffic terminates and who can absorb volume, because the answer determines whether an attack is your problem or your provider's. Know which of your endpoints are expensive, since those are what an application-layer attack will find. Have a way to reach the people who can act outside working hours, and agree beforehand who decides. And decide the payment question now, in writing, while nobody is under pressure. A policy written calmly is what prevents a decision made at three in the morning by whoever happened to be awake. ## Mitigation, honestly stated The demand is not a technical event, and the traffic behind it is ordinary traffic belonging to one of the families described on [DDoS attack types](/attacks/). Defence is therefore the same as it would be without the message: capacity for what saturates links, connection handling for what exhausts state, and request limits for what exhausts the application. Bridge WAF covers the last of those: requests are inspected before reaching your origin, and rate limiting is applied per domain. Because traffic terminates at the edge, the capacity in front of you is the platform's rather than your link's. What no product provides is a resolution to the extortion itself, and any that claims to is selling something else. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is ransom DDoS?** An extortion demand attached to a denial-of-service threat, which may or may not have any capability behind it. The message is the event: sometimes an attack accompanies it, sometimes a short demonstration precedes it, and sometimes there is nothing at all. **Should I pay?** The four arguments against are independent of each other: payment buys an unenforceable promise from an anonymous party, marks you as somebody who pays, funds the capability being used against you, and leaves your exposure exactly as it was. Legal consequences depend on jurisdiction and on who the recipient turns out to be. **Are these threats usually real?** Many are bulk messages sent to great numbers of organisations at once, with nothing behind them, because sending costs the sender nothing. What separates a targeted threat is specificity that could not be scraped, and traffic actually demonstrated rather than described. **What should I do first?** Three things, in order: do not reply, since a reply confirms a live and engaged recipient; preserve the message with its full headers as evidence; and tell whoever carries your traffic, so capacity and filtering can be arranged before the deadline rather than during an incident. **Does a WAF stop ransom DDoS?** It addresses the application-layer traffic, if traffic arrives at all, in exactly the way it would without any message attached. What no product resolves is the demand itself, and anything claiming to resolve extortion is selling something other than what it says. **Will they come back if I do not pay?** Possibly, and the odds are worse if you do pay. A payment is the clearest available signal that the approach works on you, and that information has value both to the recipient and to anybody they choose to share it with. --- https://bridge-waf.com/attacks/volumetric/ --- # Volumetric attacks: filling the link Volumetric attacks work by sending more traffic than your connection can carry. The content is irrelevant; the volume is the weapon. Because the link saturates before packets reach your server, nothing running on the server changes the outcome, which is what separates this family from every other kind of attack. ## Quick facts | | | |---|---| | **Layer** | Network (3) and transport (4) | | **Vector** | High-volume traffic toward your addresses | | **Goal** | Saturate link capacity | | **In your logs** | Often nothing: traffic never reaches the application | | **Does a WAF stop it?** | **No.** Request inspection happens after arrival | That last row is the honest answer and the reason this category is documented separately. The mechanism behind it is on [attack layers](/attacks/layers/). ## Why volume alone is enough A link has a fixed capacity. When arriving traffic exceeds it, the excess is discarded somewhere upstream, and the discarding does not distinguish between an attack and a customer. Legitimate requests are dropped in the same proportion as everything else, which is why the site becomes unreachable rather than slow. Nothing has to be exploited for this to work. No vulnerability, no malformed packet, no clever request. The attack succeeds by arithmetic, and the only variable that matters is whether the attacker can generate more traffic than the target can absorb. ## Amplification: why this is cheap The arithmetic changes when an attacker does not have to send the traffic themselves. Certain services answer a small request with a much larger response. If the request carries a forged source address, the response is delivered to that address instead of to the sender. The attacker sends a little; the service sends a lot; the victim receives all of it. The ratio between the two is what makes this the dominant technique in the category. Two properties follow, and both matter for defence. **The traffic comes from legitimate servers.** The machines flooding you are not compromised, and they are doing what they were designed to do. Blocking them by address is endless, because there are always more. **Forged source addresses are the enabling condition.** Networks that verify traffic leaves them with addresses they own remove the possibility at the source. That is a property of other people's networks rather than of yours, which is why the technique persists. ## The vectors in this category | Vector | Uses | Distinguishing property | |---|---|---| | [UDP flood](/attacks/volumetric/udp-flood/) | Connectionless traffic to arbitrary ports | No handshake, so volume is trivially generated | | [ICMP flood](/attacks/volumetric/icmp-flood/) | Diagnostic protocol traffic | Older and simpler; blocking it badly breaks connections | | [NTP amplification](/attacks/volumetric/ntp-amplification/) | Time servers with a legacy query enabled | The reply is far larger than the request | | [Memcached](/attacks/volumetric/memcached-ddos/) | Caching servers exposed to the internet | Reply size is not bounded by the protocol | One vector deliberately sits elsewhere. Amplification through the domain name system belongs with the naming layer of this network, where the record types and the resolver behaviour that make it possible are already explained, and duplicating it here would describe the same mechanism twice in two places. ## Two ways a link fails Capacity is usually described in bits per second, and that single figure hides a second limit. Equipment that handles traffic also has a ceiling on how many packets it can process each second, independent of how large those packets are. An attack made of very small packets can reach that ceiling while the bandwidth figure still looks comfortable. The link is not full; the device forwarding traffic across it is. The practical consequence is that "we have plenty of bandwidth" is not by itself an answer. Where an outage happens well below the nominal capacity of a connection, the packet rate is the thing to look at, and the bottleneck is a router or firewall rather than the pipe. ## Recognising it The signature of this category is what you cannot see. **Your own monitoring goes quiet.** Graphs stop updating because the data cannot get out over a saturated link. An absence of information during an outage is itself a signal. **Upstream sees traffic you never do.** Whoever provides your connectivity can tell you the arriving volume and its shape. That conversation is the fastest way to confirm the category, and it is often the only source of evidence. **Application logs look normal, then stop.** No error pattern, no unusual requests, just fewer entries and then none. Compare this with an application-layer attack, where logs fill rather than empty. ## After it stops Recovery is not automatic, and two effects catch people out. Clients that failed during the outage retry, often all at once and often more aggressively than normal traffic. The first minutes after the flood subsides can carry a load spike that has nothing to do with the attacker. And whatever was blocked during the incident stays blocked until someone removes it. Emergency filters are written under pressure, applied broadly, and forgotten, which turns a finished attack into a quiet loss of legitimate traffic that shows up weeks later as an unexplained drop. ## Mitigation by layer Three things work, and they sit in a specific order. **Capacity upstream.** Absorbing the traffic requires more capacity than the attack generates. This is the only defence that addresses the mechanism directly, and it is infrastructure rather than configuration. **Filtering before your link.** Traffic can be dropped by whoever carries it, based on properties visible in packets. Coarse but effective, and it must happen upstream to matter: filtering on your own equipment discards traffic that has already consumed the resource it was targeting. **Not being the reflector.** Services that answer unauthenticated queries should not be reachable from the whole internet. This does not protect you from being a victim; it stops your servers from becoming the source of someone else's attack, which is a responsibility rather than a defence. What does not work is anything applied at the application: rules, challenges, and request limits all operate on requests that, in this category, were never made. ## Where the platform sits Bridge WAF inspects requests at the application layer, which is the wrong layer for this family and is stated plainly for that reason. What does apply is where traffic terminates: when requests are served from the platform's edge rather than from your origin, the capacity in front of you is the platform's, and your origin's link stops being the constraint that a volumetric attack targets. Which component covers which layer is a fair question to ask any provider. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a volumetric DDoS attack?** An attack that delivers more traffic than your connection can carry. The site becomes unreachable regardless of how the server is configured or how much capacity it has, because the loss happens on the link before anything reaches the machine that would handle it. **Does a WAF stop volumetric attacks?** No, and it is worth being direct about that. Request inspection operates on requests, and in a volumetric attack the link saturates before requests arrive at all. Legitimate traffic is lost in the same congestion, which is why the answer has to come from upstream capacity. **Why is amplification so common?** Because it separates the volume delivered from the capacity the sender needs to own. Third-party servers do the sending, in response to requests that appear to come from the target, so the traffic arriving is far larger than anything the originator transmitted. **Can I block the addresses a volumetric attack comes from?** Rarely to any effect. In amplification the senders are real, legitimate servers being abused, and there are always more of them; in direct floods the addresses can be forged outright. Blocking also happens on your side of the saturated link, where the traffic has already arrived. **How do I confirm this is what is happening?** Ask whoever carries your connectivity what volume is arriving at your edge, because your own monitoring sits behind the congestion and may never see it. A link that is full reports very little about what filled it, which is why the upstream view is the one that settles the question. **Does more server capacity help?** No, and this is the most expensive mistake available during an incident. The constraint is the link and the equipment carrying it, not the machine behind them, so a larger server sits equally idle behind an equally full connection, having cost money during an incident and changed nothing. --- https://bridge-waf.com/attacks/volumetric/icmp-flood/ --- # ICMP flood: the attack that punishes a careless fix An ICMP flood sends large volumes of diagnostic messages, usually echo requests, toward your addresses. Each one that gets answered costs you outbound capacity as well as inbound, so a system responding correctly becomes part of the load. The attack is simple; the damage usually comes from how it is stopped. ## Quick facts | | | |---|---| | **Layer** | Network (3) | | **Vector** | High volumes of echo requests or other ICMP messages | | **Goal** | Consume link capacity in both directions | | **In your logs** | Interface counters; nothing in application logs | | **Does a WAF stop it?** | **No.** No connection, no request, nothing to inspect | The mechanism behind that answer is described on [attack layers](/attacks/layers/): this traffic does not reach the stage where requests exist. ## How it works ICMP is the protocol systems use to report problems and to test reachability. An echo request asks a host to confirm it is there; an echo reply confirms it. Both are small, and neither requires a connection. A flood exploits two properties of that exchange. **The reply doubles the cost.** A host answering echo requests spends outbound bandwidth in proportion to what arrives. Where the inbound flood is already near capacity, the replies compete with your own traffic for the remaining room. **Source addresses can be forged.** As with any protocol that needs no session, what appears in your counters is not necessarily the sender, and replies may be travelling to a host that never asked. That second case makes your machine a participant rather than only a victim. The technique is old and remains in use because it needs nothing sophisticated. It is closest in shape to the [UDP flood](/attacks/volumetric/udp-flood/), and the two are frequently combined in the same event. ## Ping of death is a different thing The names get used interchangeably, and the distinction decides what you should worry about. A ping flood is a volume problem: well-formed messages in quantities that exhaust a link. The historic vulnerability known as ping of death was not about volume at all. It involved a single malformed message assembled in a way that overflowed buffers in network stacks of that era, crashing the host outright. It was a software defect, it was fixed in every mainstream system a long time ago, and there is nothing to configure about it today. The practical consequence: if someone proposes disabling diagnostics because of ping of death, they are protecting against a defect that no longer exists, at the cost of the trade-off described below. ## Before you block all ICMP **Warning:** discarding every ICMP message is the most common response to this attack and it breaks working connections in ways that are difficult to diagnose later. Systems negotiate the largest packet size a path can carry by sending traffic and being told, through ICMP, when something is too large to pass. Remove those messages and the sender learns nothing: packets vanish silently, connections establish and then stall, and the failure appears only for clients whose path has a smaller limit somewhere. Typical symptoms are a page that starts loading and never finishes, or transfers that work from one network and hang from another. The effect is worse for modern connections, where routers do not fragment traffic on the sender's behalf and the notification is the only mechanism available. So the rule is narrow rather than absolute: limit echo traffic, keep the messages that report problems. ## Recognising it Three signals, and the third is the one people miss. **Interface counters rise while the application is idle.** The same picture as any volumetric attack: traffic arrives, nothing is served. **Outbound volume rises alongside inbound.** Distinctive to this family. If your egress graph mirrors your ingress graph during an outage, something is being answered at scale. **Diagnostics stop being useful.** The tools you would reach for to investigate use the same protocol being flooded, so their results become unreliable precisely when you need them. ## Mitigation by layer Four measures, in order of usefulness. **Rate limit echo traffic, do not discard the protocol.** Answering a reasonable number of requests and dropping the excess preserves diagnostics while removing the lever. This is the correct default and it belongs as far upstream as possible. **Filter before your link.** As with every volumetric attack, traffic removed after it crosses your connection has already done its work. Your connectivity provider can drop by protocol and rate at their edge. **Keep the messages that report problems.** Specifically the ones that report a packet was too large to pass. These are not optional, and treating them as noise is what produces the failures described above. **Do not answer on behalf of things you do not run.** Where a network is configured to respond to messages addressed to it as a group rather than individually, a single forged request can produce many replies toward a victim. Current defaults suppress this, so confirm it rather than assuming. What does not help: request rules, challenges, and anything that inspects traffic after it has arrived, for the same reason as every other attack in this category. ## What to do while it is happening Two things to do in the moment, and neither is a permanent change. **Ask upstream for a rate limit rather than making one locally.** A limit applied on your own equipment still receives the traffic and still spends the link. The same limit applied by whoever carries your connectivity removes it before the cost is paid, and they can usually put one in place quickly on request. **Write down what you changed.** Emergency measures against this attack are the kind that survive it: a protocol discarded wholesale, a diagnostic tool silenced, a filter added at three in the morning. Each one looks harmless afterwards and each one degrades something later. A note saying what was changed and why is what makes removal possible. Neither step requires knowing who is sending the traffic, which is convenient, because you probably cannot find out. ## Where the platform sits Bridge WAF operates on requests, so it does not address this attack, and saying otherwise would be inaccurate. What applies is where traffic terminates: when visitors reach your site through the platform's edge, the addresses being flooded are not your origin's, and the capacity absorbing volume is the platform's. Which component covers which layer is a fair question to put to any provider. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is an ICMP flood?** An attack that sends large volumes of diagnostic messages, usually echo requests, to consume link capacity. It consumes that capacity in both directions at once, because a system answering those messages spends outbound bandwidth in proportion to what arrives, which is what distinguishes it from a flood the target simply absorbs. **Does a WAF stop ping floods?** No. This traffic never becomes an application request, so request inspection has nothing to examine and nothing to act on. What helps is rate limiting the message type upstream, where it can be discarded on capacity large enough to absorb it, rather than on the link you are trying to keep clear. **Should I block ICMP entirely?** No, and this is the response that causes lasting damage. Blocking all of it breaks the mechanism that tells a sender a packet was too large, which produces connections that stall rather than fail and are notoriously hard to diagnose afterwards. Rate limit echo traffic instead. **Is this the same as ping of death?** No, and the names invite the confusion. That was a defect in old network software, where a malformed message crashed the system receiving it, and it was fixed long ago. A flood exploits no defect at all: it is ordinary traffic in quantities the link cannot carry. **Why does my outbound traffic rise during one?** Because your system is politely answering every message. Each echo request produces a reply of comparable size, so inbound volume converts almost directly into outbound volume, and a link congested in one direction becomes congested in both. Rate limiting the replies is what breaks that conversion. **Can I tell who is sending it?** Usually not from your own counters. Source addresses can be forged, which means the replies you generate may be travelling to a host that never sent anything and is experiencing your traffic as an attack of its own. The upstream view is the one worth asking for. --- https://bridge-waf.com/attacks/volumetric/memcached-ddos/ --- # Memcached DDoS: an exposed cache is two problems A caching server reachable from the internet can be made to send large replies to an address that never asked for them, and the same exposure lets anyone read what the cache holds. The traffic problem belongs to whoever receives the replies; the disclosure problem belongs to whoever left the cache open, and it is usually the more serious. ## Quick facts | | | |---|---| | **Layer** | Network (3) and transport (4) | | **Vector** | Forged requests to exposed caching servers, replies sent to you | | **Goal** | Saturate the link with unrequested replies | | **In your logs** | Inbound traffic from a cache service you never queried | | **Does a WAF stop it?** | **No.** The traffic never becomes a request | The reasoning is the same as for every attack in this family and is set out on [attack layers](/attacks/layers/). ## Why this vector is different from the others Amplification always depends on a reply being larger than a request. What distinguishes this case is that the size of the reply is not fixed by the protocol. With a time service, the response is whatever that service produces. With a cache, the response is whatever the cache holds, and a cache holds what was put into it. An amplifier whose output size is not bounded by protocol design behaves differently from one where it is, and that difference is the entire reason this vector attracted attention. Reported amplification ratios and the dates of specific incidents require a cited source before any figure or claim of record size appears here. Two design properties made exposure common. The software was built for communication inside a trusted network, so authentication was not part of the model. And it historically accepted connectionless traffic by default, which is the property amplification needs, since a request with a forged return address gets answered to that address. Current builds ship with that default reversed, so the exposed population comes from older deployments and from configurations written when the default was different. ## The problem that is worse than the traffic If your cache is reachable from the internet, someone else's outage is not your largest concern. A cache with no authentication returns what it stores to anyone who asks. Sessions, tokens, query results, fragments of pages assembled for particular users: whatever the application put there is readable, and reading it leaves no trace in the application's own logs, because the application was not involved. This is why the recommendation below is not "rate limit" but "do not expose it". The amplification is a symptom. The exposure is the defect, and it has consequences that continue after the attack traffic stops. ## The check worth running today Three questions, answerable without any tooling beyond what you already have. **What interface is it listening on?** A cache should be bound to a loopback or private interface. If it is bound to every interface, the question of whether a firewall happens to be in front of it becomes the only thing protecting it. **Is connectionless traffic accepted?** Where the deployment predates the current defaults, this may still be enabled and unused. Turning it off removes the amplification property entirely while changing nothing about how applications use the cache. **Can anything outside your own network reach the port?** Confirm from outside rather than by reading configuration. Configuration describes intent; a connection test describes reality, and the two diverge in the cases that matter. ## Why exposed caches keep appearing The population of open caches shrinks slowly, and understanding why turns the check above into a routine rather than a one-off. Caches are added during development, on a machine that was never meant to face the internet, and the exposure arrives later when that machine moves, gets a public address, or has a firewall rebuilt without the rule that was protecting it. Nothing in the application changes, nothing fails, and nobody has a reason to look. Container and orchestration setups add a second path to the same outcome. A service published for convenience during testing behaves identically in production, and the mapping that exposes it is a line of configuration rather than a visible decision. The common factor is that exposure is never announced. A cache that is suddenly reachable from everywhere works as well as one that is not, which is why the only reliable detection is a deliberate check from outside. ## Recognising it as the victim Two signals, the same as for other reflection vectors. **Replies you never requested,** arriving from a service port you do not use, from many distinct sources. **Sources that genuinely exist.** They are real servers, misconfigured rather than compromised, and blocking them individually is an endless task with no end state. Because the reply size is unusually large in this vector, the traffic tends to saturate a link with fewer participating sources than other reflection techniques require. From the receiving side that changes nothing about the response. ## Mitigation by layer Four measures, split by which role you are in. **As the victim: filter upstream.** Replies from a protocol you never query can be discarded before your link, and this is a rule a connectivity provider can apply quickly. Nothing on your server helps. **As the victim: have capacity in front of you.** Absorbing volume is infrastructure, as it is for the whole family. **As an operator: bind the cache privately and firewall the port.** This single change removes both problems, the traffic one and the disclosure one. **As an operator: disable connectionless traffic and require authentication where the deployment supports it.** Defence in depth for the case where a firewall rule is removed by someone who does not know why it was there. What does not help: request inspection, rules, and challenges, for the usual reason that nothing here becomes a request. ## Where the platform sits Bridge WAF operates at the application layer and does not address traffic of this kind. What applies is termination: when visitors reach your site through the platform's edge, the address receiving reflected traffic is not your origin's, and volume is absorbed by the platform's capacity rather than your link's. What no platform can do is fix an exposed cache, which is a configuration question on your own infrastructure. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a memcached DDoS attack?** An attack in which requests carrying a forged return address are sent to caching servers exposed to the internet, so their much larger replies are delivered to the address on the forgery. The caches are victims of a kind too, spending their own capacity on it. **Does a WAF stop a memcached attack?** No. The traffic arrives as volume and never becomes an application request, so there is nothing for inspection to act on. As with every attack in this family, the answer is upstream capacity and filtering rather than anything running behind the link. **Why are the replies so large?** Because a cache returns whatever it was asked to store, so the size of a reply is set by its contents rather than fixed by the protocol as it is for most services. That is what distinguishes this family from amplification through services with bounded answers. **Is my own cache at risk?** If it answers from the internet, yes, and the more serious problem is not the traffic. A cache of this kind expects to sit on a trusted network, so anything reachable from outside will also hand its contents to whoever asks, which is a data exposure rather than a capacity one. **How do I check?** Three things, in order: which interface the service listens on, whether it accepts connectionless traffic at all, and whether the port answers from outside your own network. The last is the only one that settles it, because a binding that looks internal can still be exposed by what sits in front. **Does authentication solve it?** It helps and it is not the answer. Requiring credentials narrows who can retrieve data, but the service still answers strangers enough to be used, and the design assumption was always a trusted network. Keeping it off the public internet is the measure that actually holds. --- https://bridge-waf.com/attacks/volumetric/ntp-amplification/ --- # NTP amplification: when a time server answers for you Amplification turns someone else's server into the source of your outage. A small query goes to a public service with a forged return address, the service replies to that address rather than to the sender, and the reply is far larger than the request. Time servers became a favoured instrument because one legacy query returns a great deal of data. ## Quick facts | | | |---|---| | **Layer** | Network (3) and transport (4) | | **Vector** | Forged queries to public time servers, replies directed at you | | **Goal** | Saturate the link with traffic you never asked for | | **In your logs** | Inbound replies from time services you never queried | | **Does a WAF stop it?** | **No.** The traffic never becomes a request | The reasoning is on [attack layers](/attacks/layers/): this arrives as volume, and request inspection happens after volume has already done its work. ## The mechanism Three properties combine, and removing any one of them ends the technique. **The protocol needs no connection.** Queries and replies are single messages, so nothing verifies that the sender is who the address says. **The return address can be forged.** The service answers the address in the query, and that address is the victim's. **One legacy query returns disproportionate data.** Older time server software supported an administrative query that returned a list of recent clients. A short request produced a long answer, which is precisely the property amplification needs. It exists for diagnostics, it was never meant to be reachable from the whole internet, and current software disables or removes it. Amplification ratios for this and other vectors require a cited source with a date before any figure appears here. The pattern is not specific to time services. Any protocol that answers unauthenticated queries with larger replies can be used the same way, which is why the defence is structural rather than a matter of blocking one service. ## SSDP: the same shape in home equipment The mechanism is identical, and only the population differs. Service discovery on local networks works by asking connected devices to announce what they offer. The replies are verbose by design, and the protocol assumes a local network where that is harmless. Consumer routers that expose this to the internet, usually by accident, become reflectors the way an exposed time server does. Two things follow. The reflector population is enormous and consists of devices nobody administers, so it does not shrink the way server misconfigurations do. And from the victim's side it is indistinguishable from any other amplification: high volume from sources with no relationship to you. ## Two roles, and one of them is yours to check Every amplification event has a victim and a set of unwitting participants. You can be either. **As the victim**, nothing about your configuration caused it and nothing about your configuration stops it. The traffic is legitimate replies from legitimate servers, and the only remedy is upstream. **As a potential reflector**, you have work to do. Any service you run that answers queries from anywhere, and answers them with more data than it received, is a candidate. For time services specifically, the administrative query class should not be reachable from the internet, and software current enough to have removed it is the simpler fix. This second role is the one most people never check. Being used as a reflector does not degrade your service noticeably, produces no alerts, and is visible only as outbound traffic nobody looks at. ## How you learn you were a reflector Rarely from your own monitoring, which is the problem. The usual notification is external: an abuse report from a network on the receiving end, or a message from your hosting provider forwarding one. By then the traffic has been leaving your server for a while, billed to you, and attributed to you by everyone who saw it. The check that prevents this costs a few minutes and belongs in the same routine as any other exposure review: confirm which services answer queries from outside, and whether any of them answers with more than it received. ## Recognising it Two signals distinguish it from an ordinary flood. **Replies you never requested.** Inbound traffic from a service port belonging to a protocol you did not query, from many sources at once. That is the signature: not requests arriving, but answers. **Sources are real and reachable.** Unlike forged floods, these addresses belong to servers that genuinely exist and respond. Anyone investigating will find working services at the other end, which is why blocking them is both possible and pointless: there are always more. ## Mitigation by layer Four measures, and the first two are the only ones that help a victim. **Filter upstream by source characteristics.** Replies from a protocol you never use can be dropped before your link, and this is a rule your connectivity provider can apply quickly. **Have capacity in front of you.** As with every attack in this family, absorbing volume is infrastructure rather than configuration. **Do not run open reflectors.** Restrict administrative query classes to the networks that need them, keep software current, and confirm that services intended for internal use are not reachable from outside. This protects other people rather than you, which is why it gets skipped. **Support source address validation.** Networks that verify traffic leaves them carrying addresses they own make forgery impossible at the origin. No individual operator can deploy this on someone else's network, which is why the technique persists despite being solvable in principle. What does not help: request rules and challenges, since nothing here reaches the stage where a request exists. ## A vector that belongs to another layer The same reflection mechanism applies to the naming system, and that case belongs to the naming layer of this network, where resolver behaviour and record types are documented. ## Where the platform sits Bridge WAF inspects requests, which is the wrong layer for this attack. What applies is termination: when visitors reach your site through the platform's edge, the address receiving reflected traffic is not your origin's, and the capacity absorbing volume is the platform's. Asking which component covers which layer is a fair question for any provider, including us. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is NTP amplification?** An attack in which small queries carrying a forged return address are sent to public time servers, so that their much larger replies are delivered to the address on the forgery. The target receives traffic from servers that believe they are answering it. **Does a WAF stop amplification attacks?** No. What arrives is volume rather than requests, and it fills the link before anything resembling a request exists for inspection to read. Mitigation belongs upstream, with whoever is able to absorb or discard the traffic before it reaches a connection small enough to be saturated by it. **Why time servers specifically?** Because of one legacy administrative query that returned a list of recent clients, turning a short request into a long answer. That disparity is the whole mechanism. Current software disables the query by default, which is why the technique depends on servers nobody has updated. **Can I block the servers sending it?** You can, and it accomplishes little. They are genuine servers being abused rather than the originator, there are always more of them, and the blocking happens on your side of a link that the traffic has already crossed and filled. **How do I know my own server is not being used?** Confirm that administrative queries are unreachable from the internet and that anything intended for internal use is not answering from outside. This is worth checking whether or not you are a target, since being used as a reflector consumes your capacity for someone else's attack. **Is SSDP the same thing?** The mechanism is identical and the population differs. There the reflectors are consumer devices exposing a local discovery protocol to the internet, rather than servers running outdated software, which makes the set of reflectors larger and far less likely ever to be corrected. --- https://bridge-waf.com/attacks/volumetric/udp-flood/ --- # UDP flood: volume without a conversation A UDP flood sends large volumes of connectionless packets toward your addresses. Nothing has to be established first, nothing has to be answered, and the sender keeps no state. That combination is what makes the technique the simplest way to turn available bandwidth into an outage. ## Quick facts | | | |---|---| | **Layer** | Transport (4), effect at the network layer | | **Vector** | High volumes of UDP packets to arbitrary ports | | **Goal** | Saturate the link or the packet-processing capacity in front of it | | **In your logs** | Firewall and interface counters only; application logs stay quiet | | **Does a WAF stop it?** | **No.** The traffic never becomes a request | The reason is on [attack layers](/attacks/layers/): inspection happens after arrival, and this attack succeeds by consuming what carries traffic rather than what processes it. ## Why the protocol makes this cheap UDP has no handshake. A sender does not wait for permission, does not maintain a session, and does not need a reply to consider the packet delivered. Each packet is independent, which is what makes the protocol useful for real-time traffic and what makes it convenient here. Three properties follow. **Volume scales with bandwidth alone.** The attacker's own machine keeps no per-connection state, so the only limit is what their network can emit. **Source addresses can be forged.** Because nothing is returned to the sender, a packet can carry any source address and still do its job. Blocking what you see in the counters therefore blocks addresses that may have nothing to do with the sender. **Closed ports cost you twice.** A packet arriving at a port with no listener normally produces an error response. Under flood conditions, generating those responses consumes processing and outbound capacity, which turns your own correctness into part of the load. ## What it looks like on your side The evidence lives in counters rather than in application logs. ```text # Illustrative firewall counter summary, one interval. # Values are shape, not benchmarks; addresses per RFC 5737. proto=UDP src=198.51.100.0/24 dst=203.0.113.10 dport=random state=— proto=UDP src=192.0.2.0/24 dst=203.0.113.10 dport=random state=— proto=TCP src=… dst=203.0.113.10 dport=443 state=established ``` Three things in that shape matter more than any number. **Destination ports vary without pattern.** Legitimate UDP traffic goes to services you run. Traffic spread across arbitrary ports has no service behind it and no reason to exist. **Sources are widely distributed and short-lived.** Address ranges appear, contribute, and vanish, which is consistent with forgery rather than with a population of clients. **Your established sessions are unaffected in kind, only in capacity.** Existing traffic is not being attacked; it is being crowded out. ## Recognising it against the alternatives Two distinctions save time. Against an application-layer flood, the difference is where the load appears: here the application is idle and the interface is full. Logs that stay quiet during an outage are a signal in themselves. Against a protocol attack such as a connection flood, the difference is state: there is none. Nothing is half-open, no table is filling, and the server is refusing nothing. It simply is not receiving. ## Mitigation by layer Four measures, in the order they help. **Filter upstream.** The only place a saturating flood can be removed is before your link carries it. Whoever provides connectivity can drop by protocol, port, and source properties at their edge, and this is the conversation to start first. **Rate limit UDP that has no business existing.** Where you run no UDP services, that traffic can be discarded categorically upstream. Where you do, limits per port and per source are cheaper than inspection. **Do not answer what you do not serve.** Suppressing error responses for unused ports removes the second cost described above. This is a configuration decision with a trade-off: those responses exist for diagnostics, and silencing them makes some legitimate troubleshooting harder. **Have capacity in front of you.** Absorbing volume is infrastructure rather than configuration, which is why this family is answered by whoever sits between you and the internet. What does not help: rules that read requests, challenges, and anything applied on the server itself. Filtering traffic after it has crossed the link consumes the resource it was meant to protect. ## Protection that can be bypassed Sitting behind a provider helps only for traffic that goes through them, and this is where the defence most often fails in practice. If your server's own address is reachable from the internet, packets sent straight to it never touch the edge that was supposed to absorb them. The protection is real and simply not in the path. Nothing about the flood changed; it went around. Two measures close that gap, and both belong to the origin rather than to the provider. **Accept traffic only from the edge.** Where the origin refuses connections from everywhere else, direct floods still consume its link, but they stop producing any effect on the service, and upstream filtering has a rule it can apply. **Do not publish the address.** Records that resolve to the origin, error pages that reveal it, and mail sent directly from the same machine all place it in circulation. Whether it is discoverable is not something you can undo later, which is why the time to decide is before launch. ## A related vector that lives elsewhere Floods can also arrive as replies rather than as direct traffic, when a service is made to answer a forged request toward you. The general shape of that technique is described on [volumetric attacks](/attacks/volumetric/), and the specific case built on the naming system belongs to the naming layer of this network, where record behaviour and resolver rules are already documented. Repeating it here would describe one mechanism in two places and keep neither current. ## Where the platform sits Bridge WAF inspects requests, which is the wrong layer for this attack and is stated plainly for that reason. What applies instead is termination: when visitors reach your site through the platform's edge, your origin's address is not the one being flooded, and the capacity in front of your content is the platform's rather than your link's. Asking a provider which component covers which layer is fair, including here. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a UDP flood?** An attack that sends large volumes of connectionless packets to fill a link or exhaust the equipment carrying it. Because no connection is established first, the sender needs no cooperation from your side and no reply, which is what makes the volume easy to sustain. **Does a WAF stop UDP floods?** No. The packets never become requests, so there is nothing for request inspection to look at, and this remains true however capable the inspection is. Defence belongs upstream, where filtering happens on capacity large enough that the traffic is absorbed rather than delivered to a link small enough to fill. **Why can I not just block the source addresses?** Because the protocol expects no reply, so nothing verifies the address a packet claims to come from. What appears in your counters may belong to somebody uninvolved, and blocking it achieves nothing except denying service to whoever actually holds that address. **Why do closed ports make it worse?** Because a packet to a port with nothing listening prompts your system to generate an error response. Each one costs processing and outbound capacity, so traffic aimed at ports you do not use still consumes resources, and the reply itself goes to a possibly forged address. **Will a bigger server help?** No. The constraint is the link and the equipment in front of it rather than the machine behind them, so additional capacity is spent on a resource that was never the bottleneck. The useful capacity is upstream, where the traffic can be absorbed or dropped. **How do I confirm it is a UDP flood?** Look for the gap between layers: interface and firewall counters showing volume the application never sees, and destination ports corresponding to no service you run. That combination separates this from an application-layer problem, where the requests do arrive and are simply too many. --- https://bridge-waf.com/bots/blocking/ --- # How to block bad bots without blocking your customers Blocking is a response, not a judgement. Deciding what traffic is happens before this, and it happens under uncertainty, which means every response here will sometimes land on a customer. Choosing between responses is therefore a question about consequences: what happens to a real person who receives this, and what happens to automation that does. ## The ladder of responses Ordered by severity, and the useful default is to start further up it than instinct suggests. **Observe.** Record the decision without acting on it. The only way to learn what a rule would have done before it does it. **Slow.** Delay responses to a client rather than refusing them. Automation depending on throughput loses most of its value; a person notices a sluggish page and continues. **Challenge.** Ask for proof that costs little once and much at scale. The safest active response when confidence is low. **Degrade.** Serve something cheaper: a cached version, a smaller result, a page without the expensive part. The client gets an answer, your backend keeps its capacity, and a customer who was misclassified still receives something usable. **Refuse.** Return an error and stop. The only response that guarantees a misclassified customer is lost, and therefore the one that needs the highest confidence. Most deployments jump to the last rung immediately, which is why their false positives are expensive. ## What is not a control **Instructions for cooperative crawlers are not protection.** The file at the root of your site that says which paths may be crawled is a convention followed by automation that chooses to follow it. Anything hostile ignores it, and nothing enforces it. That is not a criticism of the mechanism, which does its job well: it manages load from cooperative crawlers and keeps them out of sections that waste their time and yours. But it belongs in the category of communication, not defence, and using it as defence has one specific failure: listing sensitive paths there tells anyone who reads it where those paths are, and the file is public by definition. **Blocking by what a client claims to be** removes automation that never tried to hide. The declaration is written by the sender, so a rule matching it stops working the moment someone changes one line, and in the meantime it can catch real browsers that happen to match. ## Blocking by address, and why it disappoints The instinct is to block the source. Three properties make it weaker than it looks. **Addresses are shared.** Mobile networks and corporate egress put many people behind one, so a block lands on a population rather than on a sender. **Addresses rotate.** Automation that finds an address blocked uses another, and the supply is effectively unlimited. **Addresses outlive the reason.** A block added during an incident stays until someone removes it, and the address may be serving a customer months later. Anything address-based needs an expiry attached at the moment it is created. It is still worth doing where the source is infrastructure rather than a consumer network, and where the block is temporary. As a standing strategy it accumulates cost quietly. ## Limits as a response Constraining how much a client may consume is the most broadly useful active measure, because it does not require deciding what the client is: it only requires deciding what a client may have. The design of such limits, including how to weight them by cost and which algorithms behave well under bursts, is a subject of its own and is covered separately. Two properties matter here. Limits degrade rather than deny, which suits uncertain classification. And they apply equally to automation you approved, which is why the exemptions below come first. ## Operational rules that prevent regret Five habits, and they matter more than the choice of method. **Start in observation mode.** Every rule runs without acting until you have seen what it would have caught. **Attach an expiry to everything specific.** Blocks, address lists, and rules written against a particular campaign should end on their own. What stays permanently should be structural. **Maintain an exemption list deliberately.** Monitoring, payment callbacks, partner systems, and internal jobs, each identified by a credential rather than by an address wherever possible. **Log what decided, not just what happened.** A block with no recorded reason cannot be argued about, and the argument always comes from someone whose integration broke. **Have a way to turn it off quickly.** Under pressure, the ability to revert everything in one action prevents the improvised changes that outlive the incident. ## The failure you will not see A customer refused by mistake does not complain. They assume the site is broken and leave, and nothing in your logs distinguishes them from a visitor who never arrived. The same is true of automation you depend on: search crawlers stop fetching, monitoring stops reporting, and a callback starts failing at a partner who tells you about it days later. That asymmetry, and not the effectiveness of any method, is the reason to prefer responses that ask over responses that refuse. ## Blocking as part of the stack Bridge WAF covers three rungs of the ladder above and not the others. Off, monitor, and block are the modes; monitor is the observation step, and it is the one worth starting on. Rate limiting applies per domain, which is the slowing measure. Flagged requests appear in a near-real-time activity log, so a decision has a record behind it. What is not there: challenges, degraded responses, and any dial between monitor and block. Those belong to your application or to another layer, and a page that recommends preferring them should say where they come from. The exemption list is yours in either case, since only you know which automation you depend on. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **Does robots.txt block bad bots?** No. It is a convention observed by cooperative automation and ignored by everything else, so it manages the traffic you were not worried about. Listing sensitive paths in it also publishes those paths to anything reading the file to find them. **Is blocking by user agent worth doing?** Only against automation that is not hiding, which limits its usefulness sharply. The declaration is chosen by the sender and altered in a single line of configuration, so anything with a reason to avoid the rule avoids it in seconds. **Why is address blocking unreliable?** Three properties work against it. Addresses are shared, so one block can catch many unrelated people; they rotate, so the target moves; and blocks outlive the reason for them, so an address blocked today refuses somebody entirely different next month. **What should I do when I am unsure?** Slow the client down, challenge it, or serve something reduced, rather than refusing outright. All three leave a misclassified customer able to continue, which is the whole difference between an inconvenience they forget and a departure you never hear about at all. **How do I avoid breaking my own automation?** Three steps in order: list the automation you depend on before enforcing anything, identify each entry by a credential rather than an address so the exemption survives infrastructure changes, and run every new rule in observation mode long enough to see what it would have caught. **How long should a block last?** For a period decided at the moment it is created, whatever that period is. A block without an expiry becomes a permanent decision that nobody remembers making, applied by nobody to a reason that no longer exists, and it is usually discovered years later during an unrelated investigation. --- https://bridge-waf.com/bots/credential-stuffing/ --- # Credential stuffing: passwords that leaked somewhere else Credential stuffing tries username and password pairs exposed in a breach of some other service, on the chance that the same person reused them with you. It is not guessing: guessing tries many passwords against one account, while this tries one password against many accounts, and that password is already known to be real. The difference decides every defence here. ## Quick facts | | | |---|---| | **What it takes** | Accounts, and whatever those accounts can reach | | **Typical volume** | Spread thin: many accounts, few attempts each | | **In your logs** | Successful logins mixed into a large number of ordinary failures | | **Cost of blocking wrongly** | Locked-out customers, and a support queue that arrives all at once | ## Why it works, and where the defect is The mechanism depends on one fact about people rather than on any weakness in your system: the same password gets used in more than one place. When a service is breached, the pairs from it become usable everywhere that person reused them. Two consequences follow, and both are uncomfortable. **Your login form is working correctly.** It received a valid password and accepted it. Nothing was bypassed, and no rule about length or characters would have made a difference. **Your exposure depends on other people's security.** A breach you have no relationship with determines how many of your accounts are at risk, and you will not be told when one happens. ## The signals Three, and the first is the one that makes this identifiable at all. **An unusual failure ratio.** Ordinary login traffic fails sometimes; people mistype and forget. Stuffing produces failures at a rate no genuine population reaches, because most pairs are wrong for your site. That ratio, measured across the whole login endpoint rather than per source, is the clearest indicator available. **Breadth without depth.** Many distinct accounts, one or two attempts each. The opposite shape from guessing, which hammers a single account, and the reason per-account attempt limits alone do not see it. **Logins without the rest of the visit.** Sessions that begin at the login endpoint with no browsing before it, no assets loaded, and no behaviour afterwards resembling how your customers use the product. Sources are usually numerous and unremarkable individually, which is covered on [bot detection](/bots/detection/): reputation helps and does not decide. ## Before you lock accounts **Warning:** locking an account after a number of failed attempts is the reflex response, and against this attack it converts an intrusion attempt into a denial of service against your own users. The reason is arithmetic. The attacker is submitting attempts against accounts that belong to your customers; a lockout triggered by those attempts locks the customer out, not the attacker. Where the attack covers many accounts, so does the lockout, and your support queue receives the consequences of a defence you chose. Where lockout is used at all, it should be temporary, expressed as a delay that grows rather than a door that closes, and paired with a way for the real owner to recover without contacting anyone. The measure that targets the attacker is a limit on the source and a challenge on the endpoint, not a penalty on the account being tried. ## What actually reduces the risk Ordered by how much they change the outcome. **Second factors.** A password that is correct stops being sufficient. This is the only measure that addresses the mechanism rather than its traffic, and everything else is mitigation around it. **Checking passwords against known exposures.** At registration and at change, refusing credentials already known to be public removes the reuse this attack depends on, prospectively. **Limits and challenges on the login endpoint,** applied per source and in aggregate rather than per account, for the reason described above. **Signals about the session,** such as whether the device and location are consistent with the account's history. Useful, and they must degrade gracefully: people travel, replace phones, and use borrowed computers. **Telling the account owner.** A notification of a login from a new device converts a silent compromise into something the person can act on, and it costs nothing when it is a false alarm. Where an attempt succeeds, what happens next is a different subject: the account is under someone else's control, and the response belongs to account takeover handling rather than to traffic filtering. ## False positives: who else fails to log in The obligatory section, and here the lookalikes are ordinary people having a bad day. **Anyone whose password manager holds an old password**, which produces repeated failures from a legitimate owner on a legitimate device. **Shared offices and networks.** Many people logging in from one address, some of them failing, looks like a distributed attempt from a single source. **People who genuinely forgot,** which correlates with accounts used rarely, meaning the customers you most want to bring back. **Your own systems.** Health checks that log in, integration tests, and support tooling that authenticates as a user. The pattern across all four: real failures cluster around one account or one address, while stuffing spreads. Deciding on the aggregate shape rather than on individual failures is what separates them. ## What it looks like when it succeeds The successful attempts are the ones your login metrics hide. A campaign that tries many accounts and succeeds on a few produces a success rate that barely moves your averages. The compromised accounts then behave normally at first: a login, a look at what is there, and nothing that any threshold notices. Damage arrives later, when the access is used or sold. Two habits surface it. Compare successful logins against the sessions that follow them, since a login with no plausible activity afterwards is unusual. And treat a successful login from a source that failed repeatedly across other accounts as a compromise until shown otherwise, because that sequence has no innocent explanation. Recovery for those accounts is not a filtering question, and it should be decided before it is needed: what gets invalidated, what the owner is told, and how they regain access. ## Handling this as part of the stack Bridge WAF inspects login traffic at the edge: credential stuffing is one of the named rule categories, matches are recorded in monitor mode and refused in block, and rate limiting is applied per domain rather than per account — so watch the record first, and let it show what enforcement would have refused. What no filtering layer provides is the structural fix: second factors and exposure checks live in your authentication, and they are what make a correct-but-stolen password insufficient. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is credential stuffing?** Trying username and password pairs exposed elsewhere against your service, on the expectation that some people reused them. Nothing is guessed and nothing is broken: the pairs are known to have worked somewhere, and the only question is how many of your customers overlap. **How is it different from brute force?** Guessing attacks one account with many passwords, which makes it loud on that account and easy to rate limit. Stuffing attacks many accounts with a single password each, and that password is already known to work somewhere, so it is quiet everywhere and visible only in aggregate. **Do strong password rules stop it?** No, and this is the point people find hardest. The password being tried was already accepted by another service and may satisfy every rule you impose. Complexity requirements address guessing; they have no effect on a password that is already known. **Should I lock accounts after failed attempts?** Carefully, because a lockout triggered by somebody else's attempts locks out your customer and hands anybody a deliberate way to deny them service. Growing delays, limits applied to the source rather than the account, and challenges achieve the same protection without creating that second problem. **What is the strongest defence?** A second factor, because it changes the arithmetic rather than the odds. It makes a correct password insufficient on its own, which means the technique stops working entirely against any account that has one, whatever was exposed elsewhere and however many pairs are tried. **How do I spot it in logs?** By the shape rather than the volume: a failure ratio in aggregate that no genuine population of customers produces, spread across a great many accounts with only a few attempts against each. Per-account counters see nothing unusual, which is why the aggregate view is required. --- https://bridge-waf.com/bots/detection/ --- # Bot detection: the five signals and their real limits Detection does not identify automation. It accumulates evidence, and every signal it uses can be reproduced by something determined enough. Useful systems therefore combine several weak signals rather than trusting a strong one, and the practical skill is knowing what each signal misses and what it costs when it points at a customer. ## The five layers | Signal | Inspects | Catches | Misses | |---|---|---|---| | Declared identity | What the client says it is | Automation that does not bother to lie | Anything that copies a browser string | | Source reputation | History of the address | Known-bad infrastructure | New sources, residential proxies | | Behaviour | Actions across many requests | Systematic access, inhuman timing | Slow, low-volume, patient automation | | Client characteristics | How the client is built | Mismatches between claim and capability | Full browser automation | | Challenges | Response to a task | Anything unwilling to spend the cost | Automation willing to pay it | They are listed in order of how easily each is defeated, which is roughly the inverse of how much they cost you when wrong. ## Declared identity The client states what it is. That statement is free to write, so it proves nothing on its own and remains useful for exactly two purposes: it removes automation that never intended to hide, and it flags contradictions. The contradiction is where the value lies. A client claiming to be a current browser while behaving like a script is more interesting than either fact alone, and inconsistency between a declaration and observed capability is a genuine signal where the declaration itself is not. **The limit:** anything that has been told to hide is invisible here. Blocking on this signal alone catches the automation that was not a problem. ## Source reputation Addresses carry history: what has been seen from them, whether they belong to hosting infrastructure or to consumer networks, and whether they have been observed in abuse elsewhere. That history is real information and it is not about the current request. **The limit:** it is about the address, not the sender. Many people share one address on mobile networks and behind corporate egress, so a reputation decision lands on everyone behind it. And automation running on residential connections inherits the reputation of ordinary homes, which is precisely why that market exists. How scoring is built and where its data comes from is covered separately. ## Behaviour The strongest signal available, because it describes what a client actually did rather than what it claimed. Access that walks systematically through identifiers, sessions with no pauses, request sequences that skip the steps a person would take, and populations whose members all behave identically: none of these is provable automation, and all of them are unlike how people use a site. **The limit:** it needs volume and time. A client making a handful of requests provides too little to judge, which is the shape that patient automation takes. Behaviour also describes populations better than individuals, so it supports rate decisions more readily than verdicts about one visitor. ## Client characteristics What the client is, as opposed to what it says: which capabilities it actually has, how it negotiates the connection, and whether those details line up with the browser it claims to be. **The limit, and it has three parts.** Full browser automation produces genuine browser characteristics, because it is a genuine browser. Privacy protections in browsers and on devices deliberately reduce how distinguishable clients are, which erodes this signal over time by design. And the technique is close enough to tracking that it deserves a deliberate decision rather than a default: the same measurements that identify automation identify people, and where that data goes is a question worth answering before deploying it. ## Challenges Rather than judging, ask the client to spend something: a computation, an interaction, a proof that costs little once and more at scale. This is the only method that changes the economics rather than the classification. It also degrades gracefully: a customer who passes is inconvenienced and still served, which makes it the safe choice when confidence is low. **The limit:** automation that finds the target valuable enough will pay the cost, and challenges have their own costs on the other side, falling hardest on assistive technology, older devices, and anyone with a slow connection. A challenge on every request is a tax on your customers. ## Combining signals No single layer decides. Practical systems assign weight to several and act on the total, which has two consequences. **Thresholds are policy, not truth.** Where the line sits determines how many customers are inconvenienced and how much automation gets through, and there is no setting that avoids both. That choice belongs to whoever bears the cost of each error, which is a business decision rather than a technical one. **Response should scale with confidence.** Low confidence deserves a challenge, medium a limit, and only high confidence deserves refusal. A system with one response for every score is either too permissive or too aggressive at most levels. ## How to know it is working The question most implementations never answer, because the evidence is uncomfortable to gather. Automation blocked is easy to count and tells you little. What matters is what you refused wrongly, and that number does not appear anywhere by default: a customer who was blocked leaves, and nothing records the transaction that did not happen. Two habits produce the missing evidence. Log decisions with the signals behind them, so a complaint can be traced to a rule rather than argued about. And sample what you blocked, deliberately, on a schedule, looking for the ones that should not have been. ## The signals that age badly Two practical warnings about anything you build on these layers. **Lists go stale in both directions.** Addresses change hands, hosting ranges get reassigned, and a source that deserved blocking last year may now serve a customer. A list without an expiry becomes a set of decisions nobody remembers making, which is the same failure described for emergency filters everywhere in this material. **Rules written against one campaign describe that campaign.** Automation adapts, and a rule matching what it did last month keeps matching the handful of clients that still behave that way, most of which are no longer the ones you care about. Rules built on structural properties, such as cost consumed or systematic access, survive changes that rules built on specific strings do not. The practical rule is that anything specific should expire on its own, and anything permanent should be structural. ## Detection as part of the stack Bridge WAF classifies automation by declared identity, which is the first and weakest of the five signals above. That is worth stating plainly rather than implying more: reputation scoring, client characteristics, and behavioural analysis are not what it does. What it does provide is the part this page argues matters most. Monitor mode records what would have been blocked without acting on it, which is the observation step that makes false positives visible before they cost anything. Rate limiting applies per domain. Flagged requests appear in a near-real-time activity log, so a decision can be traced rather than argued about. Modes are off, monitor, and block, with nothing to tune between them. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **Can bot detection be certain?** No. Every signal available can be reproduced by something determined to reproduce it, so detection accumulates evidence towards a probability rather than establishing a fact. Building a system that acts as though it has proof is what produces confident, damaging mistakes. **Which signal is most reliable?** Behaviour observed across many requests, because it describes what a client actually did rather than what it declared about itself. Its weakness is the mirror of its strength: it needs a run of requests before it says anything, so it is useless on a first visit. **Why is blocking by declared identity weak?** Because the declaration is written by the client and can say anything at all. Acting on it removes exactly the automation that was being honest about itself, while everything concealing its nature continues untouched, which inverts the outcome you were aiming for. **Is fingerprinting a good idea?** It carries real signal and real costs together. Browsers are deliberately reducing what it can see, automation driving a genuine browser defeats it outright, and whatever it measures it measures about your customers as much as about anyone else, which raises questions beyond the technical. **When should challenges be used?** Wherever confidence is low, which is most of the time. The response should scale with certainty: high confidence justifies refusal, moderate confidence justifies a challenge, and low confidence justifies watching, because each mistake costs in proportion to the force used. **How do I measure false positives?** Deliberately, because nothing surfaces them on its own. Record the signals behind every decision, and sample blocked traffic on a schedule to see who was in it. A blocked customer files no report, so a system with no sampling reports perfect accuracy indefinitely. --- https://bridge-waf.com/bots/ip-reputation/ --- # IP reputation: what an address history can and cannot tell you Reputation is a statement about an address, not about whoever is using it now. It summarises what has been observed from that address over time, which makes it useful as one input among several and misleading as a verdict alone. The same address can carry an attacker on Monday and a customer on Tuesday. ## How a score is built Three ingredients, combined differently by every provider that sells them. **Observed behaviour.** Traffic seen from the address across many properties: submissions to forms that no person would find, credential attempts against unrelated sites, requests matching known abuse patterns. The value comes from breadth, since one site sees too little to judge. **What the address is.** Whether it belongs to hosting infrastructure, a consumer network, a mobile carrier, or an anonymising service. This is classification rather than behaviour, and it is often the most stable part of a score: a request from a datacentre claiming to be a phone browser is worth noticing regardless of history. **Age and stability.** How long the address has been used for what it is used for, and whether that changed recently. New allocations and recently reassigned ranges carry little evidence in either direction. Scores are then expressed on some scale, and the scale is a product decision rather than a fact. Two providers scoring the same address differently are not necessarily contradicting each other; they weighted different ingredients. ## What a score does not know Four limits, and each one produces a specific kind of mistake. **Who is behind the address.** Mobile carriers and corporate networks place many people behind one address. A score earned by one of them applies to all of them, and the people affected have no way to know why a site treats them oddly. **Whether the reason still applies.** Addresses are reassigned constantly. Evidence collected before a reassignment describes a previous occupant. **Whether the traffic is automation at all.** A poor score frequently means "this address hosts servers", which is true of every legitimate integration that calls you, every monitoring service, and every cloud-based tool your own team uses. **Whether an attacker chose an address with a good score.** Automation running through consumer connections inherits ordinary residential reputation, which is why that arrangement exists. ## Reputation is not a blacklist The two get used interchangeably and behave differently. **A blacklist is binary and authored.** An address is listed or it is not, a policy decides why it was listed, and another policy decides how it gets removed. The mechanism grew out of mail filtering, where a hard yes-or-no suits the problem, and it is typically queried through the naming system rather than through an interface. Its strength is accountability: there is a listing reason and a removal process. **Reputation is continuous and inferred.** No one wrote a decision about a particular address; a score emerged from observations. Its strength is nuance, and its weakness is that nobody can tell you exactly why a number is what it is, which makes disputes hard. The practical consequence: a blacklist entry is a claim you can appeal, and a reputation score is a weight you can only outweigh. Using a score as if it were a listing produces blocks nobody can explain to the affected visitor. ## Decay is not optional A score that only accumulates becomes a permanent block list with extra steps. Every piece of evidence has a shelf life, and addresses change hands more often than intuition suggests. Without decay, a range that misbehaved a year ago keeps paying for it while serving somebody new, and the sites using that score never learn what they lost. This applies equally to lists you maintain yourself: entries added during an incident need an expiry attached at creation, for the same reason. ## The address that is not one address Modern addressing changes what reputation can mean. Know this before building anything on per-address scores. Where each device may hold an enormous number of addresses, a score attached to a single one carries almost no information: the next request arrives from a different address at no cost to anyone. Reputation systems therefore work at the level of allocations, which is more accurate and also blunter, since an allocation may cover a whole network of unrelated people. The practical rule is to know which granularity your data uses before deciding what a score justifies. ## When your own address has the problem The mirror case, and it arrives without warning. If traffic your systems send starts being refused elsewhere, the cause is often reputation attached to an address you did not choose: a shared hosting range, a cloud allocation whose previous occupant misbehaved, or an office connection someone else on it abused. Nothing on your side changed. Two things help. Find out which classification your addresses carry, since that is the part you can sometimes influence by moving traffic to addresses used for one purpose only. And where a specific listing is the cause rather than a score, there is usually a stated reason and a removal process to follow. Know both before an outbound integration fails, because the diagnosis is unintuitive: your logs show requests leaving normally and answers not coming back. ## Using it without regret Four rules, and they follow from the limits above. **Never let it decide alone.** Reputation is a weight in a score, combined with behaviour and consistency, as described on [bot detection](/bots/detection/). **Weight by address type, not just by score.** A poor score from hosting infrastructure means something different from a poor score on a mobile carrier, and treating them identically guarantees the second becomes a customer complaint. **Respond proportionately.** A weak signal deserves a challenge or a limit, not a refusal. **Exempt what you depend on explicitly.** Your monitoring and your partners' systems run on the infrastructure that scores badly. ## Where the platform sits Bridge WAF does not score addresses. Its bot classification works on declared identity, so nothing on this page describes a capability it has, and a page about reputation is the right place to say so rather than to imply otherwise. What it offers instead sits alongside reputation rather than replacing it: three modes, off, monitor, and block; rate limiting per domain; and a near-real-time log of flagged requests. Monitor mode is the useful one here, because it lets you see which traffic a rule would have caught before anything is refused, which is the discipline this page argues for whatever your data source. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is IP reputation?** A summary of what has been observed coming from an address over time, used as one signal about traffic arriving from it now. It is a statement about a location on the network rather than about whoever happens to be behind it at this moment. **How is it different from a blacklist?** A listing is binary, usually carries a stated reason, and has a removal process somebody can follow. Reputation is a continuous score inferred from observation, which makes it more nuanced to act on and considerably harder for an affected party to dispute or even discover. **Can reputation identify a bot?** No. It describes an address rather than a visitor, and a single address routinely carries an entire office, a mobile network's users, or a university. A score attached to the address says nothing reliable about the particular request in front of you. **Why does my score matter if I run servers?** Because hosting ranges are scored worse by classification rather than by conduct, so legitimate automation you run can be treated with suspicion by other sites through no fault of its own. It is worth knowing before an integration starts failing inexplicably. **Why must scores decay?** Because addresses change hands regularly, and a score that never fades becomes a sentence served by whoever holds the address next. Decay is what keeps the signal about current behaviour rather than about somebody who left the address years ago. **Should I block on reputation alone?** No. Use it as one weight among several, respond in proportion to the confidence it genuinely provides rather than to the score's apparent precision, and exempt the automation you depend on explicitly, since infrastructure addresses are exactly the ones this signal scores worst. --- https://bridge-waf.com/bots/scrapers/ --- # Content scrapers: how to spot and slow them down safely Scrapers fetch your pages in bulk to reuse what is on them: catalogue data, prices, listings, articles, anything that took effort to produce. The requests are ordinary and the traffic often modest, so the cost appears somewhere other than an availability graph. What separates a scraper from a crawler you want is not the fetching but everything around it. ## Quick facts | | | |---|---| | **What it takes** | Content, catalogue data, prices, structure | | **Typical volume** | Modest per source; breadth matters more than rate | | **In your logs** | Systematic path coverage, no assets, no session behaviour | | **Cost of blocking wrongly** | High: aggregators, partners, and preview fetchers look identical | ## How it differs from a crawler you want Four behavioural differences, none of which depends on what the client calls itself. **It fetches only what it wants to keep.** A browser loads a page and its assets. A crawler that renders behaves similarly. A scraper takes the document and nothing else, because images and stylesheets are cost without value to it. **Its coverage is systematic where a crawler's is interest-driven.** Walking identifiers in order, exhausting a category, or requesting pages in the sequence a database would produce rather than the sequence links suggest. **It ignores what you published as limits.** Instructions for cooperative crawlers are followed by cooperative crawlers, which is precisely the population that was never the problem, as covered on [blocking](/bots/blocking/). **It cannot be verified.** Legitimate crawlers offer a way to confirm they are who they claim, and that verification is a property of the operator rather than a header. Automation with no verifiable identity is not automatically hostile, but it also has no claim on the access you grant to identified crawlers. The catalogue of automation that identifies itself and can be verified, including the crawlers that read sites for search and answer engines, is maintained on the main site of this network. ## Where the cost lands **Your capacity,** in proportion to how expensive your pages are. A catalogue that assembles from a database is far more costly to serve at scale than a static article. **Your position in search results.** A copy of your content competes with you wherever it is published. Whether a copy ever outranks an original depends on many things outside this page, and the honest claim is narrower than the usual scare: the copy exists, it is indexed, and it did not cost its publisher anything to produce. **Your commercial position.** Where the data is prices or inventory, the value is in its freshness, and continuous copying transfers exactly that. Any statement about how search engines treat duplicated content requires a citation to their documentation with a date. None appears here. ## Recognising it Three patterns, and the third is the most reliable. **Coverage without depth.** Many distinct pages, each fetched once, with no returning visits and no interest in anything interactive. **Requests for what nobody links to.** Pages reachable only by constructing a path, or by reading a machine-readable index of your site, and never reached by a person browsing. **Cost concentrated in one client.** The measurement that does not require guessing intent: a single source consuming a share of your rendering budget unlike any plausible visitor. ## Blocking without breaking things Responses in order of severity, following the ladder on [blocking](/bots/blocking/). **Limit by cost, not by request count.** Expensive pages deserve tighter allowances, which throttles bulk copying while leaving ordinary browsing untouched. **Degrade rather than refuse.** Serving a cached version, a smaller page, or results without the expensive parts removes most of the value to a copier and remains usable for a misclassified visitor. **Challenge on the paths that matter.** Catalogue and listing pages rather than the whole site, so the cost falls where the value is. **Require identity for bulk access, and offer it.** Where the data has legitimate demand, an interface with a key is cheaper for both sides than an arms race, and it converts an adversary into something you can rate limit by account. Legal avenues exist and are outside what this page can advise on: what protection applies to your material, and what your terms permit, depends on your jurisdiction and on the nature of the content. That is a question for a lawyer, best asked before an incident rather than during one. ## False positives: who else looks exactly like this The obligatory section, and on this page it is the longest one for a reason: the lookalikes are numerous and several of them are commercially important to you. **Aggregators and comparison services** fetch catalogues systematically because that is their function, and many of them send you customers. **Partners under contract.** Integrations you agreed to, often built years ago by someone who has left, calling you from infrastructure with no identifying credential. **Preview fetchers.** When someone shares your link in a chat application or a social platform, something fetches the page to build the preview. Blocking those makes your links look broken wherever they are shared, and nothing in your logs connects the two. **Archives and research.** Preservation projects and academic crawlers, which are systematic by design. **Feed readers and accessibility tools,** which fetch documents without assets for entirely legitimate reasons. The practical protection is the one from the mother page: know which automation you expect, give it identity where you can, and prefer measures that slow rather than refuse. A blocked aggregator does not complain; it simply stops sending you customers, and you will attribute the decline to something else. ## Handling this as part of the stack Bridge WAF applies rate limiting per domain, which bounds what a domain as a whole will serve: bulk copying that pushes past the limit is refused at the edge rather than served by your application, and monitor mode records what a limit would have refused before it refuses anything. What no product decides is which copying you mind: a comparison service and a competitor scraping prices produce identical traffic and opposite business outcomes. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What is a content scraper?** Automation that fetches pages in bulk in order to reuse what is on them, rather than to index them or to present them to a reader. The mechanism is identical to a search crawler's; the purpose is what differs, and purpose is not visible in a request. **How do I tell a scraper from a search crawler?** By two things that a claim alone cannot supply: whether the client can be confirmed as who it says it is by a method the sender does not control, and whether its behaviour matches a crawler's rather than systematic bulk copying of everything in order. **Does robots.txt stop scrapers?** No, on the same grounds as everywhere else: it is honoured only by automation that chooses to honour it. Something built specifically to copy your content has no reason to be in that category, and nothing enforces the file's contents. **Will scraped copies hurt my search position?** A copy competes with you wherever it is published, which is a real effect you can observe. Anything beyond that about how search engines treat duplicates is a claim requiring a citation to their own documentation, and this page does not make one. **What is the safest response?** Limits weighted by what each request costs you, together with reduced responses rather than outright refusals. Blocking risks catching link preview fetchers, aggregators, and archive services, all of which resemble scrapers closely and are frequently the traffic you actually wanted to receive. **Should I offer the data through an interface instead?** Where the demand is legitimate, this is often the strongest answer available. It converts anonymous copying into identified access that can be limited per account, revoked individually, and measured, which is a better position than any detection arrangement is able to reach. --- https://bridge-waf.com/bots/spam-bots/ --- # Spam bots: what the usual defences actually cost Spam bots submit your forms: comments, registrations, contact requests, reviews. The traffic is trivial in volume and the damage lands elsewhere, in moderation time, in what visitors see, and in whether your own mail keeps being delivered. The defences are well known; most of them also refuse real people in ways nobody measures. ## Quick facts | | | |---|---| | **What it takes** | Moderation time, page quality, mail reputation | | **Typical volume** | Low; a few submissions can cost hours | | **In your logs** | Successful submissions; nothing anomalous per request | | **Cost of blocking wrongly** | A form that silently fails for some visitors and never reports it | ## Where the damage lands **In moderation.** Every submission that reaches a person costs attention, and the ones that reach visitors before removal cost more. **In your mail reputation.** This is the consequence most sites discover late. A contact form that sends mail on submission becomes a way to send mail through your domain, and where that mail is unwanted, the receiving side attributes it to you. Delivery problems then appear on messages that matter, disconnected in time from the form that caused them. **In your published content.** Comment sections and reviews filled with links describe your site to every visitor and to anything that reads it. ## The signals that work Three, in order of reliability. **Interaction, not just submission.** A person who filled a form touched its fields: focus moved, keys were pressed, corrections happened. A submission arriving with no evidence of any of that was assembled rather than filled. This is the strongest available signal because it describes the process rather than the result. **Content patterns across submissions.** Identical structure with rotated details, links in fields that have no reason to contain them, and the same text arriving at many unrelated sites. Any single one is weak; together they are strong. **Rate and breadth per source.** Several submissions to different forms from one place, or a submission to a form nobody links to any more, which is a form that a person would not have found. ## Honeypots, and why they need care The standard technique adds a field a person will never fill and treats anything that fills it as automation. The mechanism is sound and its limits are specific. **Browser autofill fills it.** A field that looks like a name or an email to software gets completed by the same software your customers rely on, and they receive a rejection with no explanation. **Assistive technology can reach it.** A field hidden visually may still be announced to someone using a screen reader, who will fill it in because they were asked to. Rejecting that submission excludes the visitors least able to work around it, which makes implementation an accessibility question and not only a technical one. **It only catches automation that fills everything.** Anything targeting your site specifically will submit the fields your form uses. None of this makes honeypots useless. It means the field must be built so that neither autofill nor assistive technology treats it as real, and that failing it should lower a score rather than refuse a submission outright. ## Timing checks and their trap The other standard technique measures how long a form took to fill and rejects anything faster than a person could manage. Two populations break it. Password managers and autofill complete a form instantly, which is the behaviour being penalised. And people who prepared their text elsewhere and pasted it in look identical to a script. If you use timing at all, treat it as one weight among several rather than as a gate, and never as the sole reason to refuse. ## Blocking without breaking the form Following the ladder on [blocking](/bots/blocking/), applied to submissions. **Accept and hold rather than refuse.** A submission that goes to review instead of publication removes the damage without telling a legitimate sender that your site is broken. **Limit per source and per form.** Especially on forms that send mail, where the cost of each submission extends beyond your site. **Challenge on the paths that matter,** which usually means the form that produces outbound mail rather than every form you have. **Require an account for anything published.** The most effective measure where it fits the product, and the least acceptable where it does not. **Never fail silently.** Whatever you do, a rejected human should see that something happened and how to reach you another way. A form that appears to submit and quietly discards the message is the worst outcome available, and it is what most naive implementations produce. ## False positives: who else gets caught The obligatory section, and here it decides the design. **Anyone using autofill or a password manager**, which is a large share of your visitors and includes most people on phones. **People using assistive technology**, as described above. **Anyone who wrote their message elsewhere** and pasted it, which correlates with people writing carefully or in a second language. **Your own testing.** Internal submissions from a script or a monitoring check look exactly like the traffic you are filtering. The failure mode is quiet in every one of these cases: the visitor believes they contacted you, and you never learn that they tried. That asymmetry is why the recommendations above prefer holding over refusing. ## Why it keeps arriving on a small site The assumption behind the question leads people to skip defences entirely. Submissions are not sent because your site was chosen. Forms are found the way any page is found, in bulk, and the cost of submitting to one more is close to nothing. Being small changes how much spam you receive and not whether you receive it. The second reason is that many submissions are not aimed at your visitors at all. A form that sends mail is useful to a sender regardless of whether anyone reads the comment, and a registration form that creates accounts is useful regardless of whether the site has traffic. That is the practical argument for handling this on forms that produce outbound effects first, whatever the size of the audience. ## Handling this as part of the stack Bridge WAF inspects requests before they reach your application: submissions matching the spam-bot rules are recorded in monitor mode and refused in block, and rate limiting per domain bounds how hard a form can be hammered. Requests that never arrive cost nothing to moderate. What the platform cannot decide is your form's own design: whether a rejected sender is told, whether a suspect submission is held rather than dropped, and whether a hidden field is reachable by assistive technology are choices in your markup. See what the platform offers at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What do spam bots actually cost?** Three things that arrive on different timescales: moderation time immediately, the quality of what visitors see shortly after, and, where a form sends mail on submission, your domain's standing as a sender, which is slow to lose and slower to recover. **Do honeypot fields work?** Partly, and their failure mode decides how to use them. Password managers, browser autofill, and assistive technology can all fill a hidden field legitimately, so failing the check should lower a score rather than refuse the submission on its own. **Is a minimum fill time a good check?** Only as one weight among several, never as a rule of its own. Somebody pasting prepared text, or a password manager completing fields instantly, produces exactly the timing automation produces, so a hard threshold here refuses real people for the offence of being efficient. **What is the strongest signal?** Evidence that the form was interacted with rather than assembled: fields receiving focus, keystrokes arriving over time, corrections being made along the way. It describes what happened rather than what was declared, though it needs care wherever assistive technology changes the expected pattern. **Should suspect submissions be blocked?** Prefer holding them for review rather than refusing them. A person whose submission is refused usually concludes that the site is broken rather than that they were suspected, and does not attempt it a second time, so the loss is both silent and permanent. **Why does spam affect my email delivery?** Because a form that sends mail on submission is, from the outside, a way to send mail carrying your domain. Whatever it emits is attributed to you, so volume passing through it damages the standing of every message you send, including the ones you care about. --- https://bridge-waf.com/glossary/layer-7/ --- # What is layer 7? The level at which network traffic becomes a request rather than packets: a method, a path, headers, a body, and a client whose behaviour can be followed across several of them. It is the level at which traffic carries meaning that a defence can act on. ## How it works Traffic is described in layers, and each one sees less of the meaning than the one above. At the lower levels there are addresses, ports, and packets. Something is travelling from somewhere to somewhere, and whether it is a shopping cart or an attack is not a question the level can answer, because the information is not there yet. At layer 7 the pieces have been assembled into something intelligible. The request asks for a specific thing, in a specific way, with specific values, and it can be compared with what the same client asked a minute ago. That assembly is what makes judgement possible. ## Why it matters The term is used constantly in security discussions, and almost always to mark a boundary rather than to describe a level. A defence operating here can act on what traffic means: which endpoint is being hit, whether a value looks like an attempt to inject something, whether one client is behaving unlike any person would. That is the entire category of decision unavailable at lower levels. The boundary is the other half, and it is the part to carry away. Something that never becomes a request is not visible here at all. Traffic that saturates a link before arriving, connections opened and abandoned, floods aimed at the network rather than the application: none of that reaches the level where meaning exists, so no amount of rule-writing addresses it. Which defence sees what is set out under [WAF vs other defences](/vs/), and how attacks divide by level under [attack layers](/attacks/layers/). That single fact explains most confusion in this area. When a product claims to handle everything, the useful question is which level it operates at, because the answer bounds what it can possibly observe. ## Related terms How attacks divide across levels is covered under [attack layers](/attacks/layers/), and the rest of the filtering vocabulary in [this glossary](/glossary/). --- https://bridge-waf.com/glossary/virtual-patching/ --- # What is virtual patching? Virtual patching is blocking the requests that exploit a known weakness while the weakness itself remains in the application. A rule in front of the code refuses the shape of the attack, so the vulnerable path stops being reachable in the way that matters, without a line of the application changing. ## How it works A rule describes the exploit rather than the flaw. Somebody works out what a request exploiting the weakness looks like: a parameter carrying something it should not, a path reached in an order it should not be, an `HTTP` header or value longer or stranger than the code handles. A rule in front of the application matches that shape and refuses it, and the request never arrives at the code that would mishandle it. Everything hangs on that word shape. The rule knows the exploit, not the defect, so it protects against the versions of the attack somebody anticipated. A variation that reaches the same flaw by a different shape is a different request, and the rule has no opinion about it. ## Why it matters The technique is genuinely useful and routinely misunderstood, in a way that has a cost. **What it buys is time.** A fix has to be written, reviewed, tested, and deployed, and some applications cannot be changed quickly for reasons that have nothing to do with willingness: a vendor product, a release train, an integration that has to be re-certified. A rule can be in place in minutes and holds the door while the real work happens. **What it does not do is fix anything.** The weakness is still there, still reachable by any route the rule does not describe, and still present in every copy of the application elsewhere. Anybody with a variation walks past it. **The dangerous mistake is treating it as done.** A rule with no expiry becomes permanent, and the urgency behind the fix evaporates the moment the alerts stop. Rules put in place for this reason should carry a date and a reason, which is the same discipline exceptions need, covered under [operations](/operations/). A second cost: a rule describing an exploit shape can match ordinary traffic that happens to look similar, so it needs the same watching as any other rule before it starts refusing requests, which is what [rules](/rules/) sets out. ## Related terms The scanners that find such weaknesses in the first place are covered under [bots](/bots/), and the other vocabulary in [this glossary](/glossary/). --- https://bridge-waf.com/glossary/web-application-firewall/ --- # What is a web application firewall? A layer that reads requests before they reach your application and decides whether each one should be passed on. It works with the content of a request rather than with addresses and ports, which is what separates it from a network firewall and what bounds everything it can do. ## How it works Three steps, and the whole category is the same shape. A request arrives and is assembled into something readable: a method, a path, headers, a body. Rules are applied to that, describing shapes of request that should not be served: values that look like attempts to inject something, patterns of behaviour unlike ordinary use, requests aimed at paths that should never be reached from outside. A decision follows. The request is passed on, refused, or in some arrangements recorded without action, which is the mode used to see what enforcement would do before it does it, described under [operations](/operations/). Everything else in the category is variation on those three steps: where the layer runs, who writes the rules, and how much is observed before anything is refused. ## Why it matters Because a large class of attacks arrives as perfectly ordinary traffic. Requests exploiting an application do not look wrong at the network level. They use the port you deliberately opened, they are well formed, and they often come from addresses with nothing remarkable about them. What distinguishes them is what they ask for, and only something reading the request can tell. The boundary is the other half of the answer, and it is the part sales material tends to leave out. It cannot fix an application: a missing authorisation check or an operation that can be replayed remains exactly as reachable, just harder to reach. It cannot see traffic that never becomes a request. And its mistakes are visible to your own users, since a refused legitimate request looks like a broken site rather than like a defence working. Which defence sees what is set out under [WAF vs other defences](/vs/), and the attacks themselves under [attacks](/attacks/). ## Related terms How the categories of defence divide is under [WAF vs other defences](/vs/), what the attacks look like under [attacks](/attacks/), and the rest of the vocabulary in [this glossary](/glossary/). --- https://bridge-waf.com/glossary/zero-day/ --- # What is a zero-day? A weakness for which no fix is available yet, described from the position of whoever has to defend against it. The name refers to the amount of warning the defenders had, and it says nothing about how clever the attack is or how serious the weakness turns out to be. ## How it works The term marks a period rather than a technique. There is a moment when a weakness becomes usable by somebody, and a later moment when a correction exists and can be applied. Between those two, any use of it is a zero-day, whether the method is ingenious or completely routine. After the second moment, the same attack against an unpatched system is no longer called that, though it works as well. That is the whole of the definition, and the interesting consequences follow from how narrow it is. ## Why it matters Three consequences, and the third is the one to act on. **The label says nothing about difficulty.** An unremarkable technique against a weakness nobody has fixed qualifies just as much as an elaborate one. Treating the word as a measure of sophistication leads to overestimating the attacker and underestimating how ordinary the exposure usually is. **Most damage happens after the fix exists.** The window in which nothing can be done is by definition short; the window in which something could be done and was not is as long as anybody allows it to be. Attacks against known weaknesses on unpatched systems outnumber genuine zero-days by a wide margin, which is why patching discipline matters more than any defence aimed at the unknown. **Filtering can only buy time here, and only sometimes.** Where the `HTTP` traffic exploiting a weakness has a recognisable shape, a rule can refuse it before it reaches the application, which is [virtual patching](/glossary/virtual-patching/). That protects against the versions somebody anticipated and not against the ones they did not, and it is a delay rather than a repair. The honest summary is that no product prevents the category. What preparation does is shorten the period between a fix existing and your systems having it, and make the traffic reaching your application visible enough that something unusual can be noticed at all, which is what [operations](/operations/) is about. ## Related terms Blocking exploit traffic while a weakness remains is covered under [virtual patching](/glossary/virtual-patching/), and the rest of the vocabulary in [this glossary](/glossary/). --- https://bridge-waf.com/operations/activity-log/ --- # The activity log: a record of decisions, not traffic The activity log records requests that filtering flagged, with the context needed to judge whether each decision was right. That is a record of decisions rather than a record of traffic, and nearly every wrong conclusion drawn from such a log comes from reading it as the second. ## What an entry has to tell you Four things, because judging a decision needs all four. **What was asked for.** The `URL` path, the `HTTP` method, and the shape of the request, which is what lets you recognise whether this was somebody using your site or something probing it. A request for a path your site has never had tells you something on its own; a request for a form your customers use every day tells you the opposite. **What matched.** Which rule fired, since a decision you cannot attribute to a rule is a decision you cannot change. **What happened.** Whether the request was recorded and forwarded or recorded and refused. In monitor mode the record says what would have happened, which is the entire reason the mode exists. **Enough context to tell a person from a machine.** The surrounding activity matters more than any single field: a flagged request sitting inside an ordinary sequence of successful ones reads differently from one arriving alone, which is the pattern [false positives](/operations/false-positives/) is read for. Flagged requests reach the log in batches and arrive near-real-time, which is what makes reading the record practical while the traffic that produced it is still current rather than as a historical exercise. ## What it is not This matters enough to state plainly, because the log looks like something it is not. It is not a traffic overview. It is not a count of attacks by volume, and it is not a view of volumetric attack figures of any kind. It is not a general analytics surface, and it is not a dashboard for the class of attack measured in bandwidth rather than in requests. The reason is a missing denominator rather than a missing feature. The log contains flagged requests, so it knows nothing about the requests that were not flagged, and every ratio you might want, the share of traffic affected, the proportion of visitors refused, the fraction of attacks caught, requires the part it does not have. A record built to answer a decision question cannot be extended into a measurement surface without becoming worse at the job that made it useful. That mistake misleads in both directions, which is what makes it expensive. A rise in entries can mean more hostile traffic, or it can mean a rule you added last week matches something ordinary. A fall can mean the attacks stopped, or it can mean a rule stopped matching what it used to. Neither reading is available from the log alone, and neither is safe to report. ## What it answers well Three questions, and they are the ones to ask. **Was this decision right?** The original purpose. One entry, its context, and a judgement about whether that request should have been refused. **What does this rule do to my site?** Group the entries by rule and by route. Concentration on one path usually means a collision with your own content rather than a pattern of attack, which is the distinction that decides whether you write an exception or leave the rule alone. **What changed since my last configuration change?** Compare the same rule and the same route before and after. This is the only comparison in which the denominator is stable, because you are measuring your own edit rather than the behaviour of the world. ## What it cannot answer Three questions people bring to it anyway. **How much traffic do I receive?** Answered by whatever measures all requests, not by a record of the flagged ones. **Was I attacked, and how large was it?** Volume questions belong to volume measurement. A record of individual flagged requests is the wrong instrument for something described in bandwidth, and reading it that way produces confident numbers with nothing underneath them. **How many customers did this cost me?** The log shows refused `HTTP` requests, not people. What a refusal cost is visible in the business signal for that route, completions, orders, successful calls, which is why that signal is watched alongside the log rather than after it. ## The same record, two jobs Its role changes between modes even though its contents do not. During observation it is a list of predictions: what would have been refused, read to build the exception list before anything is enforced. That is the work described under [monitor mode](/operations/monitor-mode/), and the exceptions it produces are written calmly, with dates, as [exceptions](/operations/exceptions/) sets out. After enforcement begins it becomes a list of events: what was actually refused, read to catch the collisions that observation missed. Same entries, same fields, different question, and the second job never fully ends. ## Before you need it Establish one thing early: how far back the record goes. Reports about refused requests arrive late. Somebody could not submit a form on Friday, mentions it on Tuesday, and the investigation depends entirely on whether Friday is still in the record. Find out what the retention is while nothing is wrong, and if it is shorter than the delay at which your reports typically arrive, arrange to keep what you need elsewhere before the first report rather than after it. ## FAQ **Does the activity log show how much traffic my site gets?** No. It contains requests that filtering flagged, so it has no view of the ones it did not flag, and any share or ratio you compute from it is missing its denominator. Traffic questions belong to whatever measures all requests rather than to this record. **Can I use it to see the size of an attack?** Not usefully, and it is not built for it. The log records individual flagged requests, which is the wrong unit for anything described in volume rather than in requests, and it is not a dashboard for that class of event. Reading it that way produces a number that looks authoritative and has very little underneath it. **Why did entries increase after I changed a rule?** Because the log reflects your configuration as much as it reflects the traffic. A new or broadened rule matches more, including ordinary requests, so a rise immediately after a change is a statement about the change first and about the world second. **How far back does the record go?** That depends on retention, and it is worth finding out before you need it. Reports about refused requests arrive days late, so a retention window shorter than your typical reporting delay means the evidence is gone by the time somebody asks. --- https://bridge-waf.com/operations/exceptions/ --- # Filtering exceptions: every one needs an expiry date An exception is a hole with a reason attached. While the reason is attached it is a decision; once the reason is lost it is just a hole, and the loss happens by default rather than by neglect. Everything below is about keeping the two together for as long as the exception exists. ## What to record when you add one Five things, and the fifth is the one nobody writes down. **What is exempted.** The narrowest accurate description: this `URL` path, this form field, this client. A scope recorded loosely will be read loosely a year later by somebody deciding whether it still applies. **Why.** The specific case, not the category. "Support form rejects error messages containing `HTML`" survives; "false positives" does not, because it describes every exception ever made and therefore distinguishes none of them. **Who owns it.** A person or a team who would notice if it were removed. Exceptions without an owner are the ones that survive reorganisations untouched, because removing them is nobody's risk to take. **When it ends.** A date. Either the exception expires then, or somebody looks at it then, and record which of the two it is. **What would make it unnecessary.** The condition under which the hole can close: a form that stops accepting raw `HTML`, an integration that starts signing its `HTTP` requests, a rule adjusted upstream. This field is what turns a list of exceptions into a list of work, and without it the review below has nothing to decide with. ## Four kinds, by how long they live Lifetime is the useful way to sort them, because it determines what you do next rather than how the exception looks. **Incident exceptions**, added while something is on fire. These have the shortest legitimate life and the highest survival rate, which is the whole problem. Anything added during an incident should carry an end date measured in days and be revisited when the incident review happens rather than whenever somebody remembers. **Launch and migration exceptions**, added to get something out of the door. These live for weeks and end when the thing they unblocked is stable. Their characteristic failure is that the launch succeeds, everybody moves on, and the exception is the only trace of a temporary state that no longer exists. **Integration exceptions**, describing a partner, a provider callback, or an internal system. These have no natural end, and pretending otherwise produces an expiry date that gets extended without thought every time it arrives. Give them a review date instead, and treat the review as a check that the integration still exists and still behaves the way the exception assumes. **Content collisions**, where your own legitimate content trips a rule. These should be the shortest-lived of all, because an exception here is a workaround for a mismatch that can usually be corrected at the rule or in the form. Left permanently, they are the class most likely to widen, since the next similar collision is easiest to solve by extending the exception that already exists. Finding these in the first place is the subject of [false positives](/operations/false-positives/). ## The ones that cannot expire Some exceptions are permanent, and the honest thing is to say so rather than to set a date nobody intends to honour. A permanent exception is not dangerous because it is old. It is dangerous because its scope drifts: the integration it describes gains new endpoints, the client identifier it names is reused by something else, the route it covers is reorganised so that the exception now applies to more than it did. Age is a proxy for that drift, which is why review dates work even for things that will never be removed. Two habits keep them honest. Recording the scope in terms that fail loudly when the world changes, rather than terms that quietly widen. And reviewing them against the thing they describe rather than against the exception itself: the question is whether that integration still works this way, not whether the exception still looks reasonable. ## Removing one safely Deleting an exception is a change to filtering behaviour, and it deserves the same care as adding one. The safe sequence is to stop enforcing the removal before making it: put the affected traffic back under observation, watch what would now be refused, and confirm it is what you expect before the exception actually goes. That is the same discipline as [monitor mode](/operations/monitor-mode/), applied in the opposite direction, and it turns a removal from a guess into a measurement. Two things not to do. Do not remove several exceptions at once: if something breaks, you will have no way to attribute it, and attribution is the entire value of doing this deliberately. And do not remove them during a period when traffic matters most, such as a sale or a launch, because the failure mode of a wrong removal is refusing customers at exactly the moment there are most of them. Where a removal does cause refusals, reinstate the exception first and investigate afterwards. The information is still there an hour later; the customers are not. ## The review that makes this work A standing review, on whatever cadence you already use for other configuration. Go through the list, and for each entry ask the three questions the record already contains: does the reason still hold, does the owner still exist, and has the condition that would make it unnecessary been met. Entries that fail the first two are candidates for removal today. Entries where the third is now satisfied are the work the review exists to find. The list itself is the deliverable. An exception that is not on it is not managed, whatever its expiry date says, and the most common reason a review finds nothing is that the exceptions being added are not reaching the list at all. ## FAQ **Why does every exception need a date?** Because the circumstance that justified it ends before the exception does, and nothing else notices. A date is the only mechanism that forces a second look; without one, the safe-feeling choice is always to leave it alone, and that choice is made silently by everybody who inherits it. **What about exceptions that are genuinely permanent?** Give them a review date rather than an expiry. The risk with a permanent exception is not its age but its scope drifting as the thing it describes changes, so the review checks the integration or route it covers rather than the wording of the exception. **Is it safer to keep an exception than to remove one?** Only in the moment. Keeping is safe today and accumulates; removing carries a small, immediate, observable risk you can manage by watching first. The practice that fails is the one where nothing is ever removed because each individual removal looked riskier than doing nothing. **How narrow should an exception be?** As narrow as the case that prompted it: one route, one field, or one client rather than one rule switched off. A broad exception is indistinguishable in effect from not having the rule, and it will be described in the record as though it were something smaller. --- https://bridge-waf.com/operations/false-positives/ --- # False positives: finding the customers you refused A false positive is a legitimate request that filtering refused. Its defining property is not that it is wrong but that it is silent: the person affected sends no report, files no ticket, and leaves no entry that reads as a problem. Finding them is therefore something you do deliberately rather than something that happens to you. ## What the refused person actually experiences Picture it precisely: it explains the silence. They do not see a security decision. They see a page that will not submit, a form that clears itself, an application that appears broken, or a refusal they have no vocabulary to describe. The conclusion available to them is that your site does not work, and the action available is to leave. Neither produces anything you can search for later. The few who do report are a biased sample. They are the ones with an existing account, an order in progress, or a support contact they already know, which means the reports you receive describe the least severe version of the problem and come from the people least likely to be lost by it. ## Where they hide in the record Four places, in the order to check them. **Blocked requests that look like a visit.** A person browsing arrives through a plausible sequence: a listing, a page, a form. A blocked request sitting in the middle of such a sequence, from an address that also produced successful requests, is a person and not a probe, whatever the `URL` it landed on suggests in isolation. This pattern is the single most reliable indicator available without additional data. **Blocks that cluster on one endpoint.** Any form that legitimately carries awkward content will collide with content-inspecting rules: a bug report field carrying `SQL`, a support form carrying an `HTTP` error message, a comment field carrying `HTML` or quotes. The cluster is usually sharp, sitting on one path while the rest of the site shows nothing. **Blocks that cluster on one kind of client.** Integrations, partner automation, and provider callbacks are legitimate machines, and they complain even less than people: they retry, exhaust their attempts, and fail into somebody else's log. A refused callback is often discovered as a business discrepancy weeks later rather than as a filtering event. **Divergence from what the business sees.** A drop in completions for one form, in one country, or on one platform, without a matching change anywhere else, is worth checking against the record before it is explained as a seasonal effect. This is the check that finds what the first three miss. ## How to size the problem Carefully, and without inventing a percentage. A false positive rate cannot be computed, because computing it would require knowing which of the refused requests were legitimate, which is the very thing you do not know. Any number presented as such is an estimate wearing a measurement's clothes, and it will be quoted later without its caveat. What can be measured honestly is narrower and more useful: **Share by rule and by endpoint.** Which rules account for most refusals, and which paths receive them. Concentration is the signal: a rule firing across the whole site behaves differently from one firing on a single form, and the second is far more likely to be a mismatch with your own content. **Trend after a change.** Compare the same rule and endpoint before and after a configuration change. This measures your own edits rather than the truth of the world, and it is the only comparison where the denominator is stable. **Confirmed cases.** The ones you established by investigation, counted as what they are: a floor rather than a rate. A handful of confirmed cases on one endpoint says more about that endpoint than any ratio would. ## Fixing one without disabling everything A ladder, narrowest rung first. Take the highest rung that solves the case in front of you and stop there. **Narrow by path.** Adjust the behaviour for the specific route where the collision occurs, leaving every other route untouched. Most real cases end here, because most collisions are between one rule and one form. **Narrow by field or parameter.** Where a single input carries the content that trips the rule, that input is the scope of the problem. **Narrow by client.** Where the affected party is a known integration or callback, the exception describes that party rather than the path, which keeps the path protected for everybody else. **Change the rule's scope.** Slower and more deliberate, appropriate when the same collision appears in several places for the same reason. Before disabling a rule outright to unblock one form, note what that does: the rule stops applying everywhere, including the paths that were never involved and the ones that most needed it. This is the change that gets made under pressure at the end of a long day and is never revisited, and the time to write it down as a temporary measure is the moment you make it, rather than intending to remember. Every narrowing above is an exception, and an exception without an owner and an end date is a permanent change that nobody decided to make. That subject has its own page in this section. ## Not making the next one Three habits, and the first does most of the work. Watch before enforcing. A change observed first shows its collisions before they cost anything, which is what [monitor mode](/operations/monitor-mode/) is for and why it comes before enforcement rather than after a problem. Change one thing at a time. Two adjustments made together produce a result that cannot be attributed to either, and the attribution is what you will need when a report arrives days later. Keep a record of what changed and when. Reports about refused requests are always retrospective, and the question they raise is always the same: what was different that day. A short log of configuration changes answers it in seconds and is the cheapest thing on this page to maintain. ## FAQ **How do I know a blocked request was legitimate?** Look at what surrounds it. A refusal in the middle of an ordinary sequence of requests, from an address that also produced successful ones, is a person. A refusal standing alone, from an address with no other history, is not evidence of anything either way and is not worth investigating first. **What is an acceptable false positive rate?** The question has no answerable form, because the rate cannot be computed without knowing which refused requests were legitimate. Measure share by rule and endpoint, and the trend across your own changes, and treat confirmed cases as a floor rather than a percentage. **Should I disable the rule that keeps firing?** Not as a first step. Narrow it to the path, the field, or the client where the collision happens, which fixes the case without removing the rule from every other route. Disabling it outright is the change that survives longest and gets reviewed least. **Why do integrations never report being blocked?** Because they are built to retry rather than to complain. A refused callback exhausts its attempts and fails into somebody else's system, so the symptom surfaces as a business discrepancy later rather than as anything visible at the time it happens. --- https://bridge-waf.com/operations/incident/ --- # Incidents: making emergency changes you can unwind During an incident you will change things quickly and more broadly than you would on an ordinary day, and that is the correct response to pressure. Whether you come out ahead is decided afterwards, in the week when the pressure is gone and every one of those changes is still in place. ## Two incidents that look alike Before anything else, work out which of these you have, because they pull in opposite directions. **Something hostile is arriving.** Requests are refused and the refusals are correct. The instinct to widen and tighten is right, and the risk is collateral damage you will not see until later: legitimate visitors caught by a rule written in a hurry for somebody else. **Filtering is refusing your own traffic.** Customers or an integration cannot get through, and every entry in the record is a mistake. The instinct to widen is exactly wrong here, and the risk is spending the outage making it worse. Three questions separate them faster than argument. Did anything change on your side recently, a deployment, a new rule, a new form, since a fault that begins minutes after a change is usually the change. Are the refusals concentrated on one route, since your own collisions concentrate and hostile traffic usually does not. And do the affected requests sit inside otherwise ordinary sequences, which is the pattern described under [the activity log](/operations/activity-log/) and the clearest evidence that the people affected are real. ## While it is happening Two habits, and they cost nothing at the time. **Write down every change as you make it.** The time, the `URL` path or rule you changed, and why, in whatever is already open. Nobody reconstructs this afterwards, and the reconstruction is what the whole review below depends on. A note that says "14:20 blocked the whole subnet, checkout was drowning" is worth more later than a perfect description written from memory a week on. **Prefer changes you can reverse in one action.** A broad, single, reversible change is better under pressure than a precise one assembled from several edits, because the precise one cannot be undone quickly and you are the least reliable version of yourself right now. Broad now and narrow later is a legitimate sequence; broad now and forgotten is the failure. That second habit also decides what to do when a change does not help. Undo it before trying the next thing. Stacked changes that each did nothing are indistinguishable from a change that did something, and by the third one nobody knows what the configuration is. ## The move to think twice about Turning filtering off entirely is the change most likely to be reached for and least likely to be right. Before you do it, note what it costs: inspection stops everywhere, including on everything unrelated to your problem, at the exact moment you have the least visibility into what is arriving. If the fault is that legitimate traffic is being refused, the narrower move is returning the affected route to observation, which restores service on that route immediately while keeping the record you will need in an hour. Off remains the right answer when filtering itself is clearly the cause, the `HTTP` responses your visitors receive are refusals rather than pages, and you cannot yet tell which rule is responsible. Reaching for it deliberately, with a note of the time, is a different act from reaching for it because it is the biggest available lever. ## Unwinding afterwards The part that gets skipped, and the reason this page exists. Start within a few days, while the note still means something to the person who wrote it. Go through every change and put it in one of three places: it becomes part of the configuration because it was right all along, it becomes an exception with an owner and a date as [exceptions](/operations/exceptions/) describes, or it is removed. Unwind the broadest changes first. They carry the most collateral, they are the ones least likely to have been targeted at the actual cause, and they are the reason people quietly cannot reach you. A wide block put in during an event is refusing somebody today, and nothing in your systems is going to mention it. Then unwind one at a time, watching between each. That is the same discipline as removing any exception: put the affected traffic back under observation, confirm what would now be refused, and only then let the change go. Doing this during a quiet period rather than at the end of the same week is not procrastination, it is the difference between a controlled removal and a second incident. ## What the review should produce Three things, and none of them is a document nobody reads. **A list of what stayed, with reasons.** Anything still in place a week later either has a justification written next to it or should not be there. The list is short if the unwinding was done and unmanageable if it was not, which makes it a useful measure of the review itself. **One change that would have made this cheaper.** Not a plan for perfection: a single concrete thing, such as a route that should have been observed before being enforced, or an integration that should have been exempted with a date long ago. **One gap in what you could see.** During the event, what did you want to know and could not? That question produces better improvements than any discussion of the attack itself, because it is answerable and because the next incident will be different in every respect except your visibility into it. ## FAQ **How do I tell an attack from my own filtering breaking things?** Ask what changed on your side recently, whether the refusals concentrate on one route, and whether the affected requests sit inside otherwise ordinary sequences. Concentration and a recent change on your side point at your configuration; scattered refusals with no recent change point outward. **Should I turn filtering off during an incident?** Rarely, and never as the first reach. It stops inspection everywhere at the moment you can least afford to be blind. If your own traffic is being refused, returning that one route to observation restores service while keeping the record you will need afterwards. **Is it acceptable to make a broad change under pressure?** Yes, provided you can reverse it in one action and you write down that you made it. Broad now and narrow later is a legitimate sequence. The failure is not the breadth, it is the change that stays because nobody remembers making it. **How soon should emergency changes be reviewed?** Within days, while the notes still mean something to their author. Every one of them was right for that hour, and almost none is right permanently, so the review decides which become configuration, which become dated exceptions, and which simply go. --- https://bridge-waf.com/operations/monitor-mode/ --- # WAF monitor mode: see what would have been blocked Monitor mode runs every rule and blocks nothing. Each request that matches is recorded with what would have happened, so you can read a week of decisions before any of them affects a visitor. It is the cheapest way to find out what enforcement would cost you. ## What the mode actually does The rules run identically. The only difference is at the end. A request arrives, is evaluated against the rule set exactly as it would be under enforcement, and a decision is reached. Under enforcement that decision is applied. In monitor mode it is recorded and then discarded, and the request continues to your origin as if nothing had been evaluated. One consequence of that distinction is easy to miss: while you are watching, nothing is being stopped. Monitor mode is an instrument, not a posture. It tells you what enforcement would do; it does not do any of it. There are three modes in total, and this is the middle one. Off evaluates nothing, monitor evaluates and records, block evaluates and acts. There is no fourth setting and no scale between them. Tools in this category often have one, and the reflex is to look for it. Adjustment here happens through rules and exceptions rather than through a dial, as covered under [rules](/rules/). ## What you are looking for Not the total. The total tells you almost nothing on its own. **Legitimate traffic that would have been stopped.** This is the entire reason the mode exists. Somewhere in the record are requests from real users, your own integrations, or a partner's system, that a rule considers hostile. Each one is an outage you have not had yet, and finding them before enforcement is the difference between a controlled change and an incident. **Patterns rather than counts.** A hundred matches from one source in one minute is one story; a hundred matches spread across a hundred sources over a day is a different one. The same number means opposite things, and only the shape distinguishes them. **Requests you cannot explain.** The useful discipline is to treat every unexplained match as a question rather than as noise. Some will turn out to be genuine attacks, which is reassuring. Some will turn out to be a client of yours doing something unusual, which is the finding that saves you. **Your own machinery.** Health checks, deployment hooks, monitoring agents, and internal scripts all make requests that look automated because they are. They are the most commonly surprised category, and they are also the easiest to fix once seen. One habit makes this work go faster: write down the explanation as you find it, next to the thing it explains. A month later the same pattern will appear again, and without a note somebody repeats the whole investigation. The record accumulated during monitoring is the raw material for the exceptions you will write, and undocumented conclusions do not survive the gap between the two. ## How long to watch Long enough to see your traffic, which is a question about coverage rather than about days. A period that contains no deployment, no marketing activity, and no monthly job has not shown you your site. The useful question is whether the window included the things that make your traffic unusual: a release, a campaign, a billing run, whatever your equivalent of a busy Friday is. Enforcement turned on after a quiet week discovers the busy week by breaking it. The other half of the answer is qualitative. You are ready when the record contains nothing you cannot account for, which is a stronger condition than it sounds and a more useful one than any fixed duration. A site with two unexplained matches is not ready; a site with several thousand explained ones may well be. ## Reading the record The log holds requests the rules flagged, and knowing its boundaries keeps you from asking it the wrong questions. It records flagged requests in near real time, batched, with sub-second latency, so what you are reading is current rather than a report from yesterday. Each entry tells you which request matched and what would have happened to it. What it is not is a volumetric traffic dashboard. It does not tell you how much traffic your site received, nor summarise attack volume, because it only ever contains requests a rule flagged. Asking it how big an event was is asking a question it was not built to answer, and its own page in this section sets out exactly what it holds and what it does not. ## Moving to enforcement The transition is a decision, and it does not have to be all at once. Enforcement can begin on part of the site, on one path, or for one class of rule, so the first real block happens in a place you are watching closely rather than everywhere simultaneously. How to choose that first slice is set out under [staged rollout](/operations/staged-rollout/), and it matters because the first enforcement is the one most likely to surprise you. What monitor mode has bought you by that point is the list of exceptions you need before enforcement rather than after it. Writing those exceptions while nothing is broken is a calm task. Writing them during an outage, with somebody asking why checkout is failing, is the same task done badly. ## FAQ **What does WAF monitor mode do?** It evaluates every request against the rules and records the decision without applying it. You get a full record of what enforcement would have done, including which legitimate requests it would have stopped, while traffic continues to reach your site unaffected. **Does monitor mode protect my site?** No, and this is the one thing to be clear about. While the mode is active nothing is being blocked, so it provides visibility rather than protection. It is a step on the way to enforcement, not a substitute for it, and leaving it on indefinitely means watching without acting. **How long should I run monitor mode?** Until the record contains nothing you cannot explain, and until the window has covered the events that make your traffic unusual: a deployment, a campaign, a scheduled job. A fixed number of days is the wrong measure, because a quiet week proves only that the week was quiet. **Can I adjust how aggressive the rules are?** There is no sensitivity setting to adjust. The modes are off, monitor, and block, and tuning happens through rules and exceptions rather than through a level. That is a deliberate design choice: a dial makes the behaviour harder to predict and harder to explain after the fact. --- https://bridge-waf.com/operations/staged-rollout/ --- # Staged rollout: how to turn on filtering in slices Enforcement does not have to begin everywhere at once. Choose a slice small enough that a mistake is recoverable and ordinary enough that success there tells you something about the rest. Everything else on this page follows from those two words: recoverable, and representative. ## Three ways to slice, and what each costs The slice you choose decides what you can learn, not only what you risk. **By path.** Enforce on one `URL` path and leave the rest observing. Attribution is unambiguous: anything that changes, changed there. The blast radius is a route you picked deliberately, and rolling back means touching one thing. **By rule.** Enforce one group of rules everywhere and leave the others observing. Useful when a specific class of request is the reason you are doing this at all, and it answers a different question: what this rule does to your whole site rather than what your whole configuration does to one part. **By share of traffic.** Enforce for a fraction of requests across everything. This is the one that looks most scientific and helps least at the start, because the effect is spread thinly across every route: a real problem appears as a small anomaly in many places rather than an obvious one in a single place, and the first thing you lose is attribution. Start by path. Move to rule-level once you have a route where enforcement is uneventful, and treat share-based slicing as a way to widen at the end rather than a way to begin. ## Choosing the first path Two rejections and one criterion. Not the busiest route, and not the one that carries money. Both are the places where a surprise is most expensive, and neither is where you want to be learning what your rules do to your own content. Also not something so unusual that nothing follows from it. A route nobody uses, or one whose traffic looks like nothing else on the site, produces a clean result that predicts nothing about the pages you actually care about. The criterion between those rejections: the route should resemble what you will enforce on later. If your risk is people submitting text, pick a route where people submit text. If it is an `API` consumed by other systems, pick one of those. Representativeness is the whole reason for going first, and a slice that is not representative is a delay rather than a test. ## What to watch, and for how long Two signals, and the second is the one that catches what the first misses. The record of refusals on the enforced route tells you what the rules are doing. Read it the way [false positives](/operations/false-positives/) describes, looking for refusals that sit inside otherwise ordinary sequences of requests. The business signal for that same route tells you what the refusals cost. Completions of the form, orders through that path, successful calls from that integration: whatever the route exists to produce. For an `API`, that means watching the `HTTP` responses its callers receive rather than any page. This is the signal that notices the people who left without saying anything, and the time to agree on it is before enforcement starts rather than afterwards. Watch for at least one full cycle of that route rather than for a fixed number of hours. A path used by staff behaves differently at the weekend; a checkout behaves differently on a payday; an integration that runs a nightly job produces nothing worth reading until the night it runs. The cycle, not the clock, decides when you have seen enough. ## Expanding without losing the thread One dimension at a time, and each expansion is a new first enforcement for a new population. Widen the set of routes, or add the next group of rules, but not both in the same change. Two changes made together produce an outcome that cannot be attributed to either, and attribution is what the staging was for. Each new slice deserves the same short watch as the first, though usually a shorter one, because by then you know which of your own content collides with which rules. What you carry forward is the list of exceptions built along the way, written calmly rather than during an incident, and each one dated as [exceptions](/operations/exceptions/) describes. ## Deciding in advance what makes you stop Write the rollback trigger down before you enforce anything, because afterwards it will be negotiated. A usable trigger names an observation rather than a feeling: refusals on the enforced route rising without a matching change in traffic, the route's completions falling while comparable routes hold steady, or a single confirmed report from a real customer. Any one of those is enough. The purpose of writing it beforehand is that during the event, everybody's instinct is to wait a little longer and see, and that instinct is what turns a five-minute rollback into an afternoon. Returning the route to observation is not a failure of the rollout. It is the mechanism working: you learned something at the cost of one route for one period, which is the price you agreed to pay when you chose to stage this rather than enable it everywhere. Two timing rules. Do not begin during a peak period, since the point is to learn cheaply and a peak makes every lesson expensive. And do not widen enforcement immediately before a stretch when nobody is watching, such as a holiday or a weekend, because the failure mode of a bad expansion is silent and the people it affects will not wait for Monday. ## What you have at the end A configuration where each part was observed before it refused anything, and a record of what changed when. That record is worth more than it looks. Reports about refused requests arrive days late, and the question they raise is always which change is responsible. A staged rollout answers it by construction: each step was one change, watched for one cycle, on one slice, with a trigger written down in advance. ## FAQ **Where should enforcement start?** On one route, chosen because it resembles the traffic you will enforce on later, and because a surprise there is affordable. Not the busiest path and not the one carrying money, since those are where a mistake costs most and where you least want to be discovering what your rules do. **How long should each stage run?** Long enough to cover a full cycle of that route rather than a set number of hours. A path used on weekdays, a checkout with a payday pattern, and an integration with a nightly job all need different durations, and each one shows its real behaviour only across its own cycle. **Can I enforce for a percentage of traffic instead?** You can, and it is a better tool for widening than for starting. Spreading the effect thinly across every route means a real problem shows up as a small anomaly in many places at once, which costs you the attribution that makes early stages worth running. **What if I have to roll back?** Return that slice to observation, keep everything you recorded, and treat it as the mechanism working rather than as a setback. Deciding the trigger beforehand is what makes this a quick decision instead of a debate held while the problem continues. --- https://bridge-waf.com/operations/tuning/ --- # Tuning without dials: which lever to reach for first There is no strictness scale here to raise or lower. Tuning means changing specific things: which rules apply and where, which requests are exempted, and where limits are set. That makes each change slower to decide and far easier to undo, and it changes which lever you should reach for first. ## Why a scale would not help The expectation comes from a familiar model, and the model has a defect. A strictness setting promises one decision instead of many. Its cost is that nobody can say what a position on it means: moving from one level to the next changes a large number of individual decisions at once, in ways that differ per site, so the effect cannot be attributed to anything. When something breaks afterwards, the available explanation is that the level is now higher, which is not an explanation. The absence of a scale forces the opposite habit. Every change names a rule, a route, a request, or a limit, and every change can therefore be tested, reversed, and explained to somebody who was not there. That is slower on the day and much faster over a year. ## The three levers Everything you can adjust is one of these. **Which rules apply, and where.** The scope of a rule is a decision: a rule that belongs on a form does not necessarily belong on a static `URL` path, and narrowing where it applies is a change with an obvious meaning. **Which requests are exempted.** The narrow carve-outs for the cases where your own content or a known integration collides with a rule. These are covered by [exceptions](/operations/exceptions/), including the part that matters most, which is that each one carries a date. **Where limits are set.** Rate limiting is applied to the domain, and what that means in practice, along with how to choose a limit at all, belongs to [rate limiting](/rate-limiting/). ## Which lever to reach for first Four rungs, and the first is the one people skip because it is not a filtering change at all. **Change your own thing.** Where a rule collides with your content, the first question, before any configuration, is whether your side is doing something it does not need to do: a form accepting raw `HTML` it never displays, an integration sending unsigned `HTTP` requests it could sign, a route accepting a method it does not use. Fixing that removes the collision permanently and improves the site independently of any filtering. **Narrow where the rule applies.** If the collision is real and your side is correct, restrict the rule to the `URL` paths where it earns its place. This keeps the protection and removes the mismatch, and it stays true when the site grows. **Write an exception.** Narrow, owned, dated. Correct when the collision is specific and legitimate, and the right answer for integrations and callbacks that will not change for you. **Change something broadly.** Last, deliberately, and rarely. A broad change is the only one whose effect you cannot fully predict, so it belongs at the end of the list rather than at the start, where it usually appears because it is the quickest thing to do at the moment somebody is complaining. ## Making one change safely Three habits, and they are the same ones that make a rollout survivable. One change at a time, stated in a sentence. Two changes made together produce an outcome that belongs to neither. Watched for a cycle of the route it affects, not for a fixed period, since a route used on weekdays and an integration that runs nightly reveal themselves on different schedules. That reasoning is set out under [staged rollout](/operations/staged-rollout/). Recorded with its date and its reason. The report that tests your change arrives days after you make it, and the only question it raises is what was different that day. ## What not to tune Two things, and both are common. **A single event.** One probe, one scanner, one odd request from an address that never returns is not a signal. Tuning in response to it optimises your configuration for something that already stopped, and every such change is permanent until somebody removes it. **The count of entries.** Tuning until the record is quiet is tuning toward a log that tells you nothing. Entries are the instrument, not the fault; a configuration producing no entries is either seeing no hostile traffic, which is unlikely, or has been adjusted until it stopped reporting. The second is indistinguishable from the first at the moment you achieve it and very distinguishable later. ## When to tune again Tuning is not a setup step, because the fit degrades from your side rather than theirs. Come back to it when the site changes in a way that changes traffic: a new form, a new integration, a market that brings visitors from somewhere your rules have never seen, an application rewritten to send different requests. In each case the configuration did not change and stopped fitting anyway. The cheap version of this is a short observation after each such change, on the affected routes only, rather than a periodic review of everything. The expensive version is discovering the mismatch through a customer months later. ## FAQ **How do I make filtering stricter or less strict?** There is no scale to move. You change which rules apply and where, which requests are exempted, and where limits are set, and each of those is a specific statement rather than a position on a range. The result is slower to decide and much easier to reverse when it turns out to be wrong. **A rule keeps colliding with my own content. What first?** Check whether your side needs to do the thing that trips it, since a form accepting content it never displays is a problem worth fixing regardless. Then narrow where the rule applies. An exception comes after those two, and disabling anything broadly comes last. **Should I tune after seeing a suspicious request?** Not after a single one. One probe from an address that never returns is not a pattern, and a change made in response to it stays in your configuration long after the event that prompted it is forgotten. Wait for the pattern, then change one thing. **How do I know the tuning is finished?** It is not a state you reach. The configuration fits the site as it is now, so a new form, a new integration, or a new audience puts it out of fit without anybody touching it. A short observation after each such change is what keeps it current. --- https://bridge-waf.com/rate-limiting/429/ --- # 429 Too Many Requests: how to fix it on both sides A `429` means the server understood the request, found nothing wrong with it, and refused it because it arrived too often. That is different from a rejection and different from a block: the request was valid, and the same request will succeed later. What to do about it depends entirely on which end of it you are. ## If you are receiving 429 Five steps, in this order, because the first two solve most cases. **Stop retrying immediately.** The commonest cause of a `429` that will not go away is the client's own retry loop: the refusal arrives, the client retries at once, that retry is also refused, and the pattern that triggered the limit is now sustained by the attempt to escape it. Check this before anything else, because a client written to retry on failure treats rate refusal as an ordinary error and does the wrong thing with it. **Look for `Retry-After`.** If the response carries it, that is the server telling you when to come back, and honouring it is both the fastest route to success and the cheapest thing you can do. Where it is absent, back off progressively rather than at a fixed interval, and add a little randomness so that many clients refused together do not all return at the same moment. What that header does and why it is worth sending is covered under [Retry-After](/rate-limiting/retry-after/). **Count what you are actually sending.** A surprising share of limits are hit by clients doing work they do not need: polling for something that could be delivered once, fetching in a loop what could be fetched in one request, or re-requesting the same unchanged resource. Fixing that removes the limit as a problem rather than working around it. **Consider that it may not be about you.** If you share an outbound address with other people, an office, a shared platform, a mobile network, you can be refused because of traffic that was never yours. That failure mode, and why counting by address produces it, is set out under [per-IP versus per-user](/rate-limiting/per-ip-vs-per-user/). **Ask, if it is somebody else's service.** Where the limit belongs to a provider you use, the productive move is a conversation about your usage pattern, not persistence. No amount of retrying changes a limit, and sustained retrying is the behaviour most likely to get a client treated as hostile. ## If you are sending 429 Five causes, in the order you should check them. **The limit is doing its job.** The client really is asking too often, and the refusal is correct. This is the case the limit exists for, and the check that confirms it is concentration: one client, or a small number, receiving most of the refusals. **The limit is too low for a normal burst.** Ordinary clients are not smooth. A page that loads several resources at once, an application that syncs on opening, a batch that runs after a deployment: each produces a short spike inside an otherwise modest average. A limit set on the average refuses them all, which is the subject of [bursts](/rate-limiting/burst/). **The subject of the limit is wrong.** Counting by address when your users share addresses refuses whole offices for the behaviour of one person, and counting by account when the abuse arrives from thousands of accounts counts nothing useful. Choosing the subject is a separate decision from choosing the number. **The client cannot tell when to return.** A refusal without `Retry-After` leaves a well-behaved client guessing, and the common guess is to try again straight away. This turns one refused request into a stream of them and makes your own limit look like it is not working. **Something of yours is being limited.** Your monitoring, your own integration, a job that fetches your site on a schedule: all of these arrive looking like anybody else. Check this before assuming an outside cause: the traffic is familiar to you and completely anonymous to the limit. ## What a good 429 contains Three things, and the third is the one usually missing. The status itself, so a client can distinguish rate refusal from any other failure and respond correctly. A `Retry-After` value, so it knows when to come back instead of guessing. And a short readable explanation in the body, since some of the clients that receive it are people looking at a browser rather than software parsing a response. Two things to avoid. Do not use `429` for authorisation problems, which are a different answer to a different question, and do not use a generic error for rate refusal, because a client cannot tell the difference and its retry behaviour will be wrong in the way that costs you most. ## Checking that yours behaves Read the refusals by client rather than in total. Concentration on one client is the intended outcome, and it is what a working limit looks like. A thin spread across many different clients usually means the limit or its subject is wrong rather than that everybody started misbehaving on the same afternoon, and the same reading applies after any change: compare the same route before and after instead of looking at the count on its own. Bridge WAF applies rate limiting per domain, and the surrounding decisions, which subject to count and how to handle bursts, remain yours to make. See how that fits the rest of the delivery path at [Bridge CDN](https://bridge-cdn.com/). ## FAQ **What does 429 actually mean?** That the request was understood and valid but arrived too often, so it was refused for rate rather than for content. The same request will succeed later, which is what separates it from a rejection you need to fix by changing what you send. **How long should I wait before retrying?** As long as `Retry-After` says, if the response carries it, since that is the server stating its own answer rather than you guessing at one. Without it, back off progressively and add a little randomness, so that clients refused at the same moment do not all return together and reproduce the condition that refused them. **Why am I being limited when I barely send requests?** Most often because the count is not about you alone. Shared outbound addresses mean an office, a campus, or a mobile network can be counted as a single client, so the traffic that crossed the limit may have been somebody else's entirely and there is nothing in your own usage that would explain it. **Should I use 429 or just block the client?** Use `429` when the client is welcome but too frequent, since it tells them the truth and lets a well-behaved one adjust. Blocking answers a different question, and using it for rate makes ordinary clients look hostile in your own record. --- https://bridge-waf.com/rate-limiting/algorithms/ --- # Rate limiting algorithms: four ways to count requests Four algorithms cover nearly every limit in use, and they allow the same average traffic while behaving completely differently at the edges. The choice between them does not decide how much a client may send. It decides what shape of sending is allowed, which is what ordinary clients notice. ## What the algorithm decides Not the number, but the meaning of "too often". Every limit has a rate and a period. What the algorithm adds is the answer to what happens when requests arrive unevenly, which they always do: whether a client may spend its whole allowance at once, whether a quiet hour earns anything, and what happens at the moment a period ends. Those edges are where real clients live, and they are the reason two limits with identical numbers can produce completely different complaints. A browser loading a page requests many things at once and then nothing for a minute. An `API` client syncing on start does the same in a shorter span. A scheduled job does all of its work in one stretch and sleeps for a day. None of those is misbehaving, and every one of them looks like a spike to a counter that expects an even flow. ## Fixed window The simplest to implement and the easiest to get surprised by. ```text on request(key): now_window = floor(current_time / WINDOW) if counter[key].window != now_window: counter[key] = { window: now_window, count: 0 } counter[key].count += 1 return counter[key].count <= LIMIT ``` One counter per client per period, reset when the period rolls over. Cheap in memory and trivial to reason about. Its failure is at the seam. A client that spends its whole allowance at the end of one window and its whole allowance at the start of the next has sent twice the limit across a span shorter than a single window, entirely within the rules. Whether that matters depends on what the limit protects: for fairness it is a nuisance, for capacity it can be the exact event you were trying to prevent. ## Sliding window The fix for the seam, in two versions with very different costs. **The log version** keeps the timestamp of every request and counts those inside the trailing period. Exact, and it pays for that in storage proportional to the traffic it allows. **The counter version** keeps the current and previous window counts and weights the previous one by how much of it still lies inside the trailing period: ```text on request(key): w = floor(current_time / WINDOW) position = (current_time mod WINDOW) / WINDOW estimate = previous[key] * (1 - position) + current[key] if estimate < LIMIT: current[key] += 1 return allow return refuse ``` Approximate, and cheap enough to run at any scale. It assumes traffic was spread evenly inside the previous window, which is wrong in detail and close enough in aggregate for almost every purpose a limit serves. ## Token bucket The one that matches how ordinary clients behave. ```text on request(key): refill(key) # add REFILL_RATE * elapsed, cap at CAPACITY if bucket[key].tokens >= 1: bucket[key].tokens -= 1 return allow return refuse ``` Tokens accumulate at a steady rate up to a ceiling; each request spends one. A client that has been quiet has a full bucket and may send a burst; a client that has been busy is held to the refill rate. That is close to a description of a normal application: idle, then a flurry when somebody opens a page, then idle again, which is why this shape produces the fewest complaints from legitimate traffic. The subject is covered further under [bursts](/rate-limiting/burst/). It also gives you two dials with distinct meanings: the capacity is how big a burst you tolerate, and the refill rate is the sustained rate you are willing to serve. Being able to state those separately is most of the value. ## Leaky bucket The same picture from the other side: instead of controlling what is admitted, control what leaves. ```text on request(key): if queue[key].length >= CAPACITY: return refuse queue[key].append(request) # drained at a constant RATE on tick: for key in queue: release up to RATE * elapsed requests ``` Output is smoothed to a constant rate regardless of how arrivals bunch up. Where the queue is genuinely queued rather than dropped, the client experiences delay instead of refusal, which is gentler but hides the limit and can turn a burst into a growing wait nobody chose. ## Side by side | | Memory | Burst allowed | Seam problem | Client experiences | |---|---|---|---|---| | Fixed window | Lowest | Full allowance instantly | Yes, up to double at the boundary | Sudden refusal, then a clean slate | | Sliding log | Highest, grows with traffic | Full allowance instantly | No | Refusal that eases gradually | | Sliding counter | Low | Full allowance instantly | Largely removed | Same, approximated | | Token bucket | Low | Up to `CAPACITY` after idle | No | Burst tolerated, then steady | | Leaky bucket | Low, plus the queue | None, arrivals are smoothed | No | Delay rather than refusal | ## Choosing one Start from what you are protecting. If you are protecting capacity, something behind you that falls over at a certain rate, a leaky bucket or a token bucket with a modest capacity matches the problem, because both describe an outflow you can sustain. If you are protecting fairness, ensuring no single client can consume a shared resource, a sliding counter is usually the honest choice, since it prevents the boundary trick without pretending to more precision than it has. If you are protecting an interface used by ordinary applications, a token bucket almost always produces the fewest false alarms, because its shape matches the shape of legitimate traffic rather than fighting it. Whichever you pick, check it against traffic you already have rather than against an idea of traffic. Take a period from your own records, replay the arrival pattern of your busiest legitimate client against the algorithm on paper, and see whether it would have been refused. That exercise costs an afternoon and settles arguments that otherwise run until somebody's customer complains, and it usually reveals that the number was never the problem. ## What none of them fixes Three things the algorithm cannot decide for you. **Who is counted.** Every algorithm above counts against a key, and choosing that key is a separate decision with larger consequences, set out under [per-IP versus per-user](/rate-limiting/per-ip-vs-per-user/). **What a request costs.** All four treat requests as equal. Where a cheap read and an expensive search are counted the same, the limit is measuring the wrong thing whichever algorithm computes it. **What the client is told.** The algorithm decides the refusal; how it is communicated decides what the client does next, which is the subject of [429](/rate-limiting/429/). ## FAQ **Which algorithm should I use?** Token bucket for interfaces used by ordinary applications, since it tolerates the bursts real clients produce while holding the sustained rate. Sliding counter when fairness between clients matters most. Leaky bucket when you are protecting something downstream that needs a genuinely constant rate. **Why does the fixed window let clients exceed the limit?** Because its counter resets at a fixed moment. A client can spend its full allowance just before the reset and again just after, sending twice the limit across a span shorter than one window without breaking any rule the algorithm enforces. **Is the sliding counter accurate enough?** For almost every purpose, yes. It assumes the previous window's traffic was spread evenly, which is wrong in detail and close in aggregate, and it costs a fraction of what an exact log costs. Use the log only where exactness has a concrete consequence. **Does the algorithm choice matter more than the number?** They matter differently. The number sets how much a client may send; the algorithm sets what shape of sending is allowed. Ordinary clients are bursty, so a poorly chosen algorithm refuses them at a number that would otherwise have been generous. --- https://bridge-waf.com/rate-limiting/burst/ --- # Bursts and rate limits: why a flat limit breaks users Traffic does not arrive evenly. A person opening a page fetches many things at once, a client syncing sends a cluster and then goes quiet, and a legitimate integration wakes up on a schedule. A limit that assumes a smooth flow refuses all of them while the average stays well under it. ## Why even traffic does not exist The mental model behind most limits is a steady stream, and nothing produces one. Loading a single page produces a burst by design: the `HTML` document arrives, and then everything it references is requested almost at once. A visitor clicking through a site produces clusters separated by reading time. An integration polling on a schedule produces a spike at the same moment every period, and an unlucky number of integrations produce it at the same moment as each other. Averaged over an hour, all of these look modest. Measured in the second when they happen, all of them look like abuse to a limit that expects the average. ## The two numbers that describe a shape A useful limit needs both of them, and having only one of the two is where almost all of the trouble starts. **The sustained rate** is what a client may do over time: the average you are willing to serve indefinitely. **The allowance for a moment** is how much may arrive at once without being refused, provided the sustained rate is respected over the longer view. With both, a client can behave the way clients behave: a cluster now, quiet after. With only the first, every cluster is a violation. With only the second, a client that never stops bursting is never caught. The common implementation of this idea is an allowance that refills over time: you may spend a certain amount at once, and the ability to spend returns gradually. That is a mechanism rather than a recommendation, and choosing values for it is where knowledge of your own traffic replaces general advice. ## What goes wrong without it Three failures, and none of them looks like a rate limit from outside. **Pages break in parts.** The `HTML` arrives and some of its resources do not, because the burst crossed the line partway through. The visitor sees a half-rendered page rather than an error, which is reported as "the site is broken" and diagnosed as anything but a limit. **Retries make it worse.** A client refused mid-burst commonly retries, and the retry arrives while the allowance is still exhausted. What was a brief overshoot becomes a sustained one, produced entirely by the defence. **The wrong clients are caught.** Ordinary behaviour is bursty and automated abuse is often smooth, so a limit calibrated against bursts catches people and misses what it was aimed at. That inversion is the single strongest argument for shaping rather than flattening. A fourth failure is invisible: nobody reports it. Visitors who hit a limit meant for somebody else rarely write in. They conclude the site is unreliable and leave, so the cost arrives as absence rather than as a complaint anybody can investigate. ## Choosing the shape Three questions answer it, and none of them is about a number to start with. **What does one unit of ordinary use look like?** A page view, a sync, a form submission: count the requests it actually produces. That count is the floor for any allowance, because refusing below it means refusing the behaviour itself. **How long is the quiet between units?** The gap decides how fast an allowance can refill without ever letting sustained abuse through. **What is the expensive thing you are protecting?** Where cost varies sharply between endpoints, one shape for everything is either too tight for the cheap ones or too loose for the expensive one, which is the argument for treating them separately rather than raising the single limit. Once those are answered, values follow from your own traffic, and they need watching before they are enforced, which is the discipline described under [monitor mode](/operations/monitor-mode/) and [operations](/operations/). What subject the counting attaches to is a separate decision, covered under [choosing a subject](/rate-limiting/per-ip-vs-per-user/). ## Where the shape has to differ One case where a single shape cannot work, whatever the values. An interface serving both people and machines is serving two entirely different patterns. Browsers burst and go quiet; integrations arrive on a schedule and keep a steady pace. A shape suited to one is wrong for the other, and averaging the two produces something that fits neither: too tight for a page load, too loose for a client that never stops. Where both use the same paths, the honest options are to distinguish them by the subject the counting attaches to, or to treat the expensive paths separately from the ordinary ones. Both are decisions about structure rather than about numbers, and both are cheaper to make before enforcement than after somebody's integration stops working. ## What the platform provides Stated separately from the design advice, and narrowly. Rate limiting is applied per domain, which is the unit limits are counted against. Shaping described above is a way of thinking about limits generally rather than a description of controls, and where finer behaviour is needed it lives wherever your application knows about individual clients. ## FAQ **Why does my rate limit block normal users?** Because real traffic arrives in clusters and most limits assume a smooth flow. A page load, a sync, or a scheduled integration produces many requests in one moment while the hourly average stays low, and a limit calibrated on the average refuses exactly that pattern. **What is a burst allowance?** The amount that may arrive at once without refusal, separate from the rate sustained over time. Having both lets a client behave normally, bursting and then going quiet, while still preventing anybody from bursting continuously and calling it ordinary use. **Should I just raise the limit instead?** Raising a single number treats the symptom and weakens the limit at the same time. A higher flat limit still refuses a large enough burst, and it now permits more sustained load than before, which is the opposite of what you wanted from each of the two halves. **How do I pick the numbers?** From your own traffic rather than from an article, including this one. Count the requests that one ordinary unit of use produces, look at the gaps between those units, and then watch what a proposed limit would have refused before it is allowed to refuse anything at all. --- https://bridge-waf.com/rate-limiting/distributed/ --- # Distributed rate limits: why local counters overshoot A limit enforced in more than one place is not one limit. Each node counts only what it sees, so a client whose requests are spread across nodes receives the sum of their allowances rather than the number you configured. Correcting that is a trade between accuracy and the cost of every request, and no arrangement gives you both. ## What actually goes wrong Not simply that the limit is too generous, which would be easy to correct. With `N` nodes each holding a full counter, a client spread evenly across them can send `N` times the intended amount before anything refuses it. If that were the whole problem you could divide by `N` and move on. The difficulty is that the multiplier is not stable: it depends on how that particular client's requests happen to be distributed, which depends on routing, on connection reuse, on how many nodes are healthy at that moment, and on the client's own concurrency. So the effective limit differs per client and changes through the day. One client using a single long-lived connection is held to roughly the configured number. Another opening connections freely is held to some multiple of it. Neither is what you specified, and the gap between them is invisible in the configuration, which is why this is usually discovered from the outside. The same effect works in reverse when you overcorrect. Divide the allowance by the node count and a client that reaches one node is refused at a fraction of the limit you intended, which reads as an unexplainable refusal to everybody involved. ## Three arrangements Each is a defensible answer to a different constraint. **Local counters with a divided allowance.** Every node enforces the limit divided by the number of nodes. No coordination, no added latency, nothing to fail. It is correct only when traffic is spread evenly, which is what a distributed limit cannot assume: a client pinned to one node meets a fraction of the intended limit, and the divisor is wrong again the moment you scale up or lose a node. **A shared counter.** Every node consults one store before deciding. Accurate, and the accuracy costs a round trip on the path of every request, plus a new dependency: if the store is slow, everything is slow, and if it is unavailable, every node must decide what to do without it. This is the arrangement people reach for first and the one whose failure modes surprise them most. **Local counters with reconciliation.** Each node counts locally and periodically exchanges summaries, so every node knows approximately what the others have seen. Overshoot is bounded by how stale the summaries are rather than by the node count, and no request waits for coordination. Approximate by design, and for most limits the approximation is smaller than the uncertainty in the number you chose. ## The decision nobody writes down Before you deploy a shared counter, decide what happens when it cannot be reached. **Fail open** and the limit disappears at the moment your infrastructure is already unhealthy, which is frequently the moment it was protecting something that could not take the load. **Fail closed** and a hiccup in a store that has nothing to do with your visitors refuses all of them at once, turning a dependency's bad minute into your outage. Neither is right in general and both are right somewhere. What matters is that the choice is made deliberately and written down, because otherwise it is made by whatever the library does by default, discovered during an incident, and remembered as a surprise. Where you can, prefer a third option: fall back to local counting with a divided allowance while the store is unreachable, which degrades the accuracy rather than the service. ## Sticky routing is a partial answer If every request from a client reaches the same node, its local counter is correct for that client. That is a real solution for the common case and it does not survive the case you built the limit for. Sticky routing depends on a stable notion of who the client is, so it works well for identified clients and poorly for anything counted by address. It concentrates load unevenly, since one heavy client now belongs to one node. And an actor deliberately spreading traffic to evade a limit is precisely the traffic that will not stick. Treat it as an optimisation that reduces coordination for well-behaved clients, not as the mechanism that makes the limit correct. ## Clocks and window edges Nodes disagree about when a window starts, and it matters less than people fear. Small clock differences move only the boundary between periods, so their effect is confined to the seam, which the fixed window already handles badly and the sliding and bucket approaches largely remove. Choosing an algorithm whose behaviour does not hinge on an exact shared moment is a cheaper fix than tightening clock synchronisation, and the differences between those algorithms are set out under [rate limiting algorithms](/rate-limiting/algorithms/). What does deserve attention is any arrangement where a node's decision depends on a timestamp it received from another node. There, skew becomes an arithmetic error rather than a boundary effect, and whose clock is authoritative needs stating explicitly. ## What to measure The configured number is not the enforced number, so measure the enforced one. Take a client identity you control, send a known pattern of requests through your real entry point rather than at a single node, and count how many are accepted before the first refusal. That figure is your actual limit. Compare it with the one in your configuration, and if they differ, you now know the multiplier your architecture is applying rather than the one you assumed. Repeat it with a second pattern that opens many connections rather than reusing one, since that is the difference between the client that meets your limit and the client that meets several copies of it. Then confirm the refusal itself is well-formed, which is what [429](/rate-limiting/429/) covers, because a distributed limit that refuses correctly but says nothing useful produces retry storms across every node at once. ## FAQ **Why does my limit allow more than I configured?** Because each node counts only the requests it sees. A client spread across several nodes accumulates a separate allowance on each, so the enforced total is a multiple of the configured one, and the multiple depends on how that client's traffic happens to be routed. **Can I just divide the limit by the number of nodes?** Only if traffic is spread evenly, which is the assumption a distributed limit cannot make. A client that reaches one node is then refused at a fraction of the intended limit, and the divisor becomes wrong again whenever you add capacity or lose a node. **Is a shared counter worth the latency?** It depends on what the limit protects. For something genuinely fragile downstream, exactness is worth a round trip. For fairness between clients, a reconciled approximation is usually close enough and avoids putting a new dependency on the path of every request. **What should happen if the coordination store is unavailable?** Decide before you deploy rather than during an incident. Falling back to local counting with a divided allowance is often better than either extreme, since it degrades the accuracy of the limit instead of removing it entirely or refusing everybody. --- https://bridge-waf.com/rate-limiting/per-ip-vs-per-user/ --- # Rate limiting by IP, user or key: choosing a subject A limit has to count something against somebody, and choosing that somebody is a design decision rather than a detail. The subject you pick decides who gets inconvenienced when the limit fires, and every available choice is wrong for somebody, in a way that is better known in advance. ## The three candidates Each identifies a different thing, and none of them identifies a person. **The network address** is available for every request, including the first one, and requires nothing from the client. That makes it the only subject that works before anybody has identified themselves, which is why it is the default nearly everywhere. **The account** is available once somebody has signed in, and it identifies the party you care about. A limit counted against an account survives the visitor changing networks, which an address-based limit does not. **The key** is available for programmatic clients and identifies an integration rather than a person. It is the most precise of the three, and it exists only where you issued something to count against. The pattern is visible immediately: precision and availability run in opposite directions. The subject you always have tells you the least, and the subject that tells you the most is not there when you need it most. ## Why the address is wrong more often than people expect The failure here is not occasional. **Shared networks put many people behind one address.** An office, a university, a mobile carrier, a country-scale provider: all of them can present hundreds or thousands of unrelated visitors as one. A limit that would be generous for a person is restrictive for a building, and the people affected have no idea why, because nothing they did caused it. **One person can present many addresses.** Mobile clients change networks mid-session, and connections through pools of addresses can vary between requests. A limit counted against an address is then counting against something that keeps changing identity while the behaviour stays the same. **Addresses are shared over time as well as at a moment.** An address assigned to somebody abusive in the morning may belong to an ordinary visitor in the afternoon, so a decision that outlives its cause punishes whoever inherits it. This is the same property that makes reputation lists lag reality, covered under [IP reputation](/bots/ip-reputation/). There is also a cost you do not see. The visitors turned away by a limit aimed at somebody else rarely report it; they conclude the site is broken or slow and go elsewhere, so the damage arrives as absence rather than as a complaint you can investigate. None of that makes the address useless. It makes it a coarse subject that should be used with limits set for a crowd rather than for a person, and with the knowledge that it will occasionally be wrong about who it is counting. ## Choosing by what you are protecting The subject follows from the thing at risk, not from preference. **Protecting a public endpoint from volume.** The address is what you have, so it is what you use, with a threshold that assumes the address may be a crowd rather than an individual. **Protecting an account from abuse.** Count against the account. Somebody attacking one account from many addresses is invisible to an address-based limit and obvious to an account-based one. **Protecting an expensive operation from a legitimate integration.** Count against the key. The integration is not hostile; it is enthusiastic, and a limit here is a contract rather than a defence. **Protecting a scarce resource shared by everybody.** Where the thing being protected is capacity rather than a specific account, the honest subject is the total, and per-subject limits are a blunt proxy for it. **Protecting sign-in itself.** This is the case where the subject is least obvious, because there is no account yet in the sense that matters: the whole point of the attempt is to establish one. Counting against the address catches broad attempts and misses distributed ones; counting against the account name being tried catches the distributed ones and can be used to lock out a real owner deliberately. Doing both, with different thresholds, is the usual answer. ## What the platform provides here Stated separately from the design advice above, and narrowly. Rate limiting is applied per domain, which is the unit the limits are counted against. That is a coarser subject than anything on this page and should be understood as such: it bounds what a domain accepts in total rather than what any single visitor, account, or integration may do. Everything else above is guidance for designing limits, whatever enforces them. Where a finer subject is needed, it belongs wherever your application knows about accounts and keys, because that is where the identity exists. ## Before enforcing any of this One habit prevents most of the damage. Whatever subject you choose, watch what the limit would have done before it does it. The counting is the easy part; discovering that your chosen subject groups your largest customer into one bucket is the part that hurts, and it is visible in advance, as covered under [monitor mode](/operations/monitor-mode/) and [operations](/operations/). ## FAQ **Should I rate limit by IP or by user?** By whatever identifies the thing you are actually protecting. Addresses are always available and identify a network rather than a person; accounts identify the party you care about, but only after somebody has signed in. Most systems end up needing both, applied to different situations rather than layered on the same one. **Why is IP-based limiting unfair on shared networks?** Because an office, a campus, or a mobile carrier can present many unrelated people as a single address. A threshold that is sensible for one individual becomes restrictive for an entire building, and none of the people affected can tell why, since their own behaviour was completely ordinary. **Can attackers get around IP limits?** Distributed attacks make address-based limits much less effective, because each individual source stays comfortably under any per-address threshold. That is an argument for choosing subjects deliberately and for watching totals as well as individuals, rather than an argument against limits, which still stop the simpler cases outright. **What about limiting by session?** A session identifies a browser rather than a person or an account, and it can usually be discarded and replaced without effort by anybody who wants to. It is useful for shaping ordinary use, and it should never be the only subject protecting anything that actually matters. --- https://bridge-waf.com/rate-limiting/retry-after/ --- # Telling clients when to come back after a limit A refusal with no guidance attached is an invitation to try again immediately. A refusal that says when to return turns an unknown into an instruction, and the difference shows up directly as load you no longer receive during the period you were protecting. ## What a bare refusal produces Predictable behaviour follows, and none of it is helpful to either side. A client refused by an `HTTP` response that tells it nothing has two reasonable options: give up, or try again. Most of them try again, usually at once, because nothing in the response suggested that waiting would help. That retry arrives while the condition which caused the refusal is still true, is refused in its turn, and the whole cycle repeats itself. The result is that a limit intended to reduce load ends up producing additional load, made up entirely of retries that had no chance of succeeding. That is the same self-inflicted amplification described under [bursts](/rate-limiting/burst/), arriving from a different direction. Worse, those retries are indistinguishable from the abuse the limit existed to catch in the first place. A legitimate client hammering because nobody told it anything looks like a client hammering on purpose, and no amount of analysis separates them afterwards. ## What guidance changes One thing changes, and it only works on the clients that were already trying to behave properly. Told when to return, a well-built client waits and then comes back exactly once. Load during the refusal period drops to nothing from that client, and the request that eventually arrives succeeds, which is the outcome both sides were after all along. This is why the practice is worth adopting even though nothing about it can be enforced on anybody. It costs nothing at all to include, it changes the behaviour of every client whose author cared about behaving well, and it makes the traffic that remains considerably more informative: a client that keeps hammering after being told when to return has told you something about itself. That last point is the one people miss most often. Guidance is not only a courtesy to well-built clients; it is a filter that separates the merely careless from the genuinely indifferent. One more property: this is the rare defensive measure whose benefit grows with how well-behaved your traffic already is. On an interface used mostly by careful integrations, almost every refused client will honour the instruction, and the load reduction is close to total. On an interface under deliberate attack, it changes nothing. Knowing which of those describes you tells you how much to expect from it. ## Choosing what to say Three rules, and all of them are about honesty rather than about technique. **Say something you will honour.** If you name a moment and the limit is still in force when that moment arrives, the client is refused a second time and learns to distrust the guidance entirely, which leaves you worse off than saying nothing would have. **Do not name a moment that brings everybody back at once.** Telling a thousand refused clients to return at the same instant produces a synchronised burst precisely then, which is a queue you built yourself. Spreading return times, even slightly, avoids building a queue that discharges in one moment. **Prefer a short honest wait to a long safe one.** An overly cautious answer makes clients wait when they could have proceeded, and for interactive traffic that difference is felt directly by whoever happens to be sitting in front of the screen at the time. There is a second, quieter benefit. A refusal that carries an instruction is one somebody can act on without contacting you, so the volume of "my integration stopped working" conversations falls along with the retry traffic. That saving lands on people rather than on servers, and it is the one most likely to be noticed by whoever has to answer those messages. ## Where it does not help Three cases where it changes nothing, and the third is by far the most important of them. **Clients that do not read it.** Anything that ignores the `HTTP` response and retries on its own schedule is entirely unaffected. Guidance is advice, and advice reaches only the willing. **Deliberate abuse.** Traffic sent specifically to overwhelm you is not waiting for permission to continue, and it will not start waiting now. **A limit that is simply wrong.** If ordinary use is what keeps being refused, telling people when to come back fixes nothing whatsoever; it only makes the refusal politer. The correct action is to look at what is being refused and why, which is what watching before enforcing is for, described under [operations](/operations/). That third case needs a closer look, because guidance can conceal a mistake rather than reveal it. Refusals become tidy, retries become orderly, dashboards look calm, and everything appears managed while legitimate traffic is still quietly being turned away at the same rate as before. ## What the platform provides Stated separately from all of the design advice above, and narrowly. Rate limiting is applied per domain, which is the unit the limits are counted against. Everything above is guidance for designing limits, whatever enforces them, and the choice of what a refusal tells a client belongs wherever those responses are produced. ## FAQ **Why tell a client when to retry at all?** Because a refusal without guidance produces immediate retries, which add load during exactly the period you were trying to protect. Telling a well-built client when to return converts a cycle of attempts that cannot succeed into a single request later that does, which is what both sides wanted from the exchange. **Does it work if clients ignore it?** For those particular clients, no. It changes the behaviour of every client whose author cared about behaving properly, which covers most integrations and most browsers, and it leaves the remainder more visible, since ignoring clear guidance is itself a signal about what a client is. **Should the wait be generous to be safe?** No. An overly long wait makes clients pause when they could have proceeded, and interactive visitors feel that directly. A short honest interval that you will actually honour is better than a cautious one you chose to avoid thinking about it. **Does this replace fixing the limit?** No, and it can hide the need to. If legitimate use is being refused, polite refusals make the problem look managed while the traffic is still being turned away. Check what is actually being refused before improving how you refuse it. --- https://bridge-waf.com/rate-limiting/testing/ --- # Testing a rate limit before it refuses real traffic A limit you have not tested is a guess about your own traffic dressed as a control. Testing answers two questions before anybody is refused: what the limit actually stops, and what it does to the clients you want to keep. The first test costs nothing and finds most of the mistakes. ## Start on paper Before generating a single request, check the limit against traffic you already have. Take your busiest legitimate client from the record: a partner `API` integration, a mobile application, an internal job. Count how its requests actually arrive, not on average but in the shape they arrive in, and walk that pattern against the proposed limit by hand. Would it have been refused? If so, you have found the problem for the price of an afternoon and nobody noticed. Do this for at least three clients that differ in character: one that opens a connection and reuses it, one that fetches many things at once, and one that runs on a schedule and does all its work in a stretch. Those three cover most of the ways ordinary traffic fails to look average. The paper test is also the only one that can be run before the limit exists, which makes it the right place to discover that the number needs to be different rather than the algorithm. ## Record before you refuse The second-cheapest test is to count without enforcing. Where the limit can be evaluated and logged while every request is still served, do that first and read the result as a prediction: these are the clients that would have been refused, at these moments. It is the same discipline that makes filtering safe to turn on, and the same reason applies, which is that a prediction costs nothing while a refusal costs a customer. Read the outcome by client rather than in total. A prediction concentrated on one or two clients is a limit doing its job; a thin spread across many different clients means the number or the subject is wrong, and no amount of load testing will tell you that as clearly. ## Generating load, carefully Eventually you need to see the limit fire. Three constraints make that safe. **Test where it will not cost anything.** An environment that matches production in topology matters far more than one that matches it in size: the same number of layers, the same entry point, the same arrangement of nodes. A limit behaves differently across several nodes than on one, which is the subject of [distributed limits](/rate-limiting/distributed/), and a single-node test can give a confident answer to a question you did not ask. **Do not point load at anybody else.** Testing your own limit by hammering a third party's service, a payment provider, a search interface, or a partner's interface is somebody else's incident, and it is the sort of traffic that gets your identity treated as hostile long after the test is over. If the path you want to exercise crosses into somebody else's system, stop at the boundary or arrange it with them first. **Do not run the first real-traffic test at your busiest hour.** The purpose is to learn cheaply, and a peak makes every lesson expensive. Announce it, run it when the affected route is quiet, and have the rollback ready before you start rather than after something surprises you. ## What to measure Five things, and the first is the one people assume rather than check. **The effective limit.** How many requests are accepted before the first refusal, measured through the real entry point rather than at one node. In a distributed setup this frequently differs from the configured number, and the difference is the point of measuring. **The boundary behaviour.** What happens at the moment the window turns over or the bucket refills. Send traffic deliberately across that edge and see whether the result matches the algorithm you believe you are running. **The shape of the refusal.** That it is the right `HTTP` status, that it carries a value telling the client when to return, and that its body is readable if a person receives it. The details are on [429](/rate-limiting/429/), and a refusal that omits them produces the retry storm described below. **The recovery.** How long after being refused a client is served again. This is what a well-behaved client experiences as the cost of the limit, and it is rarely the number anybody expected. **The retry storm.** Refuse several clients at once and let them retry the way your real clients retry, which for most software means immediately. If your own limit sustains itself under that, you have found a defect in the refusal rather than in the client. ## The three checks people skip Each of these is discovered in production if it is not discovered here. **Two clients behind one address.** Where the limit counts by `IP` address, put two independent clients behind a single one and confirm what happens. This is the office, the campus, and the mobile network, and it is the most common cause of a limit refusing people who did nothing. **The exemption you rely on.** If your monitoring, deployment tooling, or an internal job is meant to be exempt, verify the exemption before you need it. An exemption that was never tested is a belief, and the moment it matters is the moment you find out. **The client you forgot.** Something of yours arrives at your own site on a schedule and is anonymous to the limit. Find it now rather than during the first incident it causes. ## Moving to enforcement Testing tells you the limit is right in the conditions you tested; enforcement tells you whether it is right in the conditions you have. Turn it on the way you would turn on anything else that can refuse a customer: one route, watched for a full cycle of that route, with a rollback trigger written down beforehand. That sequence, and how to choose the first slice, is set out under [staged rollout](/operations/staged-rollout/). ## FAQ **What is the cheapest useful test?** Walking your busiest legitimate client's real arrival pattern against the proposed limit by hand. It requires no traffic, no environment, and no risk, and it finds most limits that are set too low before anybody is refused by one. It also works before the limit exists, which no other test does. **Can I test a rate limit in production?** Carefully, on a quiet route, at a quiet hour, with a rollback ready and the change announced. Better still, evaluate the limit without enforcing it first, so the result is a prediction about which clients would have been refused rather than a list of the ones that were. **Why did my test pass and the limit still cause problems?** Usually because the test ran against one node while production spreads requests across several, or because it sent smooth traffic while real clients arrive in bursts. Both make the tested limit and the enforced limit different numbers, and neither difference is visible in the configuration you compared them against. **What should I test that is not the limit itself?** The refusal and the recovery. How a client is told to come back decides whether it retries sensibly or immediately, and how long it waits decides what the limit costs the people you meant to keep. Both are easier to fix before enforcement than to diagnose after it. --- https://bridge-waf.com/tools/ip-blacklist-check/ --- # IP blacklist check: is this address on a list? Each public blocklist says for itself whether it names an address, through a lookup its operator publishes. The answer is a fact rather than a judgement: a listing means some operator decided to add the address, on criteria that are theirs, at a time that may be long past. ## What a listing actually means Somebody put the address on a list, and that is all it means by itself. Lists differ in what they collect. Some record addresses seen sending unsolicited mail, some record networks that allow it, some record ranges assigned to hosting rather than to households, and some record what was observed years ago and never revisited. Being named by one says something narrow; being named by several says the same thing several times if they share a source. That is why the useful answer is which lists name an address, one by one, rather than a verdict. The lists disagree by design, and flattening them into a single answer would discard the only part that carries information. ## When the address is yours Two situations, and the useful first step differs. **Mail is being rejected.** Listings that affect mail delivery usually publish a removal procedure, and the procedure is the route. What matters more is finding out why the listing happened, because a removal without a cause fixed is a removal that repeats. **A service is refusing your traffic.** Here the listing may be incidental. Plenty of refusals come from reputation systems that never consulted a public list at all, and treating a listing you happen to have found as the cause can send you down a path that changes nothing. ## When the address is somebody else's This is the more common use, and the boundary is worth respecting. A listing tells you what a list says about an address, not what the address is doing to you now. A visitor from a listed address may be perfectly ordinary, and an unlisted address may be the one causing your problem: lists lag reality in both directions. What the result is useful for is adding context to a pattern you already observed, not for deciding on its own who gets in. That decision belongs with the material on [IP reputation](/bots/ip-reputation/), which is a different question with different inputs. ## FAQ **What does it mean if my IP is blacklisted?** That one or more list operators added it, on their own criteria and possibly some time ago. It does not by itself mean traffic will be refused: whether anything acts on a listing depends entirely on which systems consult that list and how much weight they give it. --- https://bridge-waf.com/vs/waf-vs-firewall/ --- # WAF vs firewall: two different questions entirely These two are compared constantly and are not alternatives at all. A network firewall decides whether traffic may reach a port; a web application firewall decides whether a request that already arrived should be served. One acts before a request exists, the other on the request itself. ## Side by side | | Network firewall | Web application firewall | |---|---|---| | Decides on | Addresses, ports, protocols | Method, path, headers, body, behaviour | | Sees a request | No, only the connection | Yes, in full | | Typical use | Keep traffic away from what should not be reachable | Refuse requests the application should never handle | | Blind to | What the traffic is asking for | Anything that never becomes a request | | Fails by | Allowing a port that carries abuse | Matching ordinary traffic that resembles an attack | The row that matters most is the fourth. Each is blind to what the other is built for, which is why "do I need both" is usually the wrong question and "which of these does my current problem live in" is the right one. Asked that way, most situations answer themselves in a sentence. ## What a network firewall does well It is the tool for reachability. A database that should never be reachable from outside, an administrative port exposed by a default configuration, an internal service that ended up with a public address: these are decided by address and port, and they are decided before anything about the content matters. In each case the right outcome is that the traffic never establishes a connection at all, which is a cleaner result than inspecting whatever it would have sent. A request filter placed in front of them would inspect requests that should never have arrived at all. It also fails cleanly, which is underrated. Traffic is either permitted to reach a port or it is not, and the rule that produced the outcome is findable afterwards. Compared to content matching, where a decision depends on what a pattern happened to match, the reasoning is simple enough to audit and to explain to somebody who was affected by it. The trade is that it cannot help once traffic is arriving somewhere it is supposed to arrive, which is most of what a public site consists of. ## What a request filter does well It is the tool for meaning. Once traffic is legitimately arriving at a service that should be reachable, every remaining question is about what is being asked rather than about who is allowed to ask. Injection attempts arrive on the port you deliberately opened. Abuse of an expensive endpoint arrives as ordinary well-formed requests. Automated traffic hammering a form uses exactly the interface you published on purpose. None of that is visible at the network level, because at that level all of it looks identical to the traffic you want: the same port, the same protocol, and often the same addresses as legitimate users. What separates it is the content and the pattern across several requests, and separating on those is precisely what a request filter exists to do. The types of attack this covers, and where the boundary sits, are set out under [attack layers](/attacks/layers/). ## Where both are blind Neither sees what the other is built for, and there is a third gap they share. Knowing the gaps is more useful than knowing the features, because a gap is where an expectation quietly fails rather than where a comparison table puts a mark. Neither one repairs an application. A missing authorisation check is not a network property and not a request property; it is a property of the code, and both categories can only make it harder to reach rather than absent. That distinction is the one to carry into any vendor conversation, because it is the one most often blurred, usually by describing filtering as protection rather than as distance. Volumetric traffic that saturates a link before arriving is also outside both: a firewall drops it after it has already consumed the capacity it was sent to consume, and a request filter never sees it at all. That belongs to a different layer entirely, covered under [attacks](/attacks/), and it matters because both categories are routinely credited with handling it. ## When to use which The verdict, stated as directly as the question deserves. Nothing below depends on which product you buy; it depends only on which of the two questions you currently have, and that is knowable before any purchase. **Use a network firewall when the question is reachability.** Something is listening that should not be, or something is reaching a port it has no business reaching. Nothing about request content is involved. **Use a request filter when the question is content.** The service should be reachable, is reachable, and is receiving requests you would rather it did not have to handle. Closing the port is not an option here, because closing it would remove the service along with the problem. **Use both when you have both questions,** which most sites eventually do. They are not layered versions of one another and do not overlap enough to substitute for each other: running one does not reduce what the other is for, and no configuration of either extends it into the other's territory. **Use neither as a substitute for fixing what is broken.** Both are ways of keeping traffic away from a problem rather than ways of removing it, and the discipline for introducing either without breaking legitimate users is under [operations](/operations/). That discipline matters more for the request filter, since its mistakes look like your site being broken rather than like a connection being refused. ## FAQ **Is a WAF a type of firewall?** Only by name. Both refuse traffic, but they decide on completely different information: one on addresses and ports before a request exists, the other on the content of a request that has already arrived. The shared word describes the action they take rather than the mechanism behind it, which is why the comparison confuses people so reliably. **Can a firewall stop SQL injection?** No, because it cannot see the request. An injection attempt arrives on a port you deliberately opened, in traffic that looks exactly like ordinary use at the network level, from an address with nothing remarkable about it. Only something inspecting the content of the request can tell the two apart. **Do I need a WAF if I have a firewall?** They answer different questions, so having one tells you nothing about whether you need the other. If requests reaching your application are the problem, a network firewall cannot help, because it never sees them. If services that should not be reachable are the problem, a request filter cannot help either, for the same reason in reverse. **Which one should I set up first?** Reachability first, as a rule. Closing what should never have been open is cheaper, easier to reason about, and removes an entire class of problem rather than filtering it. Content filtering, by contrast, needs a period of observation before enforcement so that it does not start refusing traffic you actually wanted.