<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Peakhour.IO - Rate Limiting</title><link href="https://www.peakhour.io/" rel="alternate"></link><link href="https://www.peakhour.io/feeds/tag/rate-limiting.atom.xml" rel="self"></link><id>https://www.peakhour.io/</id><updated>2026-06-19T00:00:00+10:00</updated><entry><title>An Operating Model for API and Account Protection</title><link href="https://www.peakhour.io/blog/api-account-protection-operating-model/" rel="alternate"></link><published>2026-06-19T00:00:00+10:00</published><updated>2026-06-19T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2026-06-19:/blog/api-account-protection-operating-model/</id><summary type="html">&lt;p&gt;API and account protection works best as an operating model: map routes, classify signals, choose proportionate actions, preserve evidence, and tune controls from monitor to enforce.&lt;/p&gt;</summary><content type="html">&lt;p&gt;API and account protection is often discussed as a stack of controls: authentication, MFA, bot detection, rate limiting, WAF rules, logging, fraud checks, and incident response. Those controls matter, but the missing piece is usually the operating model.&lt;/p&gt;
&lt;p&gt;Who owns the route? Which signals are trusted? What action should happen before origin? What evidence is preserved? When does a rule move from monitor to enforce? How does the team know whether it helped or hurt?&lt;/p&gt;
&lt;p&gt;Without those answers, account protection becomes a set of disconnected gates. The login page has one policy. The mobile API has another. Password reset is reviewed only after support tickets appear. Rate limits are tuned during incidents, then left in place because nobody wants to touch them.&lt;/p&gt;
&lt;p&gt;A better model is route first, signal second, action third, evidence always.&lt;/p&gt;
&lt;h2&gt;1. Map the Routes That Matter&lt;/h2&gt;
&lt;p&gt;Start with the account and API routes that change trust, money, access, or user state. Do not begin with every endpoint in the estate. Begin with the flows where abuse has a clear consequence.&lt;/p&gt;
&lt;p&gt;Typical routes include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Login and token issue.&lt;/li&gt;
&lt;li&gt;Token refresh.&lt;/li&gt;
&lt;li&gt;Password reset start and completion.&lt;/li&gt;
&lt;li&gt;MFA enrolment and recovery.&lt;/li&gt;
&lt;li&gt;New account registration.&lt;/li&gt;
&lt;li&gt;Email, phone, address, and password changes.&lt;/li&gt;
&lt;li&gt;Stored payment, wallet, loyalty, or checkout actions.&lt;/li&gt;
&lt;li&gt;High-volume read APIs.&lt;/li&gt;
&lt;li&gt;Partner or machine-to-machine API access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each route, record the owner, normal traffic shape, expected clients, authentication method, downstream cost, and likely abuse case. A login endpoint and a product search endpoint can both be APIs, but they should not have the same policy.&lt;/p&gt;
&lt;p&gt;This is where &lt;a href="/solutions/use-case/traffic-control/"&gt;traffic control&lt;/a&gt; becomes part of account security. The route tells the edge what kind of decision is being made: allow, challenge, throttle, block, route, cache, or log.&lt;/p&gt;
&lt;h2&gt;2. Classify the Signals Before Choosing the Action&lt;/h2&gt;
&lt;p&gt;A useful account decision combines several signal families:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identity and token state.&lt;/li&gt;
&lt;li&gt;Credential exposure or failed-login history.&lt;/li&gt;
&lt;li&gt;Residential proxy, VPN, hosting, mobile, or office network context.&lt;/li&gt;
&lt;li&gt;IP reputation and ASN behaviour.&lt;/li&gt;
&lt;li&gt;Client, browser, TLS, or HTTP fingerprint.&lt;/li&gt;
&lt;li&gt;Request rate and response codes.&lt;/li&gt;
&lt;li&gt;Route sequence and session behaviour.&lt;/li&gt;
&lt;li&gt;Account event context, such as reset, recovery, or profile change.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The mistake is treating any one signal as the whole answer. A residential proxy signal on a low-risk route may only need monitoring. The same signal on a password reset route, with repeated failures and a first-seen client, should be handled differently.&lt;/p&gt;
&lt;p&gt;This is the job of &lt;a href="/solutions/use-case/contextual-security/"&gt;contextual security&lt;/a&gt;: apply friction where the request context justifies it, while keeping trusted users on the shortest path.&lt;/p&gt;
&lt;h2&gt;3. Choose Actions That Match Route Risk&lt;/h2&gt;
&lt;p&gt;Not every suspicious request should be blocked. Blocking is one action, and it should be available, but account protection needs a wider set of responses.&lt;/p&gt;
&lt;p&gt;Common actions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allow and record.&lt;/li&gt;
&lt;li&gt;Log only.&lt;/li&gt;
&lt;li&gt;Add to a rate-limit zone.&lt;/li&gt;
&lt;li&gt;Throttle or return a 429.&lt;/li&gt;
&lt;li&gt;Require a challenge.&lt;/li&gt;
&lt;li&gt;Require step-up authentication.&lt;/li&gt;
&lt;li&gt;Deny the request.&lt;/li&gt;
&lt;li&gt;Route to a safer path.&lt;/li&gt;
&lt;li&gt;Alert security or support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="/products/advanced-rate-limiting/"&gt;Advanced rate limiting&lt;/a&gt; is useful here because the counter does not have to be the source IP. For API traffic, a policy may key on an Authorization header, token, fingerprint, route, cookie, response code, or a combination of fields. For account flows, response-aware limits can count failed logins or suspicious reset attempts, then apply a stricter rule on the next request.&lt;/p&gt;
&lt;p&gt;This matters for distributed abuse. If attackers rotate through residential proxies, a simple IP counter sees fragments. A route-aware, signal-aware policy can still recognise the behaviour that matters.&lt;/p&gt;
&lt;h2&gt;4. Preserve Evidence While the Control Runs&lt;/h2&gt;
&lt;p&gt;A security decision that cannot be explained will be difficult to tune and harder to defend internally. Teams need to know why a request was allowed, challenged, throttled, or blocked.&lt;/p&gt;
&lt;p&gt;The evidence should keep the request, route, signal, policy, action, and outcome together. That includes useful fields such as the matched route, rate-limit zone, proxy or IP classification, fingerprint, response code, decision reason, and timestamp.&lt;/p&gt;
&lt;p&gt;&lt;a href="/products/log-forwarding/"&gt;Log forwarding&lt;/a&gt; is part of the operating model, not an afterthought. If the evidence only exists in a dashboard screenshot or a short-lived edge event, support, fraud, platform, and security teams will end up reconstructing incidents by hand. Forwarded logs should carry enough context into the SIEM, object store, or observability pipeline for investigation and tuning.&lt;/p&gt;
&lt;p&gt;This also protects the rollout. When a control is in monitor mode, evidence shows who would have been affected. When it is enforced, evidence shows who was affected and why.&lt;/p&gt;
&lt;h2&gt;5. Tune From Monitor to Enforce&lt;/h2&gt;
&lt;p&gt;The safest way to deploy account and API controls is usually staged:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Monitor the route and collect baseline evidence.&lt;/li&gt;
&lt;li&gt;Add low-friction actions, such as logging or soft thresholds.&lt;/li&gt;
&lt;li&gt;Review false positives, support impact, and route ownership.&lt;/li&gt;
&lt;li&gt;Enforce on the clearest abuse patterns.&lt;/li&gt;
&lt;li&gt;Expand enforcement only where evidence supports it.&lt;/li&gt;
&lt;li&gt;Keep rollback and emergency tightening paths documented.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This avoids two common failures. The first is leaving controls in monitor mode forever because nobody owns the decision to enforce. The second is enforcing too broadly and creating customer friction that causes the business to bypass the control.&lt;/p&gt;
&lt;p&gt;A staged model gives security, platform, product, and support teams a shared language. The rule is not "on" or "off". It has a route, a risk case, an action, evidence, and a review cycle.&lt;/p&gt;
&lt;h2&gt;6. Fit the Model to the Edge You Already Run&lt;/h2&gt;
&lt;p&gt;Some teams want Peakhour as the active application edge. Others need to keep Cloudflare, Fastly, CloudFront, another CDN, or an existing hosting edge in place. That deployment choice should not change the operating principle.&lt;/p&gt;
&lt;p&gt;The goal is still to classify request context before origin, apply the right action, and preserve evidence. &lt;a href="/solutions/bring-your-own-edge/"&gt;Bring Your Own Edge&lt;/a&gt; matters because many organisations cannot redesign delivery just to improve account protection. They need a control path that fits the architecture they already operate.&lt;/p&gt;
&lt;p&gt;The practical test is straightforward: can the team explain what happened to a sensitive account or API request without guessing?&lt;/p&gt;
&lt;p&gt;If the answer is no, the next step is not another generic control. It is an operating model: map the route, classify the signals, choose the action, preserve the evidence, and tune the policy from observed behaviour.&lt;/p&gt;
&lt;p&gt;That is how API and account protection becomes something the organisation can run, not just something it bought.&lt;/p&gt;</content><category term="API Security"></category><category term="API Security"></category><category term="Account Protection"></category><category term="Log Forwarding"></category><category term="Rate Limiting"></category><category term="Contextual Security"></category><category term="Traffic Control"></category></entry><entry><title>API Bot Abuse Does Not Stay in One Endpoint</title><link href="https://www.peakhour.io/blog/api-bot-abuse-login-checkout-account-journeys/" rel="alternate"></link><published>2026-06-19T00:00:00+10:00</published><updated>2026-06-19T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2026-06-19:/blog/api-bot-abuse-login-checkout-account-journeys/</id><summary type="html">&lt;p&gt;API bot abuse moves across login, checkout, and account journeys. Defenders need route-aware bot, rate, and account controls that follow the campaign rather than treating each endpoint as a separate incident.&lt;/p&gt;</summary><content type="html">&lt;p&gt;API bot abuse rarely stays politely inside one endpoint.&lt;/p&gt;
&lt;p&gt;A campaign may start at login, move through token refresh, test account recovery, check saved addresses, probe checkout, abuse coupons, scrape product availability, and then return to account actions once a working session is found. Looking at each route alone makes the activity seem smaller than it is.&lt;/p&gt;
&lt;p&gt;The pattern matters more than the individual request.&lt;/p&gt;
&lt;p&gt;That is why &lt;a href="/solutions/use-case/api-bot-protection/"&gt;API bot protection&lt;/a&gt; has to follow journeys, not just endpoints.&lt;/p&gt;
&lt;h2&gt;Login Is the First Measurement Point&lt;/h2&gt;
&lt;p&gt;Login endpoints are the obvious place to look for bot abuse. Credential stuffing, password spraying, brute force attempts, and token abuse all show up there.&lt;/p&gt;
&lt;p&gt;But the login endpoint is only the first measurement point. Attackers are not trying to create a failed-login graph. They are trying to find usable accounts and move to the next action.&lt;/p&gt;
&lt;p&gt;A bot campaign may keep failed attempts low per IP address. It may rotate through residential proxies. It may slow down to avoid simple thresholds. It may mimic the browser request shape closely enough to get past a basic check. It may use an API route that exists for the mobile app rather than the public login form.&lt;/p&gt;
&lt;p&gt;So the useful question is not just "how many login attempts did we see?" It is "which client, route, network, fingerprint, account, and response pattern suggests automation?"&lt;/p&gt;
&lt;p&gt;That is where &lt;a href="/products/bot-management/"&gt;bot management&lt;/a&gt; belongs in the account journey. It should not be an isolated "human or bot" label. It should become part of the request evidence used for login, recovery, checkout, and account-change decisions.&lt;/p&gt;
&lt;h2&gt;Checkout Abuse Is Often API Abuse&lt;/h2&gt;
&lt;p&gt;Checkout abuse is not always a stolen-card problem. It can be a request-path problem.&lt;/p&gt;
&lt;p&gt;Bots can test coupon codes, reserve inventory, create carts, check delivery combinations, retry payment flows, and exploit business logic at machine speed. Some of this happens through visible browser journeys. Much of it happens through APIs used by the front end or mobile app.&lt;/p&gt;
&lt;p&gt;The damage is not always dramatic in a single request. A few extra cart creations may look normal. A small number of coupon checks may be expected. A payment retry can be legitimate. The problem is the campaign shape across routes.&lt;/p&gt;
&lt;p&gt;If the same automation profile moves through login, cart, promo, shipping, and payment APIs with abnormal timing or sequencing, the response should not depend on one endpoint crossing a crude global limit.&lt;/p&gt;
&lt;p&gt;It should be route-aware.&lt;/p&gt;
&lt;p&gt;A checkout API can tolerate different behaviour from a catalogue API. A payment route deserves different thresholds from a product search route. A coupon route may need controls around account age, session state, rate, and client evidence. A cart route may be harmless in one context and abusive in another.&lt;/p&gt;
&lt;h2&gt;Account Journeys Need Sensitive-Action Controls&lt;/h2&gt;
&lt;p&gt;Account abuse becomes most damaging when a session moves into sensitive actions.&lt;/p&gt;
&lt;p&gt;Changing an email address, resetting a password, adding a new delivery address, viewing stored payment details, redeeming loyalty value, or placing an order are different from normal browsing. They deserve stronger context.&lt;/p&gt;
&lt;p&gt;The request may be technically valid. The token may pass validation. The password may be correct. The API schema may be satisfied. That does not mean the action is safe.&lt;/p&gt;
&lt;p&gt;A strong control model looks at the full path into that action. Did the session begin with credential stuffing signals? Is the client first seen? Did the network change? Is there proxy or fingerprint drift? Has the account recently failed login attempts? Is the request cadence consistent with a human journey? Is the action unusually soon after authentication?&lt;/p&gt;
&lt;p&gt;These are not abstract "zero trust" slogans. They are practical checks on the account request path.&lt;/p&gt;
&lt;h2&gt;Rate Limits Need Better Keys&lt;/h2&gt;
&lt;p&gt;API abuse prevention often starts with rate limiting, but IP-only limits struggle with distributed automation and shared networks. The hard part is deciding what to count.&lt;/p&gt;
&lt;p&gt;For API bot abuse, useful rate keys can include route, method, account, token, API key, response code, ASN, country, TLS or HTTP fingerprint, verified bot state, and combinations of headers. The right key depends on the journey.&lt;/p&gt;
&lt;p&gt;A login endpoint might count failed attempts by account and fingerprint. A token endpoint might count refresh patterns by client and session. A checkout route might count attempts by account, payment state, and client fingerprint. A partner API might count by API key and route.&lt;/p&gt;
&lt;p&gt;&lt;a href="/products/advanced-rate-limiting/"&gt;Advanced rate limiting&lt;/a&gt; is valuable because it can model the abusive actor more precisely than a single IP address. It also gives teams response options short of blanket blocking: log, challenge, throttle, or deny depending on the route and risk.&lt;/p&gt;
&lt;p&gt;That matters because real API traffic includes customers, mobile apps, partners, service clients, good bots, bad bots, and increasingly AI-driven agents.&lt;/p&gt;
&lt;h2&gt;Agents Will Make the Journey Problem Harder&lt;/h2&gt;
&lt;p&gt;The next wave of automated API use will not all look like simple scripts. As discussed in &lt;a href="/blog/agentic-ai-vs-your-api/"&gt;Agentic AI vs. Your API&lt;/a&gt;, reasoning agents can explore, adapt, and change their behaviour based on responses.&lt;/p&gt;
&lt;p&gt;That does not mean every AI agent is malicious. It does mean endpoint-by-endpoint rules will age quickly.&lt;/p&gt;
&lt;p&gt;A reasoning agent can try one path, observe the result, and adjust. It can move from documentation to browser-backed APIs to mobile-shaped requests. It can test which routes are protected, which errors reveal state, and which actions trigger stronger checks.&lt;/p&gt;
&lt;p&gt;Defence needs the same journey view. The campaign should be visible as it moves, even when the exact request pattern changes.&lt;/p&gt;
&lt;h2&gt;Keep Evidence Attached to the Campaign&lt;/h2&gt;
&lt;p&gt;API bot abuse is easier to manage when the evidence stays attached.&lt;/p&gt;
&lt;p&gt;The useful record is not just "blocked by rule 42". It is the route, account state, token or key context, fingerprint, proxy signal, rate key, response pattern, action taken, and protected business step. That evidence lets teams tune controls without guessing and investigate incidents without reconstructing the whole path from raw logs.&lt;/p&gt;
&lt;p&gt;For broader background, &lt;a href="/learning/api-protection/what-is-api-abuse-prevention/"&gt;API abuse prevention&lt;/a&gt; covers the categories. The operational point is narrower: login, checkout, and account APIs should not be defended as separate islands.&lt;/p&gt;
&lt;p&gt;Attackers use the journey.&lt;/p&gt;
&lt;p&gt;The defence should too.&lt;/p&gt;</content><category term="API Security"></category><category term="API Bot Protection"></category><category term="Bot Management"></category><category term="Account Protection"></category><category term="Rate Limiting"></category><category term="API Security"></category><category term="Threat Detection"></category></entry><entry><title>API Protection and Account Protection Are One Request-Path Problem</title><link href="https://www.peakhour.io/blog/api-protection-account-protection-request-path/" rel="alternate"></link><published>2026-06-19T00:00:00+10:00</published><updated>2026-06-19T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2026-06-19:/blog/api-protection-account-protection-request-path/</id><summary type="html">&lt;p&gt;Account protection does not stop at the login form. The same request path carries API, bot, rate, token, and account-risk evidence, and that is where the decision needs to happen.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Account protection is often discussed as if it belongs to the login page. That made sense when most account abuse looked like someone submitting a username and password into a web form.&lt;/p&gt;
&lt;p&gt;That is not how modern account journeys work.&lt;/p&gt;
&lt;p&gt;A customer signs in through a browser, a mobile app, a partner integration, a password reset flow, a token refresh endpoint, a profile update request, a checkout API, and sometimes a service-to-service call that exists nowhere in the visible front end. The account is not protected by one screen. It is protected, or exposed, by the whole request path.&lt;/p&gt;
&lt;p&gt;That is why &lt;a href="/products/api-security/"&gt;API security&lt;/a&gt; and account protection should not be treated as separate operating problems. The API route, the identity context, the client evidence, the rate pattern, the token behaviour, the bot signal, and the account action all arrive together. Splitting those signals across disconnected tools makes the final decision weaker.&lt;/p&gt;
&lt;h2&gt;The Login Is Only the Start&lt;/h2&gt;
&lt;p&gt;Credential stuffing is the obvious example. Attackers test leaked credentials against login endpoints, but the useful outcome is rarely the login itself. The value comes after the session opens.&lt;/p&gt;
&lt;p&gt;They try to change the email address. They add a shipping address. They reset a password. They check stored cards. They redeem loyalty value. They place an order. They call account APIs that were built for the real customer journey and then abuse them in a different sequence.&lt;/p&gt;
&lt;p&gt;If the login defence is separate from the API defence, the organisation may see only fragments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A spike in failed logins in one dashboard.&lt;/li&gt;
&lt;li&gt;A suspicious token refresh pattern somewhere else.&lt;/li&gt;
&lt;li&gt;A burst of profile-change requests in application logs.&lt;/li&gt;
&lt;li&gt;A fraud case after checkout.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of those is useful. None is the full story.&lt;/p&gt;
&lt;p&gt;The better model is to keep the decision close to the request. A request to &lt;code&gt;/login&lt;/code&gt; is different from a request to &lt;code&gt;/account/email&lt;/code&gt;, &lt;code&gt;/checkout/payment&lt;/code&gt;, or &lt;code&gt;/api/token/refresh&lt;/code&gt;. The route matters. So does the method, the session state, the previous failures, the network, the client evidence, and the account action being attempted.&lt;/p&gt;
&lt;h2&gt;APIs Carry Account Risk&lt;/h2&gt;
&lt;p&gt;APIs are not just developer plumbing. They are where many account journeys now happen.&lt;/p&gt;
&lt;p&gt;Mobile apps use APIs for login, registration, password reset, saved addresses, payment methods, and checkout. Single-page applications call APIs behind browser journeys. Partner systems may call account or order APIs directly. Internal services may use API keys or service credentials that function like non-human accounts.&lt;/p&gt;
&lt;p&gt;That creates a practical issue: account protection must cover both human and non-human identity paths.&lt;/p&gt;
&lt;p&gt;OAuth, JWTs, API keys, refresh tokens, and service credentials all need lifecycle control, least-privilege access, rotation, validation, and monitoring. But those controls are still not enough if the protected API cannot see whether the request is behaving like abuse.&lt;/p&gt;
&lt;p&gt;A valid token can be stolen. A valid API key can be overused. A real session can be driven by automation. A known customer can suddenly perform a high-risk action from a first-seen client through proxy infrastructure.&lt;/p&gt;
&lt;p&gt;The request has to be judged in context.&lt;/p&gt;
&lt;h2&gt;Rate Limiting Has to Follow Business Logic&lt;/h2&gt;
&lt;p&gt;Basic rate limiting often starts with an IP address. That is an understandable first step, but it is not enough for account protection. Attackers rotate through proxy networks. Legitimate users may share a carrier or office IP. Some attacks are low and slow enough that no single IP looks exceptional.&lt;/p&gt;
&lt;p&gt;For account journeys, rate limiting needs to be tied to the thing being protected.&lt;/p&gt;
&lt;p&gt;Login attempts can be counted differently from password resets. Token refreshes can be counted differently from product searches. A failed authentication response can be treated differently from a normal read request. A route hit by a first-seen client can be treated differently from one used by a known browser session.&lt;/p&gt;
&lt;p&gt;That is the point of &lt;a href="/solutions/api-protection/"&gt;API protection&lt;/a&gt; as an operating layer, not just an API inventory exercise. The route, schema, authentication state, bot signal, and rate key should be available to the same decision. Otherwise teams end up writing compensating rules in several systems and hoping the gaps line up.&lt;/p&gt;
&lt;h2&gt;The Edge Decision Needs Options&lt;/h2&gt;
&lt;p&gt;Not every suspicious request should be blocked. Some should be logged. Some should be rate limited. Some should be challenged. Some should be allowed because the business impact of a false positive is worse than the risk presented by that specific request.&lt;/p&gt;
&lt;p&gt;Account protection is strongest when the action matches the journey.&lt;/p&gt;
&lt;p&gt;A login request with weak risk signals might be allowed but watched. A password reset request with stronger signals might require step-up. A checkout attempt from a newly compromised session might be blocked or reviewed. A partner API key exceeding expected usage might be throttled without affecting normal customers.&lt;/p&gt;
&lt;p&gt;Peakhour's position here is simple: API, bot, WAF, rate, and account controls work better when they share request evidence. That can run on Peakhour Edge, or it can sit beside the CDN and cloud edge already in place through &lt;a href="/solutions/bring-your-own-edge/"&gt;bring your own edge&lt;/a&gt;. The important part is not the label on the component. It is whether the request path has enough context to make the right decision.&lt;/p&gt;
&lt;h2&gt;Account Protection Is a Journey Control&lt;/h2&gt;
&lt;p&gt;A useful account protection programme should be able to answer operational questions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which routes are involved in account takeover attempts?&lt;/li&gt;
&lt;li&gt;Which sessions moved from suspicious login behaviour into account changes?&lt;/li&gt;
&lt;li&gt;Which tokens or API keys are behaving outside their expected pattern?&lt;/li&gt;
&lt;li&gt;Which controls created friction, and where?&lt;/li&gt;
&lt;li&gt;Which blocked requests actually protected account, checkout, or recovery actions?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those questions cannot be answered from a login form alone. They require API visibility, account-event context, rate data, bot signals, and reviewable evidence.&lt;/p&gt;
&lt;p&gt;That is the thesis of this series: API protection and account protection are one request-path problem. The account is compromised through a sequence of requests. The defence needs to see that sequence early enough to act.&lt;/p&gt;
&lt;p&gt;For teams already working on &lt;a href="/solutions/use-case/prevent-account-takeovers/"&gt;account takeover prevention&lt;/a&gt;, the next step is not simply adding another login prompt. It is connecting the account journey to the API routes that now carry it.&lt;/p&gt;</content><category term="API Security"></category><category term="API Security"></category><category term="Account Protection"></category><category term="Bot Management"></category><category term="Rate Limiting"></category><category term="Threat Detection"></category><category term="Fraud Prevention"></category></entry><entry><title>How Residential Proxies Changed API and Account Abuse</title><link href="https://www.peakhour.io/blog/residential-proxies-api-account-abuse/" rel="alternate"></link><published>2026-06-19T00:00:00+10:00</published><updated>2026-06-19T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2026-06-19:/blog/residential-proxies-api-account-abuse/</id><summary type="html">&lt;p&gt;Residential proxies have changed account abuse from obvious bursts into distributed, low-noise workflows across login, account, and API routes. Treat proxy use as a risk signal, not a blunt block rule.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Residential proxies have changed the shape of API and account abuse. The old picture was easier to reason about: too many failed logins from one IP, a known hosting provider range, an obvious bot user agent, or a burst that crossed a threshold quickly enough to trip a rule.&lt;/p&gt;
&lt;p&gt;That still happens, but it is not the harder problem.&lt;/p&gt;
&lt;p&gt;The harder problem is the attempt that arrives through ordinary consumer networks, spreads itself across many addresses, and behaves just slowly enough to avoid looking like an incident. One login attempt here. A password reset probe there. A token refresh pattern that is unusual only when it is seen beside the route, the client, the ASN, the credential history, and the account event.&lt;/p&gt;
&lt;p&gt;That is why &lt;a href="/products/residential-proxy-detection/"&gt;residential proxy detection&lt;/a&gt; should be treated as part of the account and API decision path, not as a standalone allow/block list.&lt;/p&gt;
&lt;h2&gt;The Account Workflow Is Now a Distributed Target&lt;/h2&gt;
&lt;p&gt;Attackers do not need to break the whole application at once. They can work through the account surface in pieces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Login attempts against known usernames.&lt;/li&gt;
&lt;li&gt;Password reset initiation and verification.&lt;/li&gt;
&lt;li&gt;New account registration.&lt;/li&gt;
&lt;li&gt;Token issue and refresh routes.&lt;/li&gt;
&lt;li&gt;Payment, address, profile, and email changes.&lt;/li&gt;
&lt;li&gt;Loyalty, wallet, checkout, or stored-value workflows.&lt;/li&gt;
&lt;li&gt;API calls that reveal whether an account or credential is valid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each route may look acceptable in isolation. The risk appears when the pattern is joined together.&lt;/p&gt;
&lt;p&gt;A residential proxy network helps the attacker keep that pattern quiet. Requests rotate through many residential-looking exits. IP-based rate limits see different sources. A reputation feed may not have labelled a fresh or private proxy network yet. Geo checks can look plausible enough. The traffic does not necessarily arrive as a clean burst.&lt;/p&gt;
&lt;p&gt;This is where static thinking breaks down. If the only question is "is this IP bad?", the answer will often arrive too late or be too blunt to use safely.&lt;/p&gt;
&lt;h2&gt;Fresh and Private Proxy Networks Create a Timing Problem&lt;/h2&gt;
&lt;p&gt;Many teams think about proxy detection as a database problem: look up the IP, see whether it is a proxy, then block it. That works for some traffic, especially known data centre proxies and commodity infrastructure.&lt;/p&gt;
&lt;p&gt;Residential proxy abuse is less tidy. Fresh networks can appear before public datasets have a confident label. Private networks may not show up in broad feeds at all. Some exit points are shared with legitimate users. Some sit behind carrier-grade NAT or normal household connections. Blocking the address outright can create customer pain, while allowing it without context leaves the account flow exposed.&lt;/p&gt;
&lt;p&gt;This is the practical reason Peakhour talks about residential proxy use as a signal. The signal matters, but it has to sit beside &lt;a href="/products/ip-intelligence/"&gt;IP intelligence&lt;/a&gt;, connection characteristics, client history, request behaviour, account state, and route sensitivity.&lt;/p&gt;
&lt;p&gt;A residential proxy on a marketing page may only need logging. The same proxy signal on a login route with recent failures may justify a challenge. On a password reset or high-value account change, it may justify step-up authentication, throttling, or blocking depending on the rest of the evidence.&lt;/p&gt;
&lt;p&gt;The control should match the risk of the action.&lt;/p&gt;
&lt;h2&gt;Low-and-Slow Behaviour Is Still Automation&lt;/h2&gt;
&lt;p&gt;Low-and-slow abuse is uncomfortable because it avoids the easy operational story. There is no dramatic spike. There may be no single IP worth banning. The application may not be overloaded. Support may only see a few confused users, a few locked accounts, or a gradual rise in reset attempts.&lt;/p&gt;
&lt;p&gt;For API and account workflows, this is still automation. It just looks less like a flood and more like a background process.&lt;/p&gt;
&lt;p&gt;Useful signals include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repeated failed authentication across a shared fingerprint or client pattern.&lt;/li&gt;
&lt;li&gt;Many accounts touched by similar request timing.&lt;/li&gt;
&lt;li&gt;Token or reset routes used out of sequence.&lt;/li&gt;
&lt;li&gt;Browser characteristics that do not match the claimed client.&lt;/li&gt;
&lt;li&gt;Residential proxy use on sensitive account routes.&lt;/li&gt;
&lt;li&gt;Fresh IP or ASN patterns appearing around account events.&lt;/li&gt;
&lt;li&gt;Similar request shapes distributed across unrelated accounts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these signals has to prove abuse by itself. The point is to combine them early enough that the application does not have to make the decision alone.&lt;/p&gt;
&lt;p&gt;Peakhour's view is that proxy detection belongs in the same operating model as bot management, rate limiting, account risk scoring, and event evidence. The useful question is not "can we block every residential proxy?" It is "what should this route do when proxy use appears with this account, this client, this credential pattern, and this recent behaviour?"&lt;/p&gt;
&lt;h2&gt;API Routes Need the Same Treatment as Browser Flows&lt;/h2&gt;
&lt;p&gt;A common gap is protecting the visible login page while leaving API routes with weaker controls. Browser-side checks can help on web flows, but many account actions now happen through mobile apps, single-page applications, partner integrations, and backend APIs.&lt;/p&gt;
&lt;p&gt;Those routes still need context. They need request-level validation, route-aware thresholds, proxy and IP signals, token checks, and evidence that can be reviewed later. A login API, a reset API, and a profile-change API should not all receive the same action just because the source address has the same reputation.&lt;/p&gt;
&lt;p&gt;This is also why rate limiting has to move beyond source IP. A rule can key on a token, header, fingerprint, account identifier, route, response code, or a combination of signals. That makes it possible to slow failed login behaviour without punishing every legitimate user behind the same network.&lt;/p&gt;
&lt;p&gt;The background reading on &lt;a href="/blog/proxy-detection-challenges-existing-solutions/"&gt;proxy detection challenges&lt;/a&gt; and &lt;a href="/blog/residential-proxy-detection-quantifying-hidden-threat/"&gt;quantifying residential proxy risk&lt;/a&gt; covers the broader detection problem. For API and account teams, the immediate step is more operational: find the routes where a residential proxy signal should change the action.&lt;/p&gt;
&lt;h2&gt;The Right Outcome Is Controlled Friction&lt;/h2&gt;
&lt;p&gt;Residential proxy detection is not a magic verdict. It is a way to make the account decision more honest.&lt;/p&gt;
&lt;p&gt;Some traffic should pass. Some should be logged. Some should be rate limited. Some should be challenged. Some should be blocked. The difference should come from route sensitivity, request context, and observed behaviour, not from a single IP label.&lt;/p&gt;
&lt;p&gt;A practical policy might look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitor proxy use across all account and API routes.&lt;/li&gt;
&lt;li&gt;Apply tighter thresholds on login, reset, token, and account-change routes.&lt;/li&gt;
&lt;li&gt;Combine proxy use with credential, client, rate, and behaviour signals.&lt;/li&gt;
&lt;li&gt;Preserve decision records so security and support can explain what happened.&lt;/li&gt;
&lt;li&gt;Move from monitor to enforce only after reviewing false positives and customer impact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That model gives teams a way to respond to residential proxy abuse without turning every shared residential network into a casualty.&lt;/p&gt;
&lt;p&gt;For a grounding definition, see &lt;a href="/learning/threat-detection/what-is-residential-proxy-detection/"&gt;What is Residential Proxy Detection?&lt;/a&gt;. For the product control, see &lt;a href="/products/residential-proxy-detection/"&gt;Residential Proxy Detection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The important shift is simple: residential proxies are not just a network category. In account and API protection, they are context for deciding how much trust a request deserves.&lt;/p&gt;</content><category term="API Security"></category><category term="API Security"></category><category term="Account Protection"></category><category term="Residential Proxies"></category><category term="Bot Management"></category><category term="Rate Limiting"></category><category term="Threat Detection"></category></entry><entry><title>Beyond the IP Address</title><link href="https://www.peakhour.io/blog/beyond-the-ip-address-advanced-rate-limiting/" rel="alternate"></link><published>2025-09-01T00:00:00+10:00</published><updated>2025-09-01T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2025-09-01:/blog/beyond-the-ip-address-advanced-rate-limiting/</id><summary type="html">&lt;p&gt;Discover why traditional IP-based rate limiting is obsolete and how advanced techniques provide robust protection against modern distributed attacks.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For years, &lt;a href="/learning/api-protection/what-is-api-rate-limiting/"&gt;rate limiting&lt;/a&gt; has been a standard control for protecting websites and APIs from abuse. The basic model is simple: limit the number of requests a single "user" can make in a given period. If a user exceeds the limit (e.g., 10 login attempts in a minute), they are temporarily blocked.&lt;/p&gt;
&lt;p&gt;The hard part has always been identifying that "user". Traditionally, the answer was the IP address. The assumption was that one IP address equaled one user. In the early days of the internet, this was a reasonable approximation. Today, that assumption no longer holds, and it leaves systems exposed to modern attacks.&lt;/p&gt;
&lt;p&gt;The IP address is no longer a reliable identifier for a single user or device. There are three common reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proxy Networks&lt;/strong&gt;: Attackers don't use a single IP address. They use large residential proxy networks to rotate requests through thousands or even millions of different IP addresses, making each request look like it comes from a new user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared IPs (CGNAT)&lt;/strong&gt;: At the same time, a single IP address can represent thousands of legitimate users. Mobile carriers use Carrier-Grade NAT (CGNAT) to make many mobile devices share the same public IP. Similarly, an entire office building or university campus might appear to the internet as a single IP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed Attacks&lt;/strong&gt;: Modern automated attacks, like Layer 7 DDoS or credential stuffing, are inherently distributed. Attackers use botnets or proxy networks to spread their attack across a large number of IPs, so no single IP ever exceeds a traditional rate limit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Blocking a shared IP because of one bad actor can cause collateral damage, denying access to thousands of legitimate users. On the other side, failing to see that thousands of IPs are part of a single coordinated attack means the attack succeeds. Traditional IP-based rate limiting is no longer enough.&lt;/p&gt;
&lt;h2&gt;The New Way: Advanced Rate Limiting&lt;/h2&gt;
&lt;p&gt;Advanced Rate Limiting addresses this by moving beyond the IP address. Instead of grouping requests by a single, unreliable identifier, it lets you count requests using more stable and meaningful characteristics of the connection or the software making it.&lt;/p&gt;
&lt;p&gt;This approach groups requests using identifiers like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TLS/HTTP2 Fingerprints&lt;/strong&gt;: Every client application (like a browser or a script) has a unique "fingerprint" based on how it initiates a secure connection (&lt;a href="/blog/tls-fingerprinting/"&gt;TLS&lt;/a&gt;) or communicates over HTTP/2. This fingerprint remains consistent even as an attacker rotates through thousands of IP addresses. By rate limiting based on the TLS fingerprint, you can track and block the underlying automation tool itself, not just the IPs it uses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device Characteristics&lt;/strong&gt;: A fingerprint can be constructed from a range of attributes, including the device's operating system, browser version, and more. This allows for the detection of repeated requests coming from the same class of device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A Combination of Headers&lt;/strong&gt;: For authenticated APIs, you can group requests by an Authorization header or API key, enforcing fair usage and preventing abuse by a single authenticated client.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Practical Use Cases&lt;/h2&gt;
&lt;p&gt;The value of advanced rate limiting is clearest when it is applied to real-world threats:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mitigating Distributed Credential Stuffing&lt;/strong&gt;: An attacker using a tool like &lt;a href="/blog/the-rise-of-openbullet/"&gt;OpenBullet&lt;/a&gt; launches a credential stuffing attack against your login page, rotating through thousands of residential proxy IPs. Traditional rate limiting is ineffective here. However, the OpenBullet software has a consistent TLS fingerprint. By setting a rule to limit failed login attempts per TLS fingerprint, you can detect and block the entire distributed attack, regardless of how many IPs are involved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Protecting APIs from Abuse&lt;/strong&gt;: A partner is abusing their API key, sending far too many requests and degrading service for other users. By rate limiting based on the &lt;code&gt;Authorization&lt;/code&gt; header, you can enforce usage limits on a per-client basis, keeping access fair without affecting other users.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stopping Content Scrapers&lt;/strong&gt;: A scraper is hammering your e-commerce site to steal pricing data. They are using a botnet to distribute the requests across hundreds of IPs. However, the scraping script has a unique combination of a user-agent and a TLS fingerprint. Advanced rate limiting can count requests based on this combined signature and block the scraper, protecting your intellectual property.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When attackers are distributed, your defences need to see the single actor behind the many IPs. Advanced rate limiting provides that visibility and should be part of a modern application security strategy.&lt;/p&gt;</content><category term="Rate Limiting"></category><category term="Rate Limiting"></category><category term="DDoS"></category><category term="API Security"></category><category term="Residential Proxies"></category><category term="Bot Management"></category><category term="Account Protection"></category></entry><entry><title>The Bot Spectrum</title><link href="https://www.peakhour.io/blog/the-bot-spectrum-good-bad-grey-bots/" rel="alternate"></link><published>2025-09-01T00:00:00+10:00</published><updated>2025-09-01T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2025-09-01:/blog/the-bot-spectrum-good-bad-grey-bots/</id><summary type="html">&lt;p&gt;Learn to classify bots into good, bad, and grey categories and apply the right management strategy for each.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The word "bot" is often used as shorthand for unwanted automation: scripts trying to break into accounts, scrape content, or overwhelm websites. A large share of internet traffic does come from &lt;a href="/learning/bots/bot-management/"&gt;bad bots&lt;/a&gt;, but automated traffic is not automatically harmful. Some bots are part of how the web is discovered, monitored, and kept usable.&lt;/p&gt;
&lt;p&gt;Effective &lt;a href="/blog/key-considerations-effective-bot-management/"&gt;bot management&lt;/a&gt; is not about blocking every automated request. It depends on accurate classification: separating good bots from bad bots, and recognising the "grey" bots that sit between them. That classification lets you apply controls that reduce risk without cutting off traffic that helps your site operate.&lt;/p&gt;
&lt;h2&gt;Good Bots: The Essential Workers of the Web&lt;/h2&gt;
&lt;p&gt;Good bots are automated programs that perform useful or necessary tasks. They are usually clear about who they are and respect the rules you set in your &lt;code&gt;robots.txt&lt;/code&gt; file. Blocking them can damage search visibility, monitoring, or other business workflows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Good Bots:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Search Engine Crawlers&lt;/strong&gt;: Bots like Googlebot and Bingbot are the best-known good bots. They crawl and index your website's content, which is how your pages appear in search engine results. Blocking them would make your site invisible on Google.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance Monitoring Bots&lt;/strong&gt;: These bots are used by services to check your website's uptime and performance from different locations around the world, and to alert you if your site goes down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copyright Bots&lt;/strong&gt;: These bots scan the web for plagiarised content, helping to protect your intellectual property.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Management Strategy&lt;/strong&gt;: Good bots should be identified and &lt;strong&gt;allowed&lt;/strong&gt; to access your site freely. Verification techniques, such as reverse DNS lookups, can be used to confirm that a bot claiming to be Googlebot is actually coming from Google.&lt;/p&gt;
&lt;h2&gt;Bad Bots: The Malicious Actors&lt;/h2&gt;
&lt;p&gt;Bad bots are designed for malicious activity. They are a major reason bot management exists as a security function. These bots are deceptive, often hiding their identity and purpose, and they can be responsible for a wide range of costly and damaging activity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Bad Bots:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Credential Stuffers&lt;/strong&gt;: These bots use stolen usernames and passwords to carry out account takeover attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content and Price Scrapers&lt;/strong&gt;: These bots steal your valuable content, product listings, and pricing data, often for use by competitors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spam Bots&lt;/strong&gt;: These bots flood comment sections, forums, and contact forms with unwanted ads or malicious links.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Denial of Service (DDoS) Bots&lt;/strong&gt;: These bots are part of a botnet used to overwhelm a website with traffic, causing it to slow down or crash.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inventory Hoarding Bots&lt;/strong&gt;: Common in e-commerce, these bots automatically add limited-edition products to shopping carts to prevent legitimate customers from buying them, often for resale at a higher price (scalping).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Management Strategy&lt;/strong&gt;: Bad bots need to be accurately identified and &lt;strong&gt;blocked&lt;/strong&gt; as quickly as possible, ideally at the network edge before they consume your server resources.&lt;/p&gt;
&lt;h2&gt;Grey Bots: The Nuanced Category&lt;/h2&gt;
&lt;p&gt;Grey bots are not inherently malicious, but their behaviour can still cause problems. They often serve a legitimate purpose, but become an issue when they crawl too aggressively, consume excessive bandwidth or server resources, and slow the site down for real users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Grey Bots:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aggressive SEO Tools&lt;/strong&gt;: Bots from marketing tools like Ahrefs, SEMrush, and Majestic crawl websites to gather data for backlink analysis and competitive research. They can be useful, but their crawling can also be heavy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partner and Aggregator Bots&lt;/strong&gt;: These could be bots from partner companies or price comparison websites that need to access your data. The activity may be legitimate, but it still needs to be managed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feed Fetchers&lt;/strong&gt;: Bots that collect data for news aggregators or other applications fall into this category.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Management Strategy&lt;/strong&gt;: Grey bots require more than a simple allow or block rule. The best strategy is often to &lt;strong&gt;rate-limit&lt;/strong&gt; or &lt;strong&gt;tarpit&lt;/strong&gt; them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rate-Limiting&lt;/strong&gt;: This allows the bot to continue accessing your site, but slows it to a manageable level so it does not overwhelm your servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tarpitting&lt;/strong&gt;: This intentionally slows the connection for a specific bot, increasing the cost and time required to crawl your site and discouraging overly aggressive behaviour.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By classifying incoming bot traffic and applying the right control for each category, organisations can block threats, manage resource consumption, and allow the useful automation the modern web depends on.&lt;/p&gt;</content><category term="Bots"></category><category term="Bot Management"></category><category term="API Security"></category><category term="Threat Detection"></category><category term="DDoS"></category><category term="Residential Proxies"></category><category term="Rate Limiting"></category></entry><entry><title>Rate Limiting for API Security</title><link href="https://www.peakhour.io/blog/introducing-advanced-rate-limiting/" rel="alternate"></link><published>2024-01-24T13:00:00+11:00</published><updated>2024-01-24T13:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2024-01-24:/blog/introducing-advanced-rate-limiting/</id><summary type="html">&lt;p&gt;How advanced rate limiting protects modern applications and APIs from sophisticated threats including proxy networks, distributed attacks, and automated abuse in enterprise security environments.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/rate-limiting/"&gt;Rate limiting&lt;/a&gt; prevents servers from being overwhelmed by too many requests in a short period of time. Typically,
rate limiting is configured using rules made up of a filter, for example a path like /login, and a limit on the number
of requests a user can make in a given time, such as 10 requests in a minute. If a user exceeds this limit, they are usually
blocked for a timeout period.&lt;/p&gt;
&lt;p&gt;But how do you identify a user? Traditionally rate limiting has used the IP address for grouping requests, assuming
that requests from the same IP address will be the same user. That assumption is now weak. IP addresses are rarely static
and are often shared. For example, an office network might have hundreds of individual computers in it but present a single
IP address for all those computers to the internet. Mobile operators commonly use carrier-grade network address translation
(CGNAT) to share the same IP across
thousands of devices or users. Bot networks, seeking to avoid security controls like rate limiting, will rotate
their requests through thousands of different IP addresses. This makes rate limiting based on IP addresses a poor choice
from both a functional and a security perspective.&lt;/p&gt;
&lt;h2&gt;Introducing Advanced Rate Limiting&lt;/h2&gt;
&lt;p&gt;Peakhour's &lt;a href="/products/advanced-rate-limiting/"&gt;Advanced Rate Limiting&lt;/a&gt; service lets you create
filters using any HTTP request characteristic, for example URI, request method, headers, cookies, country,
network fingerprints and more. You can also use response headers and response codes, so a rule can count
failed login attempts, repeated 404s from a scraper, or traffic that crosses an API threshold.&lt;/p&gt;
&lt;p&gt;For counting requests you can use the following fields for grouping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP Address&lt;/li&gt;
&lt;li&gt;ASN&lt;/li&gt;
&lt;li&gt;Country Code&lt;/li&gt;
&lt;li&gt;HTTP/2 Fingerprint&lt;/li&gt;
&lt;li&gt;TLS Fingerprint&lt;/li&gt;
&lt;li&gt;Any combination of Request Headers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use one of those fields, or a combination of them, to identify users with more control than IP address alone.&lt;/p&gt;
&lt;p&gt;You can also separate the filter and mitigation expression. For example excessive attempts to /login can be blocked on
the entire site.&lt;/p&gt;
&lt;p&gt;This matters because rate limiting is not just a request counter. In Peakhour it sits beside bot management, WAF,
DDoS protection, traffic controls, and origin shielding on the same managed edge path. That gives operators a practical
way to set different thresholds for verified crawlers, suspicious automation, authenticated API clients, and normal
visitors without pushing every policy change into the application. It also gives them allowed, blocked, and
threshold-hit evidence to tune the rule after it is deployed, whether Peakhour is the active edge or adding controls
beside an existing CDN or cloud edge.&lt;/p&gt;
&lt;h2&gt;Putting it into action&lt;/h2&gt;
&lt;p&gt;Advanced Rate Limiting can help protect applications from attacks like
&lt;a href="/products/ddos-protection/"&gt;Layer 7 DDoS&lt;/a&gt;,
Account Takeovers, Credential Stuffing, and more. Here are some real
world examples you can configure using our dashboard
and API.&lt;/p&gt;
&lt;h3&gt;Protect against general site abuse&lt;/h3&gt;
&lt;p&gt;Our example website is a medium-sized ecommerce store that has page URLs ending in /. It serves Australian clients and typically
sees around 100 page requests a minute from non-search-engine traffic during peak traffic times. With that baseline,
we can set up rate limiting to prevent general site abuse and protect against
layer 7 DDoS attacks.&lt;/p&gt;
&lt;p&gt;Peakhour rate limiting starts with zones. You specify your request limits in these zones.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/advanced-rate-limit-zone.jpg" alt="rate limit zone"/&gt;
&lt;/div&gt;

&lt;p&gt;Here we've specified a maximum of 45 requests in 1 minute. We're going to apply this limit to page loads only. Since our
typical maximum for all users on this website is 100 in a minute,
it seems reasonable that a real user is not going to view 40 pages in 1 minute. We could also specify a value for error
responses in a minute. An error could be a 404, which a scraper might typically get when looking for removed URLs.&lt;/p&gt;
&lt;p&gt;Now let's define our filter and our counter. For our filter we mentioned that pages end in /, so we'll use that, but
exclude verified bots to make sure they're not restricted when crawling the site. A verified bot is a crawler like
Google or Bing, that Peakhour has verified as legitimate by using reverse DNS to confirm
they are who they say they are.&lt;/p&gt;
&lt;p&gt;Attackers, scrapers, and others looking to abuse a site will launch an attack using a particular piece of software. That piece of
software will have a &lt;a href="/blog/tls-fingerprinting/"&gt;TLS fingerprint&lt;/a&gt;
(like JA3) that remains the same, even as the attacker rotates
their user-agent, IP address, and other characteristics, so we'll use the TLS fingerprint as our request counter.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/advanced-rate-limiting-rule.jpg" alt="rate limit rule"/&gt;
&lt;/div&gt;

&lt;h3&gt;Rate Limit authenticated API Users&lt;/h3&gt;
&lt;p&gt;It is common for APIs to require an Authorization header as part of the request to authenticate access. By grouping
requests on the value of this header, we can rate limit a specific API client even if it uses multiple applications,
or if its credentials are stolen.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/advanced-rate-limiting-header.jpg" alt="rate limit rule"/&gt;
&lt;/div&gt;

&lt;h3&gt;Protecting from Account Takeovers&lt;/h3&gt;
&lt;p&gt;Account Takeover attacks have been in the news recently, with several high-profile
websites being victims. Credential Stuffing and
Brute Force attacks rely on attempting lots of logins to identify valid credentials.
Along with lots of attempts come lots of failures. Attackers will rely on software like &lt;a href="/blog/the-rise-of-openbullet/"&gt;openbullet&lt;/a&gt;
to carry out their attacks, using proxy networks to constantly rotate IP addresses and defeat traditional rate limiting.&lt;/p&gt;
&lt;p&gt;The program the attacker is using will present a consistent TLS fingerprint. We can make a special
rule for our login form that tracks failed login attempts by TLS Fingerprint, effectively tracking the attacker as
they rotate IP address.&lt;/p&gt;
&lt;p&gt;If the attack is low and slow, we can track failed attempts over a longer timeframe by using the response
from the server when adding to our counting zone.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/rate-limit-failed-logins.jpg" alt="failed logins rate limit rule"/&gt;
&lt;/div&gt;

&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Advanced rate limiting is a practical response to the limits of IP-based controls. IP address rotation is the standard
amongst attackers and scrapers, rendering the traditional approach obsolete. Useful protection now needs to identify
the actor behind the requests, protect the origin before expensive application work is triggered, and give teams enough
evidence to adjust the policy without guesswork. Counting requests against a combination of network fingerprints,
request fields, response signals, and bot context is how you stop abuse from scrapers, SEO spiders, and layer 7
attackers without treating every visitor the same.&lt;/p&gt;</content><category term="Application Security"></category><category term="Rate Limiting"></category><category term="API Security"></category><category term="DDoS"></category><category term="Residential Proxies"></category><category term="Bot Management"></category><category term="Threat Detection"></category></entry><entry><title>RFC 9460</title><link href="https://www.peakhour.io/blog/rfc-9460-dns-evolution/" rel="alternate"></link><published>2023-11-16T00:00:00+11:00</published><updated>2023-11-16T00:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-11-16:/blog/rfc-9460-dns-evolution/</id><summary type="html">&lt;p&gt;Introducing SVCB and HTTPS records in DNS and their impact on web connectivity.&lt;/p&gt;</summary><content type="html">&lt;p&gt;RFC 9460 introduces two DNS record types: "SVCB" (Service Binding) and "HTTPS". They let browsers learn more connection details during DNS lookup, before redirects and TLS negotiation add extra steps. The result is cleaner connection setup, with practical improvements in speed, security, and efficiency.&lt;/p&gt;
&lt;h2&gt;Understanding the Current Process&lt;/h2&gt;
&lt;p&gt;Traditionally, when a browser connects to a website, it follows a sequence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browser requests site via HTTP.&lt;/li&gt;
&lt;li&gt;Server redirects request to HTTPS.&lt;/li&gt;
&lt;li&gt;Browser receives ALPN (Application-Layer Protocol Negotiation) during the HTTPS handshake.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The model is secure, but it is not optimal. It involves multiple round trips, which affects Time to First Byte (TTFB) and the overall user experience. Load balancing and failover are also less direct than they could be. RFC 9460 changes this by allowing DNS to provide the necessary connection details earlier. That reduces the steps involved in establishing a secure connection, lowering TTFB.&lt;/p&gt;
&lt;h2&gt;The Impact of SVCB and HTTPS Records&lt;/h2&gt;
&lt;p&gt;SVCB and HTTPS records move useful connection hints into DNS. They speed up the time-to-first-packet by incorporating the Alt-Svc HTTP header and ALPN TLS extension into DNS, which shortens connection setup. These records also enable redirection at the zone apex, a task not possible with CNAMEs. They simplify DNS load distribution and failover, making web services more resilient. They also remove the need for HSTS preloading and support Encrypted Client Hello (ECH), formerly ESNI, for better privacy.&lt;/p&gt;
&lt;h2&gt;Adoption and Industry Response&lt;/h2&gt;
&lt;p&gt;Adoption started before the RFC was finalised. Firefox has been conducting HTTPS lookups since May 2020, limited to DNS over HTTPS (DoH). Apple's iOS, Safari, and macOS have followed suit since September 2020. Chrome introduced partial support in December 2020 and has recently enabled ECH by default. Various DNS service providers have also started supporting HTTPS and SVCB records.&lt;/p&gt;
&lt;p&gt;As reported on &lt;a href="https://netmeister.org/blog/https-rrs.html"&gt;Netmeister&lt;/a&gt;, adoption is still early but not insignificant. As of October 2023, about 10 million domains have implemented an HTTPS record for their 'www' service names, roughly 4.4% of domains. Around 9.1 million domains, or about 4.0%, use the record on their bare second-level domain name. Among the top 1 million domains, approximately 22.5K (25.5%) use HTTPS records for 'www' service names, and nearly 24K (25.6%) use them on bare domains.&lt;/p&gt;
&lt;p&gt;&lt;img alt="October 2023 Usage" src="/static/images/blog/https-records-oct-2023.png"&gt;&lt;/p&gt;
&lt;h2&gt;What the Records Look Like&lt;/h2&gt;
&lt;p&gt;A typical &lt;a href="/learning/service-binding-record/"&gt;SVCB record&lt;/a&gt; might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;_example.com. 7200 IN SVCB 1 svc4.example.net. (alpn=&amp;quot;h2,h3&amp;quot; port=&amp;quot;8004&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This record indicates that the service at &lt;code&gt;_example.com&lt;/code&gt; can be accessed at &lt;code&gt;svc4.example.net&lt;/code&gt; using either HTTP/2 or HTTP/3 on port 8004.&lt;/p&gt;
&lt;p&gt;An &lt;a href="/learning/https-record/"&gt;HTTPS record&lt;/a&gt; could be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;example.com. 3600 IN HTTPS 0 svc.example.net.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This record suggests that &lt;code&gt;example.com&lt;/code&gt; should be accessed securely through &lt;code&gt;svc.example.net&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Apex Domains and the Importance of SVCB/HTTPS Records&lt;/h2&gt;
&lt;p&gt;One long-running DNS limitation is the inability to use CNAME records at the apex (root level) of a domain due to conflicts with other necessary records like NS and SOA. RFC 9460's SVCB/HTTPS records address this by enabling apex domain aliasing without those conflicts. This matters for efficient content delivery networks (CDNs) and load balancing strategies.&lt;/p&gt;
&lt;h2&gt;These records enhance capability&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Load Balancing:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Consider a website that needs to distribute traffic across multiple servers. SVCB records can indicate different server endpoints with varying priorities.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;example.com. IN SVCB 10 server1.example.com. (alpn=&amp;quot;h2,h3&amp;quot;)
example.com. IN SVCB 20 server2.example.com. (alpn=&amp;quot;h2&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, &lt;code&gt;server1.example.com&lt;/code&gt; is the preferred endpoint (lower priority number), offering both HTTP/2 and HTTP/3 protocols. If it's unavailable, traffic automatically shifts to &lt;code&gt;server2.example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Failover Mechanism:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a service that requires high availability, SVCB records can express failover directly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;critical-service.example.com. IN SVCB 1 primary-service.example.com. (alpn=&amp;quot;h2,h3&amp;quot;)
critical-service.example.com. IN SVCB 2 backup-service.example.com. (alpn=&amp;quot;h2&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;primary-service.example.com&lt;/code&gt; is the primary endpoint. If it fails, the system automatically falls back to &lt;code&gt;backup-service.example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Apex Domain Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A practical advantage of SVCB/HTTPS records is their ability to handle apex domains, where CNAME records are not feasible. This is important for root domain aliasing to different service providers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;example.com. IN HTTPS 0 cdn-provider.example.net.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This record indicates that the apex domain &lt;code&gt;example.com&lt;/code&gt; is to be served through &lt;code&gt;cdn-provider.example.net&lt;/code&gt;, overcoming traditional DNS limitations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Encrypted ClientHello Support:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Future enhancements of SVCB could include keys for Encrypted ClientHello, which improves privacy and security during the initial TLS handshake.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;secure.example.com. IN SVCB 1 tls-service.example.net. (ech=&amp;quot;base64-encoded-key&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This record can be used to initiate a TLS connection with &lt;code&gt;tls-service.example.net&lt;/code&gt; using the provided Encrypted ClientHello key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Directing Traffic to Specific Protocols:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For services that need to direct clients to newer or more efficient protocols, SVCB records can specify the exact protocols to use.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;api.example.com. IN SVCB 1 api-server.example.com. (alpn=&amp;quot;h3&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Clients that understand HTTP/3 can connect directly using this protocol, bypassing the usual HTTP/1.1 or HTTP/2 protocols.&lt;/p&gt;
&lt;h2&gt;The Long Wait&lt;/h2&gt;
&lt;p&gt;HTTPS has been around for a while, so RFC 9460 raises an obvious question: why did this take so long? Apex records have had their share of problems, including not being able to use CNAMEs and having to resort to custom records like ALIAS or Cloudflare's 'cname flattening'.&lt;/p&gt;
&lt;p&gt;It is a fair question. We've had some bizarre records hanging around for ages along with a wide range of solutions to the "CNAME at the zone apex"
problem.&lt;/p&gt;
&lt;p&gt;Credit to the creators of RFC 9460 for getting this through and obtaining browser support:
   - B. Schwartz from Meta Platforms, Inc.
   - M. Bishop from Akamai Technologies
   - E. Nygren from Akamai Technologies&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;RFC 9460 gives DNS a more useful role in HTTPS connection setup. SVCB and HTTPS records let operators publish endpoint, protocol, failover, and privacy information before the browser starts negotiating the connection. That gives service providers more precise control over how clients reach web services, with practical benefits for performance, reliability, and security.&lt;/p&gt;</content><category term="Interest"></category><category term="HTTP"></category><category term="Web Performance"></category><category term="Rate Limiting"></category><category term="TLS Fingerprinting"></category><category term="CDN"></category><category term="DDoS"></category></entry><entry><title>HTTP/2 Rapid Reset Attack Deepdive</title><link href="https://www.peakhour.io/blog/http-rapid-reset-attack-deepdive/" rel="alternate"></link><published>2023-10-12T00:00:00+11:00</published><updated>2023-10-12T00:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-10-12:/blog/http-rapid-reset-attack-deepdive/</id><summary type="html">&lt;p&gt;The technicalities of the HTTP/2 Rapid Reset vulnerability and steps to fortify against DDoS threats.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Distributed &lt;a href="/products/ddos-protection/"&gt;Denial of Service&lt;/a&gt; (DDoS) attack vectors keep changing. The recent spike in HTTP/2-based DDoS
attacks has been notable for its volume, with some attacks surpassing 398 million requests per second. Peakhour observed
these attacks and worked through how to understand and mitigate them. This article explains how they work and what
operators can do to reduce exposure.&lt;/p&gt;
&lt;h2&gt;The Rise of HTTP/2 in DDoS Attacks&lt;/h2&gt;
&lt;p&gt;HTTP/2 was designed to make web traffic more efficient. The same features that improve performance for legitimate users
can also be abused in DDoS traffic.&lt;/p&gt;
&lt;p&gt;Much of HTTP/2's efficiency lies in "stream multiplexing." It allows multiple messages to be sent over a single TCP
connection. While HTTP/1.1 processes each request serially, HTTP/2 can manage multiple concurrent streams on a single
connection. This means a client can send multiple requests in a single round trip, increasing how much work each
connection can drive.&lt;/p&gt;
&lt;h2&gt;The 'Rapid Reset' Attack Explained&lt;/h2&gt;
&lt;p&gt;The "Rapid Reset" attack is a specific DDoS technique built around HTTP/2. The attacker starts by opening
multiple streams, much like in a standard HTTP/2 attack. However, instead of waiting for responses, they cancel each
request immediately.&lt;/p&gt;
&lt;p&gt;The client does this by sending a RST_STREAM frame, indicating that a previous stream should be cancelled. The rapid
request-and-reset sequence means the server spends resources processing the request, only for it to be cancelled before a
response is generated. This tactic amplifies the server's workload without the attacker needing to wait for responses,
which increases the pressure each connection can place on the server.&lt;/p&gt;
&lt;h2&gt;Variants of the Rapid Reset Attack&lt;/h2&gt;
&lt;p&gt;Attackers also used variations of the Rapid &lt;a href="/blog/http-rapid-reset-attack/"&gt;Reset attack&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;One variant involves delaying the reset action. The attacker opens multiple streams, waits, then cancels the streams
  and instantly opens new ones. This method can evade some rate-based defences.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another variant avoids stream cancellations. Instead, the attacker tries to open more streams than the server allows.
  This aims to keep the server continually busy, processing a near-constant flow of requests.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Effective Mitigation Techniques&lt;/h2&gt;
&lt;p&gt;Mitigation is not as simple as blocking individual malicious requests. A more effective approach is to close the entire
TCP connection when malicious activity is detected. The HTTP/2 protocol supports connection termination through the
GOAWAY frame. This feature needs to be used aggressively to prevent &lt;a href="/blog/http-rapid-reset-attack/"&gt;Rapid Reset&lt;/a&gt; attacks, rather than
relying on the more passive, standard implementation.&lt;/p&gt;
&lt;p&gt;Deciding which connections to treat as malicious is a challenge. One potential strategy is to monitor connection
statistics. If a connection exceeds a set threshold of cancelled requests, it might be deemed malicious. Responses to
suspect activity could range from sending a GOAWAY frame to terminating the TCP connection.&lt;/p&gt;
&lt;p&gt;For the non-cancelling variant, the best approach is to shut down connections that breach the concurrent stream limit,
either immediately or after a few violations.&lt;/p&gt;
&lt;h2&gt;Broader Protocol Implications&lt;/h2&gt;
&lt;p&gt;These attack techniques are specific to HTTP/2, but the wider protocol lesson still matters. The HTTP/3 (QUIC) protocol
isn't directly vulnerable in the same way. As a precaution, server implementations should consider limiting the work done
by a single connection.&lt;/p&gt;
&lt;h2&gt;The Importance of Industry Collaboration&lt;/h2&gt;
&lt;p&gt;When the threat of the Rapid Reset attack became apparent, the industry collaborated to address the issue. The
vulnerability was disclosed to key HTTP/2 implementers, helping to devise and distribute effective countermeasures. The
vulnerability is logged against &lt;a href="https://www.cve.org/CVERecord?id=CVE-2023-44487"&gt;CVE-2023-44487&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;HTTP/2 'Rapid Reset' DDoS attacks pose a serious risk to services using the protocol. To reduce exposure, service
providers should promptly apply available software patches and updates.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Learn how Peakhour's Application Security Platform helps protect against Layer 7 DDoS attacks, including the HTTP/2 Rapid Reset vulnerability. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to secure your infrastructure.&lt;/em&gt;&lt;/p&gt;</content><category term="DDoS"></category><category term="DDoS"></category><category term="Rate Limiting"></category><category term="HTTP"></category><category term="Bot Management"></category><category term="Web Performance"></category><category term="DNS"></category></entry><entry><title>Understanding the HTTP/2 Rapid Reset Attack</title><link href="https://www.peakhour.io/blog/http-rapid-reset-attack/" rel="alternate"></link><published>2023-10-11T00:00:00+11:00</published><updated>2023-10-11T00:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-10-11:/blog/http-rapid-reset-attack/</id><summary type="html">&lt;p&gt;A comprehensive breakdown of the HTTP/2 Rapid Reset flaw and guidance on bolstering defences against potential DDoS attacks.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The discovery of the HTTP/2 Rapid Reset flaw exposed a serious weakness in a widely used version of the HTTP protocol.
When exploited, it can be used to generate large Distributed Denial of Service (DDoS) attacks against HTTP/2 services.
This post explains how the attack works and what operators can do to strengthen their defences.&lt;/p&gt;
&lt;h2&gt;A Deep Dive into the HTTP/2 Rapid Reset Flaw&lt;/h2&gt;
&lt;p&gt;HTTP/2 is widely deployed, so a flaw in how implementations handle rapid stream resets can have a large operational
impact. To take advantage of the issue, a malicious actor sends a request and immediately cancels it, then repeats that
pattern over the same HTTP/2 connection. By scaling this "request, cancel" behaviour thousands of times, an attacker can
overwhelm vulnerable HTTP/2 implementations. The result is &lt;a href="/products/ddos-protection/"&gt;DDoS attacks&lt;/a&gt; at the application layer, with
potential downtime and disruption.&lt;/p&gt;
&lt;p&gt;Major companies including Cloudflare and Google have dealt with this issue. Google, for example, mitigated a DDoS attack
reaching a peak of 398 million requests per second that relied on this technique. For scale, this two-minute-long attack
generated more requests than the total number of article views reported by Wikipedia in
September 2023.&lt;/p&gt;
&lt;h2&gt;Mitigating the Threat&lt;/h2&gt;
&lt;p&gt;Large infrastructure providers have led much of the work to understand the attack mechanics and develop mitigations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Patching Systems:&lt;/strong&gt; Prompt patching is the primary control for the HTTP/2 Rapid Reset attack. Companies
   including Peakhour, Microsoft, and others have tested and patched their systems against this threat.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rate Limiting:&lt;/strong&gt; Advanced rate limiting has been a recommended action. It provides an extra layer of protection,
   minimising the risk of massive request inflows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Collaborative Efforts:&lt;/strong&gt; Google and Microsoft have both shared intelligence and collaborated with other cloud
   providers and software maintainers implementing the HTTP/2 protocol stack. This has resulted in patches and
   mitigation techniques now employed by numerous large infrastructure
   providers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;What's Next for Users and Enterprises?&lt;/h2&gt;
&lt;p&gt;If you serve an HTTP-based workload online, understand whether this attack affects your environment. Verify that servers
supporting HTTP/2 are either not vulnerable or have applied the necessary patches. Stay informed and consider reaching
out to your service providers or account representatives for configuration assistance and guidance.&lt;/p&gt;
&lt;p&gt;The HTTP/2 Rapid Reset flaw is a serious application-layer DDoS risk, but it is manageable with the right mitigations in
place. Apply the recommended patches and keep HTTP/2-facing services under active review.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Discover how Peakhour's Application Security Platform protects against Layer 7 DDoS attacks, including the HTTP/2 Rapid Reset vulnerability. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to secure your infrastructure.&lt;/em&gt;&lt;/p&gt;</content><category term="Security"></category><category term="DDoS"></category><category term="Rate Limiting"></category><category term="DNS"></category><category term="API Security"></category><category term="Bot Management"></category><category term="Threat Detection"></category></entry><entry><title>ZDNS - scan the entire internet</title><link href="https://www.peakhour.io/blog/zdns/" rel="alternate"></link><published>2023-06-20T13:00:00+10:00</published><updated>2023-06-20T13:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-06-20:/blog/zdns/</id><summary type="html">&lt;p&gt;Details the use of ZDNS, a high-performance DNS toolkit, to create a comprehensive Reverse DNS (rDNS) lookup database by scanning the entire internet, and how randomizing the IP space overcomes UDP timeout issues.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The lack of a free &lt;a href="/learning/reverse-dns-lookup/"&gt;Reverse DNS&lt;/a&gt; (rDNS) lookup database has made large-scale DNS research harder. To address this,
we used ZDNS, an open-source, high-performance DNS toolkit developed by Stanford University, to create our own
rDNS database. To reduce UDP timeout issues during rDNS operations, we devised a scan-ordering approach that randomised
the IP space and improved the efficiency of the scanning process.&lt;/p&gt;
&lt;h2&gt;Leveraging ZDNS for rDNS Lookups Across the Internet&lt;/h2&gt;
&lt;p&gt;Understanding rDNS is useful for internet operations and research. Active DNS measurement helps us inspect how providers
advertise the use of their IP address space. One of the components of this ecosystem is Reverse DNS (rDNS), which serves
an important role in IP database categorisation and ASN (Autonomous System Number) classification. However, running rDNS
across the entire internet is not a trivial task.&lt;/p&gt;
&lt;p&gt;Previously, Rapid7 provided a free database for rDNS lookups, but it has discontinued the offering. This situation has
prompted the need to create our own database, calling for a robust, efficient, and scalable tool to accomplish
the task. ZDNS was the right fit.&lt;/p&gt;
&lt;h2&gt;Introducing ZDNS&lt;/h2&gt;
&lt;p&gt;ZDNS, a part of the ZMap.io project, is a capable tool developed by Stanford University to support scalable and
reproducible DNS research. ZDNS is an open-source DNS measurement framework specifically optimised for large-scale
DNS research on the public internet. It can resolve 50 million domains in 10 minutes and query the PTR records of the
complete public IPv4 address space in approximately 12 hours.&lt;/p&gt;
&lt;p&gt;This high-performance toolkit offers a modular interface, enabling researchers to safely implement new functionalities.
Its architecture is designed to expose &lt;a href="/learning/web-concepts/what-is-reverse-dns-lookup/"&gt;DNS lookup&lt;/a&gt; chains by performing recursive resolution. ZDNS supports a
command-line interface and outputs results in JSON, a machine-parsable format.&lt;/p&gt;
&lt;h2&gt;Enhancements by ZDNS&lt;/h2&gt;
&lt;p&gt;ZDNS's architecture and feature set are tailored to the challenges of extensive DNS research. Its guiding
principles are that the DNS lookup chain is exposed, and that the tool is safe, easy to use, and extensible.&lt;/p&gt;
&lt;p&gt;ZDNS's performance optimisations make it a suitable tool for DNS experiments that require querying a large number of
names. Parallelism, UDP socket reuse, and selective caching are some of the critical performance optimisations that
enable ZDNS to efficiently handle large volumes of DNS queries.&lt;/p&gt;
&lt;p&gt;ZDNS's scalability, execution time, and success rate have been evaluated against several existing tools, showcasing its
performance. For instance, when it comes to exposing the DNS lookup chain, ZDNS is 85 times faster than Dig.
ZDNS also outperforms other higher-performance tools, achieving 2.6 to 3.6 times more successful queries per second and
experiencing about 30% less packet drop than MassDNS.&lt;/p&gt;
&lt;h2&gt;Our rDNS Journey&lt;/h2&gt;
&lt;p&gt;When we started scanning the whole internet with rDNS, we hit a practical roadblock: UDP timeouts made the scans
slow. The system spent too much time waiting for responses from parts of the internet that were either empty or broken.&lt;/p&gt;
&lt;p&gt;We used two changes. Firstly, instead of scanning the internet's addresses in order, we mixed them
up and scanned randomly. This spread out our requests and stopped the system from getting stuck on troublesome ranges.
Secondly, we checked smaller sections of the internet first, so we did not waste time waiting for big chunks of the
internet that weren't responding.&lt;/p&gt;
&lt;p&gt;With these changes, we scanned the whole internet in &lt;em&gt;13 days&lt;/em&gt;, finding over a &lt;em&gt;billion addresses&lt;/em&gt;. The main lesson was
straightforward: scan order matters when timeout behaviour dominates runtime.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;ZDNS has proven to be a valuable tool for DNS research, especially for substantial tasks like performing a reverse
DNS scan of the entire internet. Our experience underscores the value of practical adjustments when dealing with
large-scale challenges, like randomising the IP space to avoid delays caused by UDP timeouts.&lt;/p&gt;
&lt;p&gt;As an open-source tool, ZDNS is available on Github. For more detail, read the award-winning paper presented at IMC
2022.&lt;/p&gt;
&lt;p&gt;Our work with ZDNS shows its value in DNS research and the operational detail involved in large-scale DNS work. By
randomising the scan order, we mitigated timeout issues and improved the efficiency of our scanning process.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1^"&gt;
&lt;p&gt;Izhikevich, L., Akiwate, G., Berger, B., Drakontaidis, S., Ascheman, A., Pearce, P., Adrian, D., &amp;amp; Durumeric, Z. (2022). ZDNS: a fast DNS toolkit for internet measurement. In Proceedings of the 22nd ACM Internet Measurement Conference (pp. 33-43). https://doi.org/10.1145/3517745.3561434&amp;#160;&lt;a class="footnote-backref" href="#fnref:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2^"&gt;
&lt;p&gt;ZMap Project. (n.d.). ZDNS. GitHub. Retrieved 2023-05-15 13:00, from https://github.com/zmap/zdns.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2^" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Technical"></category><category term="DNS"></category><category term="CDN"></category><category term="Rate Limiting"></category><category term="Residential Proxies"></category><category term="DDoS"></category></entry><entry><title>Enterprise DDoS Protection</title><link href="https://www.peakhour.io/blog/enterprise-ddos-protection-microsoft-365-application-security/" rel="alternate"></link><published>2023-06-19T00:00:00+10:00</published><updated>2023-06-19T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-06-19:/blog/enterprise-ddos-protection-microsoft-365-application-security/</id><summary type="html">&lt;p&gt;Analysis of the Microsoft 365 DDoS attack by Storm-1359 reveals critical lessons for enterprise application security platforms. Learn advanced Layer 7 DDoS protection strategies and rate limiting techniques for modern applications.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Cyber threats continue to grow in complexity and volume, and Layer 7 attacks remain especially difficult to defend
against&lt;sup id="fnref:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;. Each layer presents its own set of vulnerabilities for threat actors to exploit. The 7th layer, or
application layer, handles application-specific communications. That makes it a useful target because modern
applications are complex and varied.&lt;/p&gt;
&lt;p&gt;Defending against Layer 7 attacks requires continuous tuning and adaptation&lt;sup id="fnref2:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;. Microsoft highlighted the issue in
June 2023, when it reported a traffic surge that temporarily affected the availability of some of its services&lt;sup id="fnref3:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2&gt;Microsoft's Layer 7 DDoS Attacks&lt;/h2&gt;
&lt;p&gt;Microsoft's security team detected and tracked DDoS activity from a threat actor it called Storm-1359. The actor used a
mix of resources, including multiple virtual private servers (VPS), rented cloud infrastructure, open proxies,
and DDoS tools&lt;sup id="fnref4:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The activity did not target layers 3 or 4. It targeted layer 7, where requests can look like regular traffic and arrive
from source IPs distributed around the world.&lt;/p&gt;
&lt;h3&gt;The Attack Methods&lt;/h3&gt;
&lt;p&gt;Storm-1359 used several attack types, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTTP(S) Flood Attack&lt;/strong&gt;: The attacker aimed to exhaust system resources with a high load of SSL/TLS handshakes and HTTP(S) request processing. This attack led the application backend to run out of compute resources such as CPU and memory&lt;sup id="fnref8:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache Bypass&lt;/strong&gt;: The attacker attempted to overload the origin servers by bypassing the CDN layer&lt;sup id="fnref9:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slowloris&lt;/strong&gt;: In this case, the client opens a connection to a web server, requests a resource, such as an image, but fails to acknowledge the download or accepts it slowly. This causes the web server to keep the connection open and hold the requested resource in memory&lt;sup id="fnref10:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.
  Strengthening Layer 7 Protections&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Microsoft mitigated the majority of disruptions by hardening its Layer 7 protections. It fine-tuned Azure Web
&lt;a href="/learning/cloud-security/cloud-waf-vs-native-waf/"&gt;Application Firewall&lt;/a&gt; (WAF) to better defend customers from the impact of similar DDoS attacks&lt;sup id="fnref5:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;Azure Web Application Firewall, ModSecurity, and DDoS Attacks&lt;/h3&gt;
&lt;p&gt;Azure &lt;a href="/products/waf/"&gt;Web Application Firewall&lt;/a&gt; (WAF), part of Microsoft's security architecture, is built upon ModSecurity&lt;sup id="fnref:4^"&gt;&lt;a class="footnote-ref" href="#fn:4^"&gt;4&lt;/a&gt;&lt;/sup&gt;,
a well-established open-source Web Application Firewall (WAF) module&lt;sup id="fnref6:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;. The DDoS attack Microsoft faced highlighted
potential limitations in using ModSecurity, or any conventional WAF, as the primary defence mechanism against such
threats.&lt;/p&gt;
&lt;h3&gt;ModSecurity's Limitations in DDoS Defence&lt;/h3&gt;
&lt;p&gt;ModSecurity is effective against a variety of web application threats, but it has limitations when dealing with DDoS
attacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lack of Scalability:&lt;/strong&gt; ModSecurity is not inherently scalable. It can struggle to handle the enormous traffic volume
  associated with DDoS attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delayed Response:&lt;/strong&gt; ModSecurity's rule-based approach can result in slower response times to evolving DDoS threats.
  While it can block threats based on established rules, it can take time to identify and create rules for new or
  uncommon attack patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational Complexity:&lt;/strong&gt; ModSecurity requires substantial expertise and constant fine-tuning to remain effective,
  potentially slowing down response times during a fast-paced DDoS attack.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These limitations were visible during the DDoS attack Microsoft experienced. Even though Microsoft utilised ModSecurity
via Azure WAF, the time it took for Azure to respond underlines the challenge of using traditional WAFs for this class
of attack&lt;sup id="fnref7:1^"&gt;&lt;a class="footnote-ref" href="#fn:1^"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;The Role of Residential Proxy Networks in Layer 7 DDoS Attacks&lt;/h3&gt;
&lt;p&gt;&lt;a href="/products/residential-proxy-detection/"&gt;Residential proxy&lt;/a&gt; networks create a specific problem in the defence against Layer 7 DDoS attacks&lt;sup id="fnref:3^"&gt;&lt;a class="footnote-ref" href="#fn:3^"&gt;3&lt;/a&gt;&lt;/sup&gt;. These
networks use IP addresses tied to physical locations, often originating from typical home or office internet
connections. That makes it harder to separate legitimate traffic from malicious traffic.&lt;/p&gt;
&lt;p&gt;Unlike traditional proxy or VPN networks, where traffic can be blocked or rate-limited based on their recognisable IP
ranges, residential proxy networks blend in with legitimate users. That complicates identifying and blocking malicious
requests, as any blocking or limiting measures could affect legitimate traffic from
residential IPs.&lt;/p&gt;
&lt;h3&gt;A Potential Solution&lt;/h3&gt;
&lt;p&gt;In this context, fingerprinting can help distinguish between legitimate clients and malicious actors. Fingerprinting
involves gathering data points from each client request, including user agent, IP address, headers, cookies, and more.
The combination of these data points creates a unique 'fingerprint' for each client.&lt;/p&gt;
&lt;p&gt;By analysing these fingerprints, it is possible to detect anomalous request patterns and potentially identify malicious
clients hidden behind residential IPs. Fingerprinting can improve the accuracy of identifying malicious traffic, but it
is not foolproof and should sit inside a broader, layered defence strategy.&lt;/p&gt;
&lt;p&gt;Implementing effective fingerprinting also requires substantial technical expertise and resources. The measures need to
avoid degrading user experience or breaching privacy regulations.&lt;/p&gt;
&lt;h3&gt;The Need for Specialised Rate Limiting Services&lt;/h3&gt;
&lt;p&gt;A specialised rate limiting service could have offered a faster and more effective response to the DDoS attack. Rate
limiting restricts the number of requests that an IP address can make within a specific time period&lt;sup id="fnref:2^"&gt;&lt;a class="footnote-ref" href="#fn:2^"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Such a service offers several advantages when defending against DDoS attacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rapid Response:&lt;/strong&gt; Rate limiting can provide a quick initial defence against a DDoS attack by immediately limiting
  traffic from suspicious IP addresses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; Rate limiting rules can be applied to factors such as IP addresses, URL, headers, response codes, and
  more, creating more granular defence mechanisms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Load:&lt;/strong&gt; By limiting the rate of requests, these services can reduce the load on the server, preserving
  resources for legitimate traffic.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Advanced Rate Limiting and Custom Keys&lt;/h2&gt;
&lt;p&gt;One way to defend against these attacks is through &lt;a href="/blog/beyond-the-ip-address-advanced-rate-limiting/"&gt;advanced rate&lt;/a&gt; limiting&lt;sup id="fnref2:2^"&gt;&lt;a class="footnote-ref" href="#fn:2^"&gt;2&lt;/a&gt;&lt;/sup&gt;. Rate limiting restricts the number of
requests an IP address, URL, or another custom key can make in a set time period. This can stop a single actor from
flooding a network with traffic.&lt;/p&gt;
&lt;h3&gt;Criteria Used in Rate Limiting&lt;/h3&gt;
&lt;p&gt;Rate limits can be defined using different criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IP Address&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query String&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Response Codes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GeoIP Information&lt;/strong&gt;: ASN or Country Code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parsed User Agent Information&lt;/strong&gt;: Different rules for search engines vs. generic 'bots'&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fingerprints&lt;/strong&gt;: TCP, TLS or H2 fingerprints can uniquely identify the connecting software&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meta Information&lt;/strong&gt;: From bot protection service&lt;sup id="fnref3:2^"&gt;&lt;a class="footnote-ref" href="#fn:2^"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows rate limiting to 'bucket' requests using different criteria, effectively rate limiting a larger group of
connections.&lt;/p&gt;
&lt;h2&gt;The Role of Anomaly Detection&lt;/h2&gt;
&lt;p&gt;Anomaly detection is another useful tool against these attacks. It identifies patterns or events that deviate from the
norm and may indicate suspicious activity. Detecting those anomalies quickly can help teams respond faster, identify a
suitable rate limit key and stop the potential attack.&lt;/p&gt;
&lt;h2&gt;Caching as a Mitigation Strategy&lt;/h2&gt;
&lt;p&gt;Caching is an effective mitigation strategy for Layer 7 attacks. It stores static responses to requests, reducing load
on the server by serving those responses instead of processing each request individually. In a DDoS scenario, where a
flood of requests is sent to the server, caching can help maintain availability. Ignoring client-provided 'Cache
Control' headers such as 'max-age=0' or 'no-cache' can be effective because these headers are typically used to bypass
a CDN.&lt;/p&gt;
&lt;h2&gt;Recommendations for Defence Against Layer 7 Attacks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use anomaly detection to identify an active attack.&lt;/li&gt;
&lt;li&gt;Use Layer 7 protection services, including rate limiting, with past 99th percentile hit rates as a starting point.&lt;/li&gt;
&lt;li&gt;Apply bot mitigation techniques, as most Layer 7 attacks originate from bots.&lt;/li&gt;
&lt;li&gt;Use IP reputation as an early warning sign, as many IPs have been involved in attacks before.&lt;/li&gt;
&lt;li&gt;Block, limit, or redirect traffic from outside a defined geographic region.&lt;/li&gt;
&lt;li&gt;Rate limit or block requests from data centre and hosting ASNs.&lt;/li&gt;
&lt;li&gt;Create custom WAF rules to automatically block and rate limit HTTP or HTTPS attacks with known signatures.&lt;/li&gt;
&lt;li&gt;Use effective CDN caching and ignore client-presented Cache-Control headers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Defending against Layer 7 attacks requires several controls working together. Rate limiting, anomaly detection, and
effective caching all have a role.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Peakhour's advanced rate limiting and DDoS mitigation strategies help protect applications from sophisticated Layer 7 attacks. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to strengthen your defences.&lt;/em&gt;&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1^"&gt;
&lt;p&gt;&lt;a href="https://msrc.microsoft.com/blog/2023/06/microsoft-response-to-layer-7-distributed-denial-of-service-ddos-attacks/"&gt;Microsoft Response to Layer 7 DDoS Attacks&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref5:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref6:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref7:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref8:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref9:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref10:1^" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2^"&gt;
&lt;p&gt;&lt;a href="https://www.peakhour.io/blog/rate-limiting/"&gt;Rate Limiting - Peakhour&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2^" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:2^" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:2^" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3^"&gt;
&lt;p&gt;&lt;a href="https://www.peakhour.io/blog/residential-proxies-unseen-challenges/"&gt;Residential Proxies: Unseen Challenges - Peakhour&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:3^" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4^"&gt;
&lt;p&gt;&lt;a href="https://github.com/microsoft/ModSecurity"&gt;Microsoft - ModSecurity&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:4^" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="DDoS"></category><category term="DDoS"></category><category term="Threat Detection"></category><category term="Rate Limiting"></category><category term="Application Security"></category><category term="Account Protection"></category><category term="API Security"></category></entry><entry><title>Understanding HTTP Link Headers</title><link href="https://www.peakhour.io/blog/http-link-headers/" rel="alternate"></link><published>2023-05-24T13:00:00+10:00</published><updated>2023-05-24T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2023-05-24:/blog/http-link-headers/</id><summary type="html">&lt;p&gt;HTTP Link headers are a relatively unknown but powerful way to improve page load times.&lt;/p&gt;</summary><content type="html">&lt;p&gt;HTTP headers are part of browser requests and server responses. They carry information about the
connecting client, the requested resource, the server, and other request context.
An HTTP header has a case-insensitive name followed by a colon (:), then its value. Headers are used for
authentication information, content negotiation, and related protocol behaviour. Here are some sample
request headers sent by my browser when requesting a page on the Peakhour website:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="sr"&gt;/html,application/xhtml+xml,application/xml;q=0.9,*/&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;
&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deflate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;br&lt;/span&gt;
&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Language&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AU&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;
&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;alive&lt;/span&gt;
&lt;span class="n"&gt;Cookie&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_ga_NRWSVE0PSC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GS1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.1685943893&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;13.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1685943893.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;peakhour&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;io&lt;/span&gt;
&lt;span class="n"&gt;Sec&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dest&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;
&lt;span class="n"&gt;Sec&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Mode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;navigate&lt;/span&gt;
&lt;span class="n"&gt;Sec&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;
&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mozilla&lt;/span&gt;&lt;span class="sr"&gt;/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4.1 Safari/&lt;/span&gt;&lt;span class="mf"&gt;605.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;The HTTP Link header&lt;/h2&gt;
&lt;p&gt;An HTTP Link header lets a server send
context about a document back to a client. It can identify related
resources or the direct location of a specific asset. For page-load optimisation, Link headers can be an alternative to
putting preload/preconnect/prefetch hints in the HTML.&lt;/p&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;HTTP Link headers were proposed as a standard in the late 1990s, around the same time the
HTTP/1.1 protocol was defined. However, it wasn't until 2010 that HTTP Link headers were officially recognised by
the Internet Engineering Task Force (IETF) in RFC 5988, which described their purpose and functionality.&lt;/p&gt;
&lt;h2&gt;Uses&lt;/h2&gt;
&lt;p&gt;HTTP Link headers have several uses in web development. Some common examples are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pagination&lt;/strong&gt;: Say we have a blog site with hundreds of posts, and we display 10 posts per page.
  When a user requests a page, we can use Link headers to provide URLs for the next and previous pages.
  This helps navigation through the large list of posts. Here's an example of how it might look:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Link:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;/posts?page=2&amp;gt;;&lt;span class="w"&gt; &lt;/span&gt;rel=&amp;quot;next&amp;quot;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;/posts?page=4&amp;gt;;&lt;span class="w"&gt; &lt;/span&gt;rel=&amp;quot;prev&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Preloading&lt;/strong&gt;: Suppose we have a heavy image or a large CSS file that we know will be required for a webpage.
  We can use a Link header to tell the browser to start downloading it early, improving the perceived page
  load speed. For instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;picture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Hints&lt;/strong&gt;: Link headers can give the browser hints about resources that might be needed in the
  future, so the browser can decide whether to fetch them ahead of time. For instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;Link&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;scripts&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;myscript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;js&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;prefetch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Comparison to Link Tags and Why Headers Can Be Better&lt;/h2&gt;
&lt;p&gt;Now you might be wondering, "Why use Link headers when we can use HTML Link tags?" There are several reasons
HTTP Link headers might be a better choice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Faster Processing&lt;/strong&gt;: Since HTTP Link headers are part of the HTTP response, they arrive before the HTML document.
  This allows browsers to start preloading or prefetching resources sooner, which can improve page load times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Greater Flexibility&lt;/strong&gt;: HTTP Link headers can be used in situations where HTML Link tags cannot. For instance, they
  can be used with file types that don't support HTML, like JSON or XML. They can also be added by a third party, e.g.,
  &lt;strong&gt;an edge delivery layer such as Peakhour&lt;/strong&gt;, without the need to parse and rewrite the HTML document.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less Clutter&lt;/strong&gt;: Link headers can make your HTML less cluttered, as you can avoid filling the HTML document with
  numerous Link tags.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;HTTP Link headers are a small part of HTTP, but they are useful for performance and flexibility. An edge delivery layer
can add Link headers without the overhead of parsing or manipulating the main document, which makes them useful for
optimising website performance.&lt;/p&gt;</content><category term="Learning"></category><category term="HTTP"></category><category term="Web Performance"></category><category term="Caching"></category><category term="Rate Limiting"></category><category term="Core Web Vitals"></category><category term="CDN"></category></entry><entry><title>Consistent Hash with Bounded Loads</title><link href="https://www.peakhour.io/blog/bounded-load-hashing/" rel="alternate"></link><published>2023-05-15T13:00:00+10:00</published><updated>2023-05-15T13:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-05-15:/blog/bounded-load-hashing/</id><summary type="html">&lt;p&gt;An overview of consistent hashing with bounded loads, an advanced load balancing technique that ensures a more even distribution of keys across servers, preventing overload and improving system stability.&lt;/p&gt;</summary><content type="html">&lt;p&gt;A consistent hash with load bounds extends the basic consistent hashing technique. Standard consistent hashing
distributes keys across servers in a way that minimises rehashing when servers are added or removed, but it does not
guarantee a perfectly even load distribution. Random hash collisions can leave some servers responsible for
significantly more keys than others, creating an imbalance in the load distribution.&lt;/p&gt;
&lt;p&gt;Consistent hashing with bounded loads, or bounded-load hashing, addresses this issue. It keeps the load (i.e., the
number of keys assigned) on any given server within a factor of the average load across all servers.&lt;/p&gt;
&lt;p&gt;The approach still uses a hash ring, but with an additional constraint that no server can exceed a certain load limit.
When a key is hashed and the corresponding server in the hash ring is already at its load limit, the key is assigned to
the next server in the hash ring that isn't at its load limit. This process is repeated until all keys have been
assigned.&lt;/p&gt;
&lt;p&gt;Here's a rough pseudocode example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Function to add a key with bounded loads&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_key_bounded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Find the server for this key&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;  &lt;span class="c1"&gt;# To loop back to the beginning of the ring&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hash_ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;server_loads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hash_ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LOAD_LIMIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;server_loads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hash_ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Increment the server&amp;#39;s load&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hash_ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Return the server that should handle this key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, &lt;code&gt;server_loads&lt;/code&gt; is a dictionary that tracks how many keys each server is responsible for,
and &lt;code&gt;LOAD_LIMIT&lt;/code&gt; is the maximum number of keys any server is allowed to handle.&lt;/p&gt;
&lt;p&gt;By bounding the load on each server, this approach can produce a more balanced distribution of keys across servers.
However, it's worth noting that this algorithm can result in keys being assigned to servers that are not their nearest
neighbours in the hash ring, which can increase latency in some cases. As with any algorithm, there's a
trade-off between &lt;a href="/learning/load-balancing/"&gt;load balancing&lt;/a&gt; and other factors such as latency and computational overhead.&lt;/p&gt;
&lt;p&gt;The Google Cloud team, in collaboration with visiting researcher Mikkel Thorup from the University of Copenhagen,
devised an efficient allocation algorithm to improve load balancing in large-scale web services such as content hosting.
The results of their research were detailed in a paper titled “Consistent Hashing with Bounded Loads” that was published
in August 2016.&lt;/p&gt;
&lt;p&gt;Load balancing in large-scale web services means distributing client requests evenly across multiple servers to prevent
any individual server from becoming overloaded. An ideal load-balancing system distributes the load uniformly and
minimises the changes to the system when servers or clients are added or removed. This consistency matters in dynamic
environments where servers and clients can change over time.&lt;/p&gt;
&lt;p&gt;Traditional consistent hashing techniques, although effective for load balancing in dynamic environments, can still lead
to sub-optimal load distribution across servers in certain scenarios. As both servers and clients can be added or
removed frequently, the load balancing algorithm needs to stay dynamic and adaptive, maintaining an evenly distributed
load while minimising the number of client reassignments whenever a change occurs.&lt;/p&gt;
&lt;p&gt;Google's algorithm addresses these challenges. To explain their method, they use an analogy of servers as bins and
clients as balls. The goal is for all bins (servers) to have a load (clients) roughly equal to the average density, with
a small tolerance factor, ε. The algorithm is designed to ensure that every bin has a capacity within the range of the
average load times (1+ε), which helps achieve both uniformity and consistency in client-server allocations.&lt;/p&gt;
&lt;p&gt;The algorithm employs two separate hash functions to assign positions to balls (clients) and bins (servers) on a
circular continuum. The balls are then allocated in a specific order (say, based on their ID), with each ball being
assigned to the first bin it encounters with spare capacity as it moves clockwise on the circle.&lt;/p&gt;
&lt;p&gt;The algorithm recomputes the allocation whenever an update occurs (i.e., the addition or removal of a client or server)
to maintain the uniform distribution of load. The paper proves that every ball removal or insertion in the system
results in O(1/ε²) movements of other balls. Importantly, this upper bound is independent of the total number of balls
or bins in the system, which means the algorithm scales well with increasing size.&lt;/p&gt;
&lt;p&gt;The algorithm creates a trade-off between uniformity and consistency. A smaller ε value provides better uniformity but
compromises consistency, while a larger ε value improves consistency but reduces uniformity. The algorithm performs well
even in worst-case scenarios, making it ideal for dynamic, large-scale environments like content hosting services.&lt;/p&gt;
&lt;p&gt;Google's algorithm has been used in production. Andrew Rodland from Vimeo implemented it in HAProxy, a popular
open-source software package, for their load balancing project, resulting in a substantial decrease in cache bandwidth
by almost a factor of 8. This eliminated a significant scaling bottleneck, showing the algorithm's practical
effectiveness.&lt;/p&gt;
&lt;p&gt;Overall, the work of the Google Cloud team and Mikkel Thorup is a useful contribution to load balancing. By addressing
the challenges of uniformity and consistency in dynamic environments, their algorithm provides a robust solution for
managing large-scale web services efficiently. The team's research and its open-source availability give the broader
community a practical implementation path.&lt;/p&gt;</content><category term="Features"></category><category term="Rate Limiting"></category><category term="Drupal"></category></entry><entry><title>Multi-Origin Load Balancing</title><link href="https://www.peakhour.io/blog/multi-origin-load-balancing/" rel="alternate"></link><published>2023-04-11T13:00:00+10:00</published><updated>2023-04-11T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2023-04-11:/blog/multi-origin-load-balancing/</id><summary type="html">&lt;p&gt;Websites with a global audience need more than just a traditional CDN. They need geographic multi origin load balancing.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Websites and applications with global audiences often run into a problem that a standard CDN cannot always hide: not
every request can be served from cache. Traditional Content Delivery Networks (CDNs) reduce latency by distributing
content across multiple points of presence (POPs) around the world. But when content has to be fetched from a distant
origin server, for example dynamic content that cannot be cached, users still wait on that round trip. This post explains
the problem multi-origin &lt;a href="/learning/load-balancing/"&gt;load balancing&lt;/a&gt; solves and how Peakhour handles it.&lt;/p&gt;
&lt;h2&gt;Understanding the Problem&lt;/h2&gt;
&lt;p&gt;Web content usually starts from a single server, called the origin server. As a website's audience grows, that server
takes more traffic, which can slow response times. CDNs reduce the pressure by caching and delivering content from
servers distributed across multiple geographic locations. When the content is already cached, this reduces origin load
and lowers latency for users accessing the content.&lt;/p&gt;
&lt;p&gt;However, traditional CDNs still have limits when serving global audiences. If a user requests content that is not cached
in the CDN, the request has to go back to the origin server. If that origin is far away from the user, latency increases
and pages take longer to load.&lt;/p&gt;
&lt;p&gt;Multi-origin load balancing addresses that remaining gap in &lt;a href="/learning/cdn/"&gt;CDN&lt;/a&gt; performance and further reduces latency.&lt;/p&gt;
&lt;h2&gt;Introducing Multi-Origin Load Balancing&lt;/h2&gt;
&lt;p&gt;Traditional load balancing distributes traffic evenly across two or more servers that
are physically hosted in the same location.&lt;/p&gt;
&lt;p&gt;Multi-origin load balancing extends that approach across origin servers in different geographical locations. The
Peakhour EDGE can select the closest origin server to a user, or choose a different origin based on criteria such as
device type, user preferences, or URL. For requests not stored in the CDN, this reduces the time spent crossing long
network paths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real-Time Performance Monitoring:&lt;/strong&gt; Peakhour continuously monitors its global network of servers in real time. This
allows the system to detect potential issues or bottlenecks and adjust routing. If one origin server experiences high
traffic or goes offline, Peakhour can reroute user requests to the next best server to keep the site responsive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adaptive Content Caching:&lt;/strong&gt; Peakhour Edge uses adaptive content caching strategies, which dynamically cache both
static and dynamic content based on user behaviour and request patterns. Frequently requested dynamic elements, such as
personalised user data or search results, are cached on edge servers, reducing the need to fetch content from the
origin servers and further minimising latency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Load Balancing and Failover:&lt;/strong&gt; Peakhour's multi-origin load balancing is complemented by load balancing and failover
mechanisms. These features keep the system resilient and responsive during periods of high traffic or server outages.
By distributing user requests evenly across origin servers and automatically redirecting traffic when a server fails,
Peakhour maintains a stable and reliable content delivery experience for users worldwide.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Multi-origin load balancing addresses the limitations of traditional CDNs by optimising content delivery for a global
audience. Peakhour Edge reduces latency and improves the experience for users who would otherwise wait on a distant
origin server.&lt;/p&gt;
&lt;p&gt;As web content and applications grow in complexity and reach, origin placement and routing become part of performance
planning. Peakhour implements multi-origin load balancing with clients' origin servers so requests can be sent to the
most suitable origin instead of treating a single distant server as the only fallback.&lt;/p&gt;</content><category term="Features"></category><category term="CDN"></category><category term="Web Performance"></category><category term="Drupal"></category><category term="Caching"></category><category term="Rate Limiting"></category></entry><entry><title>Introducing Automatic Cache Tags in the Updated Peakhour WordPress Plugin</title><link href="https://www.peakhour.io/blog/wordpress-plugin-cache-tags/" rel="alternate"></link><published>2023-03-20T13:00:00+11:00</published><updated>2023-03-20T13:00:00+11:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2023-03-20:/blog/wordpress-plugin-cache-tags/</id><summary type="html">&lt;p&gt;Read about automatic cache tags in the updated Peakhour WordPress plugin.&lt;/p&gt;</summary><content type="html">&lt;p&gt;We have updated the Peakhour WordPress plugin with automatic cache tag generation. The update is designed to help keep
cached WordPress content accurate without forcing full cache clears for routine content changes. We have also checked
compatibility with the latest versions of WordPress and PHP.&lt;/p&gt;
&lt;h2&gt;What are Cache Tags?&lt;/h2&gt;
&lt;p&gt;Cache tags are labels that CDNs such as Peakhour use to manage cached content more precisely. Instead of clearing the
whole cache when one page changes, you can purge only the content associated with the relevant tag. Visitors get the
updated content, while the rest of the site can continue to be served from cache.&lt;/p&gt;
&lt;h3&gt;A Cache Tag Example&lt;/h3&gt;
&lt;p&gt;Suppose you run a site with a home page, product pages, and blog articles. Without cache tags, updating one product page
or article may require clearing the entire cache. With cache tags, each part of the site can use its own tag, such as
"homepage," "product," and "blog." When you update content, you only need to purge the cache for the affected tag. That
means less unnecessary cache invalidation and a faster site for visitors.&lt;/p&gt;
&lt;h2&gt;Automatic Cache Tags in the Peakhour WordPress Plugin&lt;/h2&gt;
&lt;p&gt;The updated Peakhour WordPress plugin generates cache tags automatically for your site's content. When you update
content in the WordPress admin, the plugin sends the relevant purge requests to Peakhour. The result is more targeted
cache clearing without extra manual work.&lt;/p&gt;
&lt;h2&gt;How to Get Started with Automatic Cache Tags&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Update to the latest version of the Peakhour WordPress plugin.&lt;/li&gt;
&lt;li&gt;Follow the instructions to configure cache tags in the Peakhour admin.&lt;/li&gt;
&lt;li&gt;Flush your cache.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that, the plugin generates cache tags and sends purge requests to Peakhour whenever you update content in the
WordPress admin.&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Automatic &lt;a href="/learning/cache-tags/"&gt;cache tags&lt;/a&gt; in the Peakhour WordPress plugin make cache purging more precise. They
help improve performance, give you more flexibility, and reduce unnecessary cache clears. Try the updated plugin and let
us know how it works for you.&lt;/p&gt;</content><category term="CMS"></category><category term="Caching"></category><category term="CDN"></category><category term="Drupal"></category><category term="WordPress"></category><category term="Rate Limiting"></category></entry><entry><title>Layer 7 DDoS Protection</title><link href="https://www.peakhour.io/blog/layer-7-dos-and-full-page-caching/" rel="alternate"></link><published>2023-02-07T13:00:00+11:00</published><updated>2024-12-01T13:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2023-02-07:/blog/layer-7-dos-and-full-page-caching/</id><summary type="html">&lt;p&gt;Comprehensive guide to Layer 7 DDoS protection using strategic caching within application security platforms. Learn how intelligent caching strategies provide robust defence against sophisticated application-layer attacks.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In previous blog posts we've covered the benefits that &lt;a href="/blog/caching-dynamic-content-with-a-cdn/"&gt;full page caching has on page load performance&lt;/a&gt;.
We also covered how caching pages lowers origin server utilisation, so the site can handle more customers.
A lesser-known side benefit is protection against Layer 7 &lt;a href="/products/ddos-protection/"&gt;denial of service&lt;/a&gt; (DoS) attacks.&lt;/p&gt;
&lt;h2&gt;What is a Denial of Service attack?&lt;/h2&gt;
&lt;p&gt;The goal of a DoS attack is to make a network resource, such as a website or networked service, unavailable to users
by overwhelming it with excessive traffic or requests. DoS attacks can be launched from a single source or from multiple
sources (known as a distributed denial of service, or DDoS attack).&lt;/p&gt;
&lt;p&gt;Typically, an attacker floods the web server with HTTP or API requests to try to overwhelm it. An
attacker might also launch a 'slow attack', especially if they find a weak point in the application that consumes
a lot of server resources for a single request. One example is repeatedly using a site search function.
By slowing down the rate at which requests are sent, the attacker can bypass common rate-limiting and
traffic-shaping mechanisms that are designed to block high-volume traffic spikes.&lt;/p&gt;
&lt;p&gt;DoS conditions can also be inadvertent. A CMS like Magento or WordPress on an underpowered server can be overwhelmed,
or slowed to a crawl, by so-called 'grey' bots. Examples include Semrush, Ahrefs, dotbot, and MJ12Bot. These spiders
can crawl a site aggressively enough to bring it to its knees. Even Bing or Google can negatively impact a site.&lt;/p&gt;
&lt;h2&gt;What is Layer 7?&lt;/h2&gt;
&lt;p&gt;In networking parlance, Layer 7 refers to the actual application running on a web server. It is part of the OSI (Open Systems
Interconnection) model used to describe the various functions in transmitting data over a network. The model is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Layer 1 -&amp;gt; Physical Layer&lt;/strong&gt;, responsible for transmitting raw bits of data, e.g., a wire or wireless link&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 2 -&amp;gt; Data Link&lt;/strong&gt;, responsible for transmitting data frames between network devices and detecting transmission errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 3 -&amp;gt; Network Layer&lt;/strong&gt;, responsible for routing data packets between networks and determining the best path for transmission.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 4 -&amp;gt; Transport Layer&lt;/strong&gt;, responsible for end-to-end communication between applications, providing reliable data transmission and flow control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 5 -&amp;gt; Session Layer&lt;/strong&gt;, responsible for establishing, maintaining, and terminating communication sessions between applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 6 -&amp;gt; Presentation Layer&lt;/strong&gt;, responsible for formatting data to be presented to the application layer and for converting data from the application layer into a standardised format for transmission.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 7 -&amp;gt; Application Layer&lt;/strong&gt;, responsible for providing services to the user, such as file transfer, email, and web access.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How Full Page Caching helps&lt;/h2&gt;
&lt;p&gt;Full page caching helps by reducing the number of dynamic requests to the server. Caching the entire page
allows the server to serve pre-generated content to visitors, rather than generating it dynamically each time a page is
requested. This reduces the server's processing load and helps prevent excessive requests from overloading
the server or making it unavailable.&lt;/p&gt;
&lt;h2&gt;A real world example&lt;/h2&gt;
&lt;p&gt;As part of a series of Peakhour recommendations to 'harden' its website against layer 7 attacks, a Peakhour client
(a government site) applied limited full page caching with a &lt;strong&gt;time to live of 10 minutes.&lt;/strong&gt;  This means that Peakhour
will serve a page from its Edge cache for 10 minutes before hitting the origin again for a new version.&lt;/p&gt;
&lt;p&gt;Not long after implementation, that change was tested: a DDoS originating from hundreds of IPs across multiple countries
hammered a set of 5 pages. The attack was spread over several days with bursts of activity lasting about 15 minutes. With
the first hit, the page was cached and every subsequent hit was served from our high-performance Edge cache. No
slowdown was observed and the attackers gave up.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/layer-7-dos-attack.jpeg" width="100%" alt="Layer 7 DoS real world"/&gt;
&lt;em&gt;Real attack on a Peakhour client; the spikes formed in 15 minute bursts.&lt;/em&gt;
&lt;/div&gt;

&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/dos-attack-page-load.jpg" width="100%" alt="Layer 7 DoS real world page load"/&gt;
&lt;em&gt;Real page load times measured in the client browser&lt;/em&gt;
&lt;/div&gt;

&lt;h2&gt;But my site is dynamic...&lt;/h2&gt;
&lt;p&gt;Many websites have a small dynamic component on the page. For ecommerce sites this might be the mini cart in the top right
showing the number of items in the cart, or it might be some personalisation for a user. Often these dynamic
parts of the page can be rendered in the browser using Ajax or local storage, rather than rendered on the server.
By moving the dynamic components to the browser, the full page becomes cacheable. Another option is to use Edge Side
Includes (ESI), which enables the majority of the page to be cached in the CDN while the dynamic parts are fetched separately
before serving the full page to the user.&lt;/p&gt;
&lt;p&gt;Peakhour can help move dynamic page components from the server to the browser and cache more at the edge.
We also have a range of CMS plugins that do just that. Contact us if you want some help.&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Layer 7 DoS attacks have become more common than traditional DoS attacks, as they typically require far fewer
resources from the attacker. Reducing dynamic requests to the origin using full page caching is a useful but underappreciated
way to mitigate them. If you're concerned about website security, resilience, and performance,
Peakhour helps you cache more so you can protect, accelerate, and scale your website.&lt;/p&gt;</content><category term="DDoS"></category><category term="DDoS"></category><category term="CDN"></category><category term="Rate Limiting"></category><category term="Caching"></category><category term="Drupal"></category><category term="DNS"></category></entry><entry><title>Automatic Image Optimisation</title><link href="https://www.peakhour.io/blog/automatic-image-optimisation/" rel="alternate"></link><published>2022-12-06T13:00:00+11:00</published><updated>2022-12-06T13:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-12-06:/blog/automatic-image-optimisation/</id><summary type="html">&lt;p&gt;Image optimisation saves you bandwidth and designer effort while reduces page load time.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since releasing our &lt;a href="/image-optimisation/"&gt;automatic image optimisation&lt;/a&gt; capability in 2019, Peakhour optimises
more than 35 million images each month. On average, clients reduce page download time by 35% and image sizes by
91%.&lt;/p&gt;
&lt;p&gt;Automatic image optimisation offers a number of benefits over manual optimisation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Image formats are dynamically chosen based on the content of the image.&lt;/li&gt;
&lt;li&gt;Files are optimised based on client capabilities.&lt;/li&gt;
&lt;li&gt;Designer time is saved by offloading image optimisation work.&lt;/li&gt;
&lt;li&gt;Page load times can be reduced across an entire website.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is Image Optimisation?&lt;/h2&gt;
&lt;p&gt;Image optimisation means delivering high quality images in the right format and resolution for the device viewing them.
The aim is to minimise file size without compromising visual quality. Smaller image files generally load faster in a
visitor's browser, which can improve website speed, reduce traffic and support higher page visits and conversions.&lt;/p&gt;
&lt;h2&gt;Why dynamically choose the image format?&lt;/h2&gt;
&lt;p&gt;Using a one size fits all optimisation process does not account for the different types of images used across a typical
website.&lt;/p&gt;
&lt;p&gt;Website images can include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Photographs, such as product images, demonstration photos and title photos.&lt;/li&gt;
&lt;li&gt;Logos, which are typically text and can include animation.&lt;/li&gt;
&lt;li&gt;Illustrations that incorporate custom graphics to support the quick perception of information.&lt;/li&gt;
&lt;li&gt;3D graphics from computer renders including buildings, interior and exterior designs and products.&lt;/li&gt;
&lt;li&gt;Combinations of the above!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Any optimisation process needs to account for the end user's device type, supported file formats, resolution and the
content of the image. For example, a photograph with text needs different optimisation parameters so the text remains
crisp, while images with large areas of colour may need different formats to avoid colours being degraded by lossy
compression.&lt;/p&gt;
&lt;h2&gt;Fine developer control&lt;/h2&gt;
&lt;p&gt;With the &lt;a href="/docs/explanation/image-optimisation/api/"&gt;image optimisation API&lt;/a&gt;, your developers can enable reactive images by
resizing images on the edge. Peakhour serves and caches these optimisations, reducing origin requests and traffic,
cutting costs and making image changes faster to ship. You no longer need to wait for a designer to resize, crop or
re-orient an image for a page.&lt;/p&gt;
&lt;h2&gt;How does image optimisation effect web application performance&lt;/h2&gt;
&lt;p&gt;Large portions of a website are typically built from images. Large images loading over a 4G network in a train can delay
image rendering and create a poor user experience. Layout shifts can occur as the browser attempts to render the page,
and the user's perceived page load time will be affected.&lt;/p&gt;
&lt;p&gt;You can see the benefit of automatic image optimisation with our &lt;a href="/pages/page-weight"&gt;free tool&lt;/a&gt;. It will analyse any
website, calculate its optimisation potential and let you download the optimised images.&lt;/p&gt;
&lt;h2&gt;See how it can help in a real life example below&lt;/h2&gt;
&lt;div class=images&gt;
&lt;div class=image-container style="border: 1px;border-color: lightgrey; border-style: solid;"&gt;&lt;div class="section text-center"&gt;&lt;div class=image-header&gt;&lt;i class="fa-image fas" style="padding-right: 5px;"&gt;&lt;/i&gt; security.png &lt;/div&gt; &lt;div class=image-box&gt;&lt;a href=https://www.peakhour.io/static/images/security.png target=original title="show original"&gt;&lt;img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAChCAMAAABK+nL1AAAAt1BMVEX///8sOU/yyLr99fL+/f0hLUP9+/rvrUD//v7EjzT0z8MUIzvxwbL88Ozsrpr11cpTfrj55d7onYTvu6ofME7qp5H44Nb66uXttaJZUUPBiy6Eo8y6y+Hb5O/lkXb22tCZstXy9fqnvdvPlTLJ1eX3sj/n7fTbnznT3eyyt79pj8HJlDeRl6F1YT9ESlXrqDqPcT2rgTrhgGD34LjQpFnivHtibHzszJQ7bK7utVfbaEOhprCAh5RYZMzlAAAACXBIWXMAAAsSAAALEgHS3X78AAAWIklEQVR4nO1dCUPiOhAOaYwxtiltt4ccLSAiwgME12Pd/f+/680k5ZRzRReUz4PSFmg/ZiYzk2RCyAknnHDCCSeccMIJJ5xwwgknfBTEGP/6Qo4AYunm98YKIgRx7BxB9D3ZWqpSYslu2JGqIEcaEfYJF3dgYIwwtEECNpAgeEosTjjX9gn+MTjMBNJHrJRoswWnKPrtyGLEU0lGLOCHRDE8cwmzSKZInCQx7GOckTjCDYtospgB/55kubajMiVtRbOMJtImMnRVSNwwi+3EVXbmBRnskipDiUsnr0u+JVlUKN9OwjiwbRkGkoROQiWxoiAJbRUQldAgsTLfDjRZxmkQ/HuSlYUJpcoNHJsmKrQlARmTLnGDhCYBCFqgPDguAxWNJcvYrG9IFty64xAWcyYYF44FxgieCKAhBpPlCDT0cCQWHAyaIN4ojh04aMVWGJDv6JrO3LNWsbEDZXbjf5E3k3KUpv4olWrkp+koJOx7+lrbgIGGwj9uB0EMj1FKHGg7T3QtBfjvqR+GYZKAcQvDVBKeBctd2hPQz3LHyFwPtTMOrG9o5/8OIGzBtwx7toFgM8AdYMLAKTuxtR3A5ToZrh3A4sQ6+RBbAux+4p2Ea0sATSfDpTFjzdfBDT7jYg4cWyqXICfDRcBJN04o33wmGq5PuKKDBSMqDUOllL8xagYDb8svb+bX3Z4gPsTMjuPE1PM8a9MbufbX5spyiJYKk4gxW2KSpWHE94jvhz4G0L4vNgjXlzZcENolgUtizh3GHODNciyL4C+3jBhx6sUUdgoiQ+k7G5gQxnB9TbqArFA6ibK9UAahSiRYp8RLEhrK0MWb5r5BmhH/1Q83kQWxI7FdnUH8eoSB7+3ZSeIoGqggCjxFXQqEUUWtwOaYRk6x35CTJCCZijZKlmbL1a/8egDJUoEMQ2rDgydj240yN0ts6VqBwluOX33MV9FXSjhhW5CFZi5OHOJuc+rRgTvEdgTXFkqYptFCI21xfOKF9ijivgLJ4oynDvjzGzmA1ypH9zJ+NeherXkLk/dT6D/PJ1ma2sROVOqnfn7CJhoEof636ygTJPL1WAcSJAScLZCqSEbcHFqHBBP0K8gSIs8gfrGONBzbMGkNjY7yWNo003ytkRzLWjzIOGD5K/DQ5kD98AFsReC5e5Ezs5M7klIX6RB8pXDMHNA8mc16q1VtNyt3gMpdpdlsV1t1c0isJvOoYAY3TJ7iHTEro1Q6nGzSRxwUgeDtu99/np76/cKZxuXZjx9nZ4VCod9/evrz312lapT7uHshxZJ0FggU/OcRpTTGVnR1C4myIqp3f56ApEv4maIwxg8EPO0//XfXwjfbnN44Omh+uAd8edZklOCCUuI51f+ezi4BZwv4YVCYkoYMPv1uHbt0rYCmBgw+taMY+WILYTYj7A6ZmhB0OSNUV33EWLJy1lAzn5qbXZOjBPCD40UclwYZjn5wZwblwh03n8ZMwUPh6qrXu78fDoelUumidHs+GAxub2+7F8P7+95Vv5AzBnw9VckXVEUD1BphZTJw48yfksXIbyNKl8BT735Y6l4jut3uBQDIAtyc3xicD7rD+6uC4euscHdsDu0uhoNpNyJyJfj6+W0y8p+hqtC7LyFJF/PQZM0AKRsMe32k68fZkbE1jXm2A7aIjvLHesjIneaqD0whT6UFrkqLZOWMDYZ9ZKvQPCq2hIXu+i62QxBXTrd5H8nqXVxfLMdSsrRm9oCts6cjylkwEvs4di0gfKeLZhMlrGiurt+I1FrJMnTdo+GqHphorUmom8iZxOnOpsuAk9/gg/YXDdUWkgUYgCYenNUCJWP5zAk9gyKfRIFIgCx3FHopsf9qig5H8355tUoH10rW+c2VJuuA3AcIkYEP4giIYC20UGikONM5QEaUT9IRV69RNPqrFPFGstZJ1iGS5YRuTENXUTfMklC6ylV2kDgmFROqdEToq53mncw7pp7eJVnnB0gW9+xEWV5o0SQJnNC3A9zUA0VJrNJX5bivI18uCNY4dbeQuVswMF9PspLAxpkTllJ2qChVWWC5oR6rzdMgGgWpPQoyk/HkWeTFjmO99SUYckechf1fTLIIzpKAMBju1HJ4AI8OZ6Z7mpFEERdUkI584qU4xAG8c5dCxExtm1IpZRRFcWxZee6PEanmBXALyfo1pmbwa4Grj5EsMY+/ef3k5sab2mJZzEpp6oUqtIkz1TDMLFiWE8dR5kqXUgqiCeRRV3r+PFtbSJYVjbmKfn0CWYuOyP58XkZcn1A/FG6Yf4owdurNidxyHM+LIt+f27+RrK5HyMNAU+NZnyFZotWuVqvt/Lfd2t87A1khzm4lE7IWPhn9sqmNFyRQ8ydsIqv0gKZRs/VAnI+zWeNB6Jw0XoqzeKnsz+kV3EHTjT2wm88FqYt3ag27F6VHhm//PBg8gO38MMmamb9VxtC8jmi16i1S6/zD4HMnsjD596gt5jNI2BvJ2qMaNmtzaGFE1umUi6SxT7LyzO62rcbiaWvJKj0/lrqlZ0w7c53Z2TNZ2glES0EqL+VyuVMeo1Osw4c2m+3Kfsl6J9aRBTTxn6VbzZbu6XgcfIzNYqRt0mIgTvV2vcnqxfZYxorlwwnU15AFCgj+3M/b85IeDQGGq7RXyRKkUexMUOwUy1xwkLHGS7VebI7lbB9k6f4H3Uv4PiFdTRaYdlQQ59fNoOTid/5cWhSsd5ElSOulUcnRhJ9KsYGzsVqsRVpFzJJVq632PtRQzPim7xq1sZKs0k9uwsv4/Pz2IiKEvuHqfWQBGWCZhHEays1ahXQatbG/UEQnAgz8yyayxEppmelwrtehBSmXq7C107Vua+BLP6087iAesNWN3bdcvc9mjcnSqYJOpdMgnVoVZAzRKLaM/9BaTRaWT8HEHtO8YJJPu5T5o/Et9UHSLneq1U612alXOuXWLoK6MApmBVmlnzGeiX2M4JIiW93bt1z9tWQxjoPNWsUmuukTdBr6ztrlOtiszljIaktsFqvnt8xbdd4af35dj+rj+bF2q9kygldutcq1JiGNRplU9NuJN+NCcow7f/QjtDXbBNIlCHKAK+8C5YuhA3+7hKtFsvALNl+y/tbNn6mPM90hzCn4w4sLznobyeo0Oy1oDdsgYPAHUrEkWmw1CKm20KhVG5VqHR7qvM0aFQK316wxfN4sg7dWb3N4da2BIODulivlXQKCTmeerRWSleFIkbirXVI453mJCr5Hsmo1ptWwxesG4KvXwWbV2wCQtopWw1oNRGGJGmqyqrVaBSio1KB5gBMbVfiDrQbITrtcbdRgE09A/lmjxhlwVyMtsIwo041isVEtFst1kN96uVhsV2Z2tMByNmFHrVV86cxJ31Ky0Lij11DKQ0Pr13KyFmwWXFu9CpddbzSaDG6ENRsN+OobbdhRYXCUj3c0X8rwtlObVX+pFWtAVvllYuDXk1UjICONZhuoamNbCm8K3LRrKFywp90oY/uK14P9V+VavQmMVtqtWrmNCgi2sVWHlzI4i8Eb1FsVEFB4I9hR4bCjhTtY56WyWbKQLMMV1RnGn9fLuVqQLPiKQCaKlfwr6tTzHY3JDvjO2k3Y0XoBniZkIc+tZhUMPKkzMEHadUAVRDFbooZw1UA43FGj3KhWGyiLrTZQ12pUG1VSbzSrqJwooc0atICtDtiscgOpr/FmZzIjZfZxidGHrxAM3WabhWSB794t/cT2ha3iamc1nHg7NdPaFcu1PL5BX71crJCpUzqxZO1lRgYNI9DSmGnb2FsKzCdCk9o0ni2DtrCKG2LWsorcspLxzsmTxUh6JVmPJXxEbXhcxdUKA8/e2vPxk/wP2jBUhnpxGg0iXnS+oVmvQLiD6rMmT6rf2FRZY3mhNRzNrUeMMe0eGscnv+NKw8Qg4Grt1L26cPIKshhyhY/A1WKQs9Jm7QA9Tn1GDZtGDSszgbSYnLnmXba5dYZNrAk0y/V3xU4ryNJcaQl7ExC+Qw2nEMYpbekhv5yhgS+DgR+ThWb4HTf1Fq22xk4e6Vusckpz0ohdur35ALJIThYxSRrSQs3sLPM/9wKxhZhugfX5rJ8PpQ/rNwRF7Mw7pWCo6txg36Ttp7zthrRyd20n63vzWfXmHN6pJB+PgxoYcnBcHVT3PZv9+eiJLiYo3eUFfMF5eEvW7FCt7rENOVqDnUaTGg9N0fm9b8gqDad0de+H4MWviKL3YLM+E5zQRCprg5E3g2nyV1hRGq4LpLvD/tXVsKtdh9LF9dX9denR9EefL6HsICVrkjqen5pJ4hRL+q1xTsQMTV4kqbQjOH9NIH09vLrt9S56V73r+6uri6th6f7ReXge/Hp4eD5/Hjz+On94eFiUrIPpfZlAR1d64JDQfcQ4FCmlQEcql3yzYjqvxnI8V+KQmsizOPH8+bO5HtldmGjhsD+8uu9dDQv3F7gBP4/ZT+/Xw+Nt9PwweHg8j2bSgIPCj8KPPXav7wPcI7GZAxfPTf4ejTLP85LX+amoU+crp0kiTSw/EMeL03aaOAp+2J2oYe++i/NRhr0ekFXoXT8+3D48Zr9uHwxZD4OJPt4MgavCQXlHOMSfJJ4bERpJ6TnSyjLPxQle3H9FuPnVTnVO8NiTktpSZrE19vSXN5tmHPxED0H5brvXIFnDUt9IVg9s1sOv54fH6Bf8gGQtmKzDGgePM3oT37PDgEZ2GiswU5HSZTSDUQo2aJTOlCziVgymiQbSjZxJPZrZIUhvWgNuZqMMr3PJ6qFxB5t1cX/VG94PL3o/0VTdPj/8vH18eP51/jzRQRSsQzNZOACXJEEQKukFaQacKZaFEu5S+amM/TDVmgUWPHNxyFoWWblZEts4YRDE4pzVsdXqatKur69h6xqjne717fnt4PwaH66vB+cTi3VzCzp41j+0Mho8Ip5HpWPLOM48GkciozjCKLWDV3/kpLq8SoQW3JnQtMNcHi1al1fL5g1gAjDPOtzkf3NN4aEJFplzi6YdsKCFIYl9qoiXWjPu6WZpEotP89k7K0KeFR78zaHO3GGmZAMzCVPMMuKwFt8jrop9QnxTnWDJ4MgVbzcvDIy0UREvl7O1ItzR83Z+9A+qKVwNRnzq+GE8cuN0p4koVrbolxlf6+zyfilbS8kyXB3N/DlBsrwIlK92uGJGeODLN4n435erZGupZBmufhycwdon0JzxOEpGi7KVz2a97C2x8m/IGpiZhoWz3wcWFa7DfJ3pTRCYqsUSIrazZGkZTv5otq4uuqUNkjW4GVwdHVc7QcsUMuWBN7us2l/um172h4uquEjWTbef6+CX5ArFCJiSpmoIZ8uqMQiwW6ZYwYKZX5Ssm2FB2/YvyZWRKaplKu9jXe5iQJtY0FPLe93uSskam6t+89i5WjLoS8dBWClkWlllzcvbfWO4ZlVxTrKMCoIv2jrudhAN+Jz3rpVthqnNERAn9SfNFqhid4lk3dzcaxU8+8OPXK4Eseg0lBGmHJSkNELt29K3Z+PiITPCNZWsm9urSZmQQ/fbMd6ZmePC5swPI460X6U07ZweVYNMZZqpHT6Ek2b/Mrfz3TnJysWqcPl0aLUJlkCYXDEXAhe50rsYNmw4llXnvEKVKD8vMSMcl5oSdmu1T/DFYhDQKNb/mAo+V8OZWjRgrbRY/Sj8dwwqyCkVnuWZJ4I4VGL+T5fEwqd+GigntNPQQqZsmXGxWfuW3TUIsGkVL/MqIkjWzSC3VtAKHrwKYk0Qatu+DO3YorFHiQyoHQeWb3vUgptOfH80kqPUTylxgSlGtim7GaglxeNBbFt5hag+6CJI1s2NrjsDjuifel6Y5KDLJDKiYkcpT8kgUYGyiVRJELhBkiWJg2SNQk9yGfkjqm9niypgAlf/GC2pu4mae2eciLOr0vXtzW3vx0Ss2MzLDxUgWbZNAzdxEpW4SURoIBWQZcsoxEjPSvxYStdL7S1KIRJNpuCSusvLCsNRsFy5LnaNYT9DazXuECFRdMiGS4DNIp4EqwVqGDtgs6jlBZYjMcMM37J8xVUGwtetVrjCNGHsJh7L1PLTcQgFNIuaroIRq6e2ESttImOaJOPk+yHaMLGwMXuJjLhpnOAUfC/dvDoFDld1bIoZQ2vligS4tuRvE/4AVZf9u0m7iv6L9KhyiemLPMhcqR5zLPQEgfHqyPpq9TBc5UZpolTqBPYG0cKktAeNAyNLJ6/MfV4LdVFrYH0sQCxGqQSxthPNFBfekVX9BrICkKvE9YNwPVlo/DO41XF7tu42schp8wkk6091XPGVYDFmj7BEkkjXh8hs6ieHbL7eAvwtPwxx8YowjNcQgA2gh+UktxQFlNo7XWFzJoyCj3IiSbIMmwibetSlxyVaCDE7zGHZcdRXSSXOL9n6TXVJm2ldG4GlXpjrKykpyF0m3SBA5sQWPXCHg+lqhquuGfZD+BhZuy78y2ZHDvMIWJIQTYQJlpMQklo0ySYf8DWgfQVpe/ydviTFNRwoCBq3ffTobFwr3cMuIywX/iXowkYrDqSnW9J3vRHFeFRKPa0ugMjKUq6NPbwsTNWXWDwEvY2M2hZ7t/vISBYJy6Uq1p4LRA2uQ2P8LpxQUv9418KYGi/BI3s/K6AI4iUyCaSJvrlFYhVmyCE4XYH0j3XdRDH9zzM7s/YT9oJkBVKadcgY4xCKEi8MI2ghcdkkuunlhwpuuaFnhmlxbKz2liIwJfjxbWWmQtBBEvng2rEsUdlhmCwxSYzMVL4g+qKZmY8452HpxT9Go1E6qT+217sw0bRFfXdEsVq6oYvvS3z3gby+g2ZHF3gYe9U4etmkr4SZR0r0sjJO4FipY+b17RGTL8uiqa+CGCXXIZmf6JIG/54s8JACN98aB60Rj3CwHyeubenMskVdOb0TICv2MXdqf9T1C+LSxMWkRURlIB3pBxYJNqyq+CkIswBcP5lx6keZdGwap67r2XFiRb6bpdSzvMRPbc92pOuiywhkYbk61//A1ZosJ9PzkyCUTlPKuZ3mWZt/CZCakBCpbKUSaSdhAu2OreIkU8p2iAw85SVOQoPAhUOhF+LXi2QFYI3TNP24y9fDchhxAxXa4PASHrz6/5osuCoF4aqUIYT4SaCoTSOaREmSqMCKKXg4WUCVpNQL4bhw0fMxZIH/4/ofZkfyhoXIDKyXxKg6NEV4d52ott+rIg7Ev7FwIyYljzInthwviz3pxRwiWe5kDo0cJ+axdDySuRPJgmuOP46sycVhqhttu+Pkew4gpjYXsS4FM93wRq6PK/fh0nQff+ETt8WUPnOTYOuE2UdczXiE8thv0JUftLSzabUovdOUlCIywQU9PkGyTDf5JOnKHSsYJeEocraoBHooYATiWulmwaeaXGiLRmnqhyH4xOrf6+K2EIJjZ08Yfu5K5IwkeS1F/6+WPfhWYMROCMcOJ/9fmq3dsT7J/EGfiRXUdZidHoIzf9gAf94E71b6ry/l8GFWhiWf0gofPTRLmrPwRNYmgO+A89XZqur0J8xBpJ5lOZjzOJG1CYLYqZ8CPte/O1qcSNoeS0aPnXDCCSeccMIJJ5xwwgnfFP8D+4Qq+JHEZOkAAAAASUVORK5CYII=" style="max-width: 100%; max-height: 300px"&gt;&lt;/a&gt;&lt;/div&gt; &lt;div class=info-box&gt;&lt;div&gt;&lt;div style="width: 40%;display: inline-block"&gt;&lt;h5&gt;Original&lt;/h5&gt;&lt;/div&gt; &lt;div style="width: 50%;display: inline-block"&gt;&lt;strong&gt;2362 x 1266px&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;div style=" width: 35%; display: inline-block"&gt;&lt;strong&gt;PNG&lt;/strong&gt;&lt;/div&gt; &lt;div style=" width: 5%;display:inline-block"&gt;&lt;/div&gt; &lt;div style="display: inline-block; width: 25%"&gt;&lt;strong&gt;190.2 kb&lt;/strong&gt;&lt;/div&gt; &lt;div style="width: 30%; display: inline-block; font-size: 17px"&gt;&lt;span class="fa-info-circle fas text-primary" data-content="                    &lt;strong&gt;format:&lt;/strong&gt; PNG&lt;br&gt;                    &lt;strong&gt;is_animated:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;colour_space:&lt;/strong&gt; RGBA&lt;br&gt;                    &lt;strong&gt;has_transparency:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;is_photo:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;width:&lt;/strong&gt; 2362&lt;br&gt;                    &lt;strong&gt;height:&lt;/strong&gt; 1266&lt;br&gt;            " data-title="Image Info" data-toggle=popover&gt;&lt;/span&gt;&amp;nbsp; &lt;a href=https://www.peakhour.io/static/images/security.png target=original title="open original in new window"&gt;&lt;span class="fa-external-link-alt fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt; &lt;div class=info-box&gt;&lt;div&gt;&lt;div style="width: 40%;display: inline-block"&gt;&lt;h5&gt;Optimised&lt;/h5&gt;&lt;/div&gt; &lt;div style="width: 50%;display: inline-block"&gt;&lt;strong&gt;605 x 324px&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;div style="width: 35%; display: inline-block; text-transform: uppercase"&gt; png &lt;/div&gt; &lt;div style="width: 5%; display: inline-block"&gt;&lt;br&gt;&lt;/div&gt; &lt;div style="width: 25%; display: inline-block"&gt; 10.8 kb &lt;/div&gt; &lt;div style="width: 30%; display: inline-block;font-size: 17px"&gt;&lt;span class="fa-info-circle fas text-primary" data-content="                    &lt;strong&gt;format:&lt;/strong&gt; PNG&lt;br&gt;                    &lt;strong&gt;optimize:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;quality:&lt;/strong&gt; 75&lt;br&gt;                    &lt;strong&gt;colour_space:&lt;/strong&gt; RGBA&lt;br&gt;                    &lt;strong&gt;lossless:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;subsampling:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;delay_format:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;strip:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;compression:&lt;/strong&gt; 6&lt;br&gt;            " data-title="Optimised Info" data-toggle=popover&gt;&lt;/span&gt;&amp;nbsp; &lt;a download=security.png.optimised.png href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/6641ec77-2367-4c17-ab27-2447cdc8aceb/img.png title=download&gt;&lt;span class="fa-download fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;a href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/6641ec77-2367-4c17-ab27-2447cdc8aceb/img.png target=6641ec77-2367-4c17-ab27-2447cdc8aceb title="Open in new window"&gt;&lt;span class="fa-external-link-alt fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;div style="width: 35%; display: inline-block; text-transform: uppercase"&gt; jpeg &lt;/div&gt; &lt;div style="width: 5%; display: inline-block"&gt;&lt;br&gt;&lt;/div&gt; &lt;div style="width: 25%; display: inline-block"&gt; 15.4 kb &lt;/div&gt; &lt;div style="width: 30%; display: inline-block;font-size: 17px"&gt;&lt;span class="fa-info-circle fas text-primary" data-content="                    &lt;strong&gt;format:&lt;/strong&gt; JPEG&lt;br&gt;                    &lt;strong&gt;optimize:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;quality:&lt;/strong&gt; 75&lt;br&gt;                    &lt;strong&gt;colour_space:&lt;/strong&gt; RGB&lt;br&gt;                    &lt;strong&gt;lossless:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;subsampling:&lt;/strong&gt; 4:2:0&lt;br&gt;                    &lt;strong&gt;delay_format:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;strip:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;progressive:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;progressive_min_bytes:&lt;/strong&gt; 10240&lt;br&gt;                    &lt;strong&gt;quant_table:&lt;/strong&gt; 3&lt;br&gt;            " data-title="Optimised Info" data-toggle=popover&gt;&lt;/span&gt;&amp;nbsp; &lt;a download=security.png.optimised.jpeg href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/796c932f-a4a1-4a4b-890d-d88fba459c29/img.jpeg title=download&gt;&lt;span class="fa-download fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;a href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/796c932f-a4a1-4a4b-890d-d88fba459c29/img.jpeg target=796c932f-a4a1-4a4b-890d-d88fba459c29 title="Open in new window"&gt;&lt;span class="fa-external-link-alt fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;div style="width: 35%; display: inline-block; text-transform: uppercase"&gt; [webp](/products/image-optimisation-and-transformation/) &lt;/div&gt; &lt;div style="width: 5%; display: inline-block"&gt;&lt;br&gt;&lt;/div&gt; &lt;div style="width: 25%; display: inline-block"&gt; 10.7 kb &lt;/div&gt; &lt;div style="width: 30%; display: inline-block;font-size: 17px"&gt;&lt;span class="fa-info-circle fas text-primary" data-content="                    &lt;strong&gt;save_all:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;duration:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;loop:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;format:&lt;/strong&gt; WEBP&lt;br&gt;                    &lt;strong&gt;optimize:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;quality:&lt;/strong&gt; 75&lt;br&gt;                    &lt;strong&gt;colour_space:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;lossless:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;subsampling:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;delay_format:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;strip:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;method:&lt;/strong&gt; 3&lt;br&gt;                    &lt;strong&gt;kmin:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;kmax:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;allow_mixed:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;minimize_size:&lt;/strong&gt; True&lt;br&gt;            " data-title="Optimised Info" data-toggle=popover&gt;&lt;/span&gt;&amp;nbsp; &lt;a download=security.png.optimised.webp href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/72346c2d-1302-40f0-bb38-027890c5c920/img.webp title=download&gt;&lt;span class="fa-download fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;a href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/72346c2d-1302-40f0-bb38-027890c5c920/img.webp target=72346c2d-1302-40f0-bb38-027890c5c920 title="Open in new window"&gt;&lt;span class="fa-external-link-alt fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;div style="width: 35%;display: inline-block; text-transform: uppercase"&gt;&lt;strong&gt;avif &lt;span class="fa-trophy fas text-primary"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt; &lt;div style="width: 5%; display: inline-block"&gt;&lt;br&gt;&lt;/div&gt; &lt;div style="width: 25%; display: inline-block"&gt;&lt;strong&gt;8.2 kb&lt;/strong&gt;&lt;/div&gt; &lt;div style="width: 30%; display: inline-block;font-size: 17px"&gt;&lt;span class="fa-info-circle fas text-primary" data-content="                    &lt;strong&gt;format:&lt;/strong&gt; AVIF&lt;br&gt;                    &lt;strong&gt;optimize:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;quality:&lt;/strong&gt; 50&lt;br&gt;                    &lt;strong&gt;colour_space:&lt;/strong&gt; RGBA&lt;br&gt;                    &lt;strong&gt;lossless:&lt;/strong&gt; False&lt;br&gt;                    &lt;strong&gt;subsampling:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;delay_format:&lt;/strong&gt; None&lt;br&gt;                    &lt;strong&gt;strip:&lt;/strong&gt; True&lt;br&gt;                    &lt;strong&gt;compression:&lt;/strong&gt; 6&lt;br&gt;            " data-title="Optimised Info" data-toggle=popover&gt;&lt;/span&gt;&amp;nbsp; &lt;a download=security.png.optimised.avif href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/11a20ace-cd35-4f59-91f7-2794c8650815/img.avif title=download&gt;&lt;span class="fa-download fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&amp;nbsp; &lt;a href=/page-weight/result/41377868-5104-4eaf-9776-a9a682a5e8f5/images/11a20ace-cd35-4f59-91f7-2794c8650815/img.avif target=11a20ace-cd35-4f59-91f7-2794c8650815 title="Open in new window"&gt;&lt;span class="fa-external-link-alt fas text-primary"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Benefits of Peakhour Automatic Image Optimisation&lt;/h2&gt;
&lt;p&gt;Peakhour image optimisation is integrated into your website so you can reduce traffic, speed up page loads and remove
manual image preparation from the design workflow.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Transforming images on the Peakhour edge enables agility and offloads origin work.&lt;/li&gt;
&lt;li&gt;User experience is improved through faster-loading pages, without a separate workflow for image optimisation.&lt;/li&gt;
&lt;li&gt;Take advantage of new image formats, as supported by end users' browsers, to improve the page load experience.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Peakhour image optimisation runs on Peakhour Edge. Images are optimised as they pass through the Peakhour network, and
optimised versions are cached for reuse. Peakhour image optimisation also works with &lt;a href="/blog/cdn-origin-shield"&gt;Origin Shield&lt;/a&gt;,
with the original and transformed images cached appropriately. This reduces origin hits and bandwidth while speeding up
image delivery.&lt;/p&gt;</content><category term="Features"></category><category term="Web Performance"></category><category term="Caching"></category><category term="Core Web Vitals"></category><category term="CDN"></category><category term="Drupal"></category><category term="Rate Limiting"></category></entry><entry><title>Drupal full page caching module</title><link href="https://www.peakhour.io/blog/drupal-purge-module/" rel="alternate"></link><published>2022-10-05T13:00:00+11:00</published><updated>2022-10-05T13:00:00+11:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2022-10-05:/blog/drupal-purge-module/</id><summary type="html">&lt;p&gt;We're excited to announce our Drupal 8/9 caching module, read on for more details.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Drupal is an open source content management system (CMS) widely used by Australian government websites. For example,
GovCMS is a customised version of Drupal. Peakhour now provides a purge module for Drupal 8/9, extending our
existing Drupal support.&lt;/p&gt;
&lt;p&gt;The Peakhour Purge module extends the Drupal Purge module. The Purge module provides a standardised way of
integrating third party CDNs, like Peakhour, with Drupal's native full page caching support.
Drupal's native support is suitable for small websites, but has a number of drawbacks. These drawbacks include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doesn't support the Vary header.&lt;/li&gt;
&lt;li&gt;Is served by PHP, so it doesn't scale well.&lt;/li&gt;
&lt;li&gt;Runs on the same server as Drupal, so geographic latency is still an issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Peakhour's edge cache and delivery layer &lt;strong&gt;removes these issues before requests reach origin&lt;/strong&gt;, and also adds
&lt;strong&gt;image/content optimisation and website security.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Default Caching&lt;/h2&gt;
&lt;p&gt;Since version 8, Drupal has supported cache tags to provide efficient,
targeted invalidation of content for anonymous browser sessions. In this context, anonymous means a user that does
not have a Drupal Session cookie. Peakhour supports cache tags for all sites, a feature some competitors
reserve for 'Enterprise' plans.&lt;/p&gt;
&lt;p&gt;Cache tags are great, but another default setting is not. That setting is to add a:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Vary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cookie&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Header to the page response to make sure that logged-in users don't get cached pages. The Vary
header informs a cache that different content may be served from origin based on the value in the Cookie
header sent by the browser.&lt;/p&gt;
&lt;p&gt;This is fine if you are using Drupal with no third party javascript libraries. If you do
use third party libraries, it can render page caching close to useless. For example, drupal.org itself uses
perimeterx for bot detection, which results in a unique session cookie being set on the very first request.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/drupal-org-first-request.jpg" width="100%" alt="The cookie set by perimiterx"/&gt;
&lt;em&gt;The first request to drupal.org results in a unique cookie being set by perimiterx&lt;/em&gt;
&lt;/div&gt;

&lt;p&gt;If you use Google analytics, Facebook, or any of a wide array of popular third party libraries, the same
thing can happen.&lt;/p&gt;
&lt;p&gt;This means only the &lt;strong&gt;very first&lt;/strong&gt; request from the user could be served from a general
page cache. Hit rates would be virtually zero.&lt;/p&gt;
&lt;h2&gt;Fix the Vary issue with Skip Cache on Cookie&lt;/h2&gt;
&lt;p&gt;Peakhour gives you a way to work around this. The first step is to disable the &lt;strong&gt;Vary: Cookie&lt;/strong&gt; header. Then, to
make sure any user with a Drupal Session bypasses the cache, use Peakhour's &lt;strong&gt;Skip Cache on Cookie&lt;/strong&gt; feature.
As soon as Drupal sets a session cookie, eg when someone logs in, Peakhour will pass requests through to the origin.
Full instructions on how to do this are provided on our &lt;a href="/docs/how-to-guides/integrations/drupal/"&gt;drupal module documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;eCommerce Drupal sites&lt;/h2&gt;
&lt;p&gt;If you are running an ecommerce store, or some other type of site that
might serve customised information on a page, for example a mini cart with cart count/information,
then you will have to do custom development to continue caching pages.
A workaround for a mini cart would be to make it load via Ajax or to use local browser storage,
and &lt;strong&gt;Peakhour assists in making that happen&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Future features&lt;/h2&gt;
&lt;p&gt;Hopefully in the future Drupal will support setting its own cookie for varying the cache, in a similar manner to
Magento 2. eg X-Drupal-Vary, this would allow Peakhour to store multiple versions of a page to serve to different users.
For example, a user in Germany might get a version of a page in German with German currency.&lt;/p&gt;</content><category term="CMS"></category><category term="Drupal"></category><category term="Caching"></category><category term="CDN"></category><category term="Core Web Vitals"></category><category term="WordPress"></category><category term="Rate Limiting"></category></entry><entry><title>IP Threat Intelligence</title><link href="https://www.peakhour.io/blog/ip-threat-intelligence/" rel="alternate"></link><published>2022-07-15T13:00:00+10:00</published><updated>2022-07-15T13:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-07-15:/blog/ip-threat-intelligence/</id><summary type="html">&lt;p&gt;Comprehensive guide to IP threat intelligence for modern application security platforms. Learn how managed IP reputation lists and threat intelligence feeds protect applications from known malicious sources and emerging threats.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/learning/threat-detection/how-to-use-threat-intelligence/"&gt;Threat intelligence&lt;/a&gt; helps organisations make earlier decisions about cyber attacks. One of the
most common forms of threat intelligence in cyber security is &lt;a href="/products/ip-intelligence/"&gt;IP reputation&lt;/a&gt; lists. For example, a given
IP address might have a poor reputation for spam, &lt;a href="/products/ddos-protection/"&gt;ddos attacks&lt;/a&gt;, malware, and several other categories. IP reputation
lists often form a front line of defence in Web Application Firewalls and cyber security solutions.&lt;/p&gt;
&lt;h2&gt;How Peakhour uses IP threat intelligence&lt;/h2&gt;
&lt;p&gt;Peakhour supports threat intelligence across more than 20 categories, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Active DDoS attacks&lt;/li&gt;
&lt;li&gt;Brute forcing&lt;/li&gt;
&lt;li&gt;Active attackers&lt;/li&gt;
&lt;li&gt;Computers infected with malware&lt;/li&gt;
&lt;li&gt;Anonymous Proxies&lt;/li&gt;
&lt;li&gt;Forum Spammers&lt;/li&gt;
&lt;li&gt;TOR anonymous users&lt;/li&gt;
&lt;li&gt;IPs with poor reputation&lt;/li&gt;
&lt;li&gt;Unroutable and unassigned IPs&lt;/li&gt;
&lt;li&gt;Robots and web scrapers&lt;/li&gt;
&lt;li&gt;Datacenter&lt;/li&gt;
&lt;li&gt;Hosting Providers&lt;/li&gt;
&lt;li&gt;Crawlers&lt;/li&gt;
&lt;li&gt;And more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Customers have access to all 10 lists, which can be enabled as blocklists or used as part of a custom
firewall rule, rate limiting rule, or page rule. For example, you may want to disallow POSTs from forum spammers, rate
limit proxies, and outright deny traffic from known brute-forcing IPs.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/spammers-cant-post.jpg" width="100%" alt="Creating a spammer can't post rule"/&gt;
&lt;em&gt;Creating a spammer can't post rule&lt;/em&gt;
&lt;/div&gt;

&lt;h2&gt;How does Peakhour assemble these lists?&lt;/h2&gt;
&lt;p&gt;The IP reputation lists are sourced from third-party sources, including open source intelligence feeds (OSINT),
commercial feeds, community feeds, and our own threat intelligence. IPs are categorised into our pre-defined lists and
made available to the &lt;a href="/docs/firewall/"&gt;WAF&lt;/a&gt; and &lt;a href="/docs/configuration/rules/"&gt;rules&lt;/a&gt;
engine. Each list is re-evaluated and updated based on the data provider's update schedule; some are
updated every minute.&lt;/p&gt;
&lt;p&gt;Internally managed feeds include bot sources that are verified using reverse DNS lookups, PTR record lookups,
and WHOIS verification (such as Facebook IPs). WAF hits across customers are consolidated and made available as
the Active Attacker list, which is updated in near real time. Our Malware and C&amp;amp;C nodes lists are generated from
various partnerships.&lt;/p&gt;
&lt;p&gt;The Anonymous Proxies list contains known open proxies, services that relay traffic without authentication, whilst our
targeted VPN list tracks known third-party VPN services.&lt;/p&gt;
&lt;p&gt;IPs are fed back into our system for re-evaluation to help identify emerging behaviour within our customer data.&lt;/p&gt;
&lt;h2&gt;Data visualisation&lt;/h2&gt;
&lt;p&gt;Requests from IPs that match a blocklist are tagged with the lists they belong to. Firewall events are
enriched with this information, providing visibility into security threats. This context helps you decide how to
handle requests, whether they should be blocked, rate limited or observed.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/ip-reputation-events.jpg" width="100%" alt="Ip reputation events"/&gt;
&lt;em&gt;Firewall events generated by reputation matches&lt;/em&gt;
&lt;/div&gt;

&lt;p&gt;Blocks generated by our reputation lists can also be viewed in our analytics section.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/blog/ip-reputation-analytics.jpg" width="100%" alt="Ip reputation events"/&gt;
&lt;em&gt;Firewall events generated by reputation matches&lt;/em&gt;
&lt;/div&gt;

&lt;h2&gt;Future work&lt;/h2&gt;
&lt;p&gt;We are working on additional data sources to further refine and expand our lists. This includes further
segregating our data centre lists and categorising IPs that appear on several lists. We are also introducing
our threat research centre to discover possible threats and enrich data blocked only by our WAF.&lt;/p&gt;
&lt;p&gt;IP threat intelligence adds another layer of security to a cyber defence system. Peakhour sources and
maintains up-to-date threat intelligence, helping our clients better protect themselves against would-be attackers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;See how Peakhour's IP threat intelligence supports the first line of defence for your applications. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to discuss your security requirements.&lt;/em&gt;&lt;/p&gt;</content><category term="Security"></category><category term="Threat Detection"></category><category term="DDoS"></category><category term="Rate Limiting"></category><category term="API Security"></category><category term="Bot Management"></category><category term="Networking"></category></entry><entry><title>CVE-2022-26134</title><link href="https://www.peakhour.io/blog/cve202226134-atlassian-confluence/" rel="alternate"></link><published>2022-06-02T00:00:00+10:00</published><updated>2022-06-02T00:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-06-02:/blog/cve202226134-atlassian-confluence/</id><summary type="html">&lt;p&gt;Peakhour clients are protected against CVF-2022-26134 Atlassian Confluence RCE&lt;/p&gt;</summary><content type="html">&lt;p&gt;On June 2, 2022, &lt;a href="https://www.volexity.com/blog/2022/06/02/zero-day-exploitation-of-atlassian-confluence/"&gt;Volexity&lt;/a&gt; announced active exploitation of Atlassian Confluence. The issue is a
Remote Code Execution vulnerability via OGNL injection, tracked as &lt;a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-26134"&gt;CVE-2022-26134&lt;/a&gt;, and impacts all
Confluence Server and Data Center versions greater than 1.3.0.&lt;/p&gt;
&lt;p&gt;Atlassian has released its &lt;a href="https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html"&gt;security advisory&lt;/a&gt;
with patches and mitigation instructions.&lt;/p&gt;
&lt;p&gt;Peakhour WAF clients are already protected. Since the vulnerability was announced on June 2nd, we have observed a 200% increase in OGNL-based exploit attempts.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Peakhour's Web Application Firewall helps protect applications against zero-day exploitation attempts such as CVE-2022-26134. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to secure your applications.&lt;/em&gt;&lt;/p&gt;</content><category term="Security"></category><category term="API Security"></category><category term="DDoS"></category><category term="Rate Limiting"></category><category term="Application Security"></category><category term="Credential Stuffing"></category><category term="Features"></category></entry><entry><title>Intelligent Rate Limiting</title><link href="https://www.peakhour.io/blog/rate-limiting/" rel="alternate"></link><published>2022-05-16T13:00:00+10:00</published><updated>2022-05-16T13:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-05-16:/blog/rate-limiting/</id><summary type="html">&lt;p&gt;Comprehensive guide to intelligent rate limiting for modern application security platforms. Learn how sophisticated rate limiting protects APIs and web applications from abuse, DDoS attacks, and automated threats whilst maintaining optimal user experience.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Rate limits protect web applications from clients making excessive requests. Peakhour.IO supports rate limits
with flexible controls for selecting which clients are limited and which type of limit applies.&lt;/p&gt;
&lt;h1&gt;What kinds of attacks are stopped by rate limiting&lt;/h1&gt;
&lt;p&gt;When an application is protected with rate limiting, the main attack patterns are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brute force and enumeration attacks&lt;/li&gt;
&lt;li&gt;Denial of Service (DoS) and Distributed Denial of Service (DDoS)&lt;/li&gt;
&lt;li&gt;Site scraping&lt;/li&gt;
&lt;li&gt;Vulnerability scanners&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What else can rate limiting protect&lt;/h2&gt;
&lt;p&gt;Public APIs and authenticated APIs can be abused or misused. Sensible rate limit policies on these endpoints can
reduce attack traffic and help maintain service availability. Rate limiting can protect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Overzealous 'good bots'&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;How does it work?&lt;/h1&gt;
&lt;p&gt;Rate limiting focuses on a connecting client and their IP address. The following measures can be used to track
client requests for rate limiting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concurrent connections&lt;/li&gt;
&lt;li&gt;Connections per interval&lt;/li&gt;
&lt;li&gt;Hits per interval&lt;/li&gt;
&lt;li&gt;HTTP 4xx responses per interval&lt;/li&gt;
&lt;li&gt;HTTP 5xx responses per interval&lt;/li&gt;
&lt;li&gt;Custom criteria&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How granular can rate limiting be?&lt;/h2&gt;
&lt;p&gt;Using wirefilter rules, rate limiting can identify clients from both the HTTP request and response, allowing
rate limits to be separated by endpoint or behaviour. For example, the URL /api can be rate limited separately from
the /login endpoint. Rate limits can also be set on response codes; for example, the endpoint /search can be
protected from scraping by rate limiting clients with excessive 4xx response codes.&lt;/p&gt;
&lt;h2&gt;What types of criteria can be used to define rate limits?&lt;/h2&gt;
&lt;p&gt;Rate limits can include any information defined in an HTTP request and response, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;Query string&lt;/li&gt;
&lt;li&gt;Headers&lt;/li&gt;
&lt;li&gt;Response codes&lt;/li&gt;
&lt;li&gt;GeoIP information such as ASN or country code&lt;/li&gt;
&lt;li&gt;Parsed user agent information allowing different rules for search engines vs generic 'bots'&lt;/li&gt;
&lt;li&gt;Metadata we make available from our BOT protection service&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Defining your rate limits&lt;/h2&gt;
&lt;p&gt;Picking sensible rate limits is difficult without adequate analytics on how the web application is typically used.
The Peakhour dashboard includes rate-based analytics to help with setup.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/client-access-rates.png" class="img-responsive"/&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Peakhour's Application Security Platform combines high-performance delivery and cache capabilities with security controls for applications and APIs. It maintains caching performance while applying advanced threat protection. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to discuss how rate limiting can improve application performance and security posture.&lt;/em&gt;&lt;/p&gt;</content><category term="DDoS"></category><category term="Rate Limiting"></category><category term="DDoS"></category><category term="API Security"></category><category term="Bot Management"></category><category term="Application Security"></category><category term="Threat Detection"></category></entry><entry><title>Rate limiting</title><link href="https://www.peakhour.io/blog/rate-limiting-how-it-works/" rel="alternate"></link><published>2022-05-16T13:00:00+10:00</published><updated>2022-05-16T13:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-05-16:/blog/rate-limiting-how-it-works/</id><summary type="html">&lt;p&gt;How can rate limiting protect your web application and the key items to consider when enabling.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Rate limits are a useful control for protecting a web application from abuse. When setting them for a web application,
the key elements to consider are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What endpoints on the web application require protecting?&lt;/li&gt;
&lt;li&gt;Do different endpoints require separate handling?&lt;/li&gt;
&lt;li&gt;What is the normal request rate for the entire application over a time period?&lt;/li&gt;
&lt;li&gt;How many concurrent connections are typically used by your clients?&lt;/li&gt;
&lt;li&gt;What errors does your API endpoint return in response to requests?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before setting those policies, it helps to understand how rate limits protect an application from abuse
or misuse, the types of attacks they can reduce, and how the &lt;a href="/learning/api-protection/what-is-api-rate-limiting/"&gt;rate limiting&lt;/a&gt; algorithm makes
decisions.&lt;/p&gt;
&lt;h1&gt;What kinds of attacks are stopped by rate limiting?&lt;/h1&gt;
&lt;p&gt;When protecting an application with rate limiting, common attack scenarios include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brute force and enumeration attacks&lt;/li&gt;
&lt;li&gt;Denial of Service (DoS) and Distributed Denial of Service (DDoS)&lt;/li&gt;
&lt;li&gt;Site scraping&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What else can rate limiting protect?&lt;/h2&gt;
&lt;p&gt;Public APIs and authenticated APIs can be subject to both abuse and misuse. Sensible rate limit policies can be applied
on these endpoints to help prevent attacks and maintain service availability. Rate limiting can help protect these endpoints.&lt;/p&gt;
&lt;h1&gt;How does rate limiting work with user logins?&lt;/h1&gt;
&lt;p&gt;A well designed web application should allow only a limited number of failed login attempts
before locking an account and requiring a password reset. This is designed to protect against
&lt;a href="/learning/security/brute-force/"&gt;brute force&lt;/a&gt; attacks against an account. Bots commonly attempt to brute force logins to
WordPress and other popular web applications. Determined attackers can also attempt to brute
force API login endpoints.&lt;/p&gt;
&lt;p&gt;Rate limiting on a login page can be applied to the IP address of a user attempting to log in.
By rate limiting by IP address, you can limit both password brute force attacks and simpler
username enumeration attempts.&lt;/p&gt;
&lt;p&gt;Using Peakhour.IO rate limiting, responses to requests can be monitored and IPs blocked
for administrator-defined periods. This saves origin server resources and stops repeated
attempts before they reach the application.&lt;/p&gt;
&lt;h1&gt;How could API rate limiting work?&lt;/h1&gt;
&lt;p&gt;APIs are ubiquitous across the modern web. Single Page Applications (SPAs) can be built almost
entirely on REST or GraphQL APIs, while legacy applications often use form submits. Even when
browsing this blog, you have consumed a range of APIs.&lt;/p&gt;
&lt;p&gt;Because APIs are often publicly available, rate limits are commonly used to reduce abuse. &lt;a href="/blog/introducing-advanced-rate-limiting/"&gt;Rate limiting for APIs&lt;/a&gt;
can protect against malicious attacks. An attacker could script a bot to perform many API calls and make the service
unavailable for other users, causing unplanned downtime - a layer 7 DoS or DDoS attack.&lt;/p&gt;
&lt;h3&gt;APIs&lt;/h3&gt;
&lt;p&gt;Public and private APIs can be subject to abuse or misuse. Public APIs are discoverable by anyone and can
be scripted for data mining or attacks. Rate limiting these endpoints
based on fair use policies is commonplace. Keeping track of this within an endpoint can be expensive, so handling
it through Peakhour can offload that work from developers.&lt;/p&gt;
&lt;h3&gt;Overzealous 'good bots'&lt;/h3&gt;
&lt;p&gt;Peakhour has seen websites where up to 65% of requests come from automated bots. These bots are typically indiscriminate
when mining information, and they do not carry the operational cost when your site slows down or fails. Rate limiting good
bots separately from your main users helps ensure these crawlers do not stop your site from generating revenue.&lt;/p&gt;
&lt;h1&gt;How is rate limiting implemented?&lt;/h1&gt;
&lt;p&gt;Rate limiting is typically implemented using several common methods:&lt;/p&gt;
&lt;h2&gt;Fixed window&lt;/h2&gt;
&lt;p&gt;Window-based rate limiting is the simplest to understand. Fixed window limits are easy to
define, such as 5,000 requests per 60 minutes. Fixed window rate limiting is subject to
spikes at the edges of the window. For example, 5,000 requests in the first 5 minutes
of the window may overwhelm a service.&lt;/p&gt;
&lt;h2&gt;Sliding window&lt;/h2&gt;
&lt;p&gt;A sliding window keeps much of the simplicity of a fixed window, but
uses a rolling window. This allows bursts to be smoothed.&lt;/p&gt;
&lt;h2&gt;Token bucket&lt;/h2&gt;
&lt;p&gt;A token bucket is an algorithm where tokens are placed into a fixed-capacity bucket. Tokens could be defined as bytes transferred
or hits to an API. When a request is considered for rate limiting, tokens are removed from the bucket. If the bucket has a
sufficient quantity of tokens, the request can proceed. If there are insufficient tokens, the request is considered to be
non-conforming. Non-conforming requests are dropped.&lt;/p&gt;
&lt;h2&gt;Leaky bucket&lt;/h2&gt;
&lt;p&gt;Leaky buckets are a mirror image of token buckets. Instead of removing tokens from a bucket, tokens are added to a bucket.
Tokens are removed from the bucket (leaks) at a fixed rate. When a request is considered for rate limiting, it is compared
to the number of tokens in the bucket. If the bucket is full, the request is considered non-conforming and is dropped.&lt;/p&gt;
&lt;p&gt;If rate limiting is something you need to do to protect and secure your website,
reach out to see how we can help.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Learn how Peakhour's Application Security Platform can improve your application's performance and security. &lt;a href="/contact-sales/"&gt;Contact our team&lt;/a&gt; to get started.&lt;/em&gt;&lt;/p&gt;</content><category term="DDoS"></category><category term="Rate Limiting"></category><category term="API Security"></category><category term="DDoS"></category><category term="Application Security"></category><category term="Web Performance"></category><category term="Bot Management"></category></entry><entry><title>Request collapsing</title><link href="https://www.peakhour.io/blog/request-collapsing/" rel="alternate"></link><published>2022-05-16T11:00:00+10:00</published><updated>2022-05-16T11:00:00+10:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-05-16:/blog/request-collapsing/</id><summary type="html">&lt;p&gt;Request collapsing - saving your origin by reducing concurrent requests and re-using responses for resources.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Request collapsing protects busy origin servers that serve changing content. On a high traffic site, a cache miss
after content expires can amplify one expired resource into many simultaneous origin requests. This behaviour is commonly
called a cache stampede or dog-piling.&lt;/p&gt;
&lt;p&gt;When request collapsing is enabled, only a single request is sent to an origin server for a given resource, then the
resulting body is used to satisfy pending requests.&lt;/p&gt;
&lt;p&gt;This can stop a popular cached resource from causing a flood of requests to an origin server when it expires.
On high traffic sites, enabling the feature for the right resources can smooth request volume and traffic to origin servers.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/request-collapsing.png" class="img-responsive"&gt;&lt;/p&gt;
&lt;h1&gt;How it works&lt;/h1&gt;
&lt;p&gt;Request collapsing is implemented internally using &lt;a href="/blog/cache-keys/"&gt;cache keys&lt;/a&gt; and queues.
Cache keys are used as keys to a map, with client requests tracked using a queue. Secondary response keys
are then used to match waiting client requests to origin responses. Matching requests can then be fulfilled using the
same response.&lt;/p&gt;
&lt;p&gt;Failed requests are retried in the same manner.&lt;/p&gt;
&lt;p&gt;If a response to an active request is marked as private with &lt;code&gt;Cache-Control: private&lt;/code&gt; or &lt;code&gt;Set-Cookie&lt;/code&gt;, then all queued
and future matching requests will go directly to the origin without trying to match them.&lt;/p&gt;
&lt;p&gt;This implementation allows Peakhour to serialise requests to an origin, so it's important to enable the feature only on
resources that you know will be cacheable, either through cache-control headers or Peakhour configuration.&lt;/p&gt;
&lt;h1&gt;How do you know its working?&lt;/h1&gt;
&lt;p&gt;Request collapsing can be verified with Debug enabled and the cache-status header in the response. A collapsed request
looks like the example below, with 'collapsed' at the end.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;cache-status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;peakhour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;io&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;uri-miss&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://website.com/home-eco.jpg&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;86400&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;collapsed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;How its used in practice?&lt;/h1&gt;
&lt;h2&gt;Image optimisation&lt;/h2&gt;
&lt;p&gt;Peakhour.IO uses request collapsing internally for image transforms. The feature ensures we only transform a single image
when a resource expires on the edge, reducing latency sensitive image transformation work, client transform costs and
avoidable delays for end users.&lt;/p&gt;
&lt;h2&gt;Dynamic page caching&lt;/h2&gt;
&lt;p&gt;Request collapsing is a good fit when enabling caching of expensive dynamically written pages. Peakhour.IO
can cache server heavy WordPress, Magento, PrestaShop, Drupal and other platforms via our caching plugin. The plugin
keeps the CDN in sync by notifying us when content changes.&lt;/p&gt;
&lt;p&gt;Content still needs to change during busy periods such as sales or item purchases. During these periods
servers can be overwhelmed when pages incur a cache miss. Request collapsing can help smooth out this traffic and maintain
response times for users.&lt;/p&gt;</content><category term="Caching"></category><category term="Caching"></category><category term="CDN"></category><category term="Rate Limiting"></category><category term="Drupal"></category></entry><entry><title>Cdn-Cache-Control</title><link href="https://www.peakhour.io/blog/cdn-cache-control-header/" rel="alternate"></link><published>2022-02-28T13:00:00+11:00</published><updated>2022-02-28T13:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-02-28:/blog/cdn-cache-control-header/</id><summary type="html">&lt;p&gt;CDN-Cache-Control is a proposed new header to augment the venerable Cache-Control. Its aim is to make controlling caching easier as CDNs become ubiquitous.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Caching headers are easy to get wrong. Public resources may be cached in one layer, while the server
configuration prevents an otherwise cacheable resource from being stored where you expect.&lt;/p&gt;
&lt;p&gt;Controlling caching without a service like Peakhour usually means working directly with Cache-Control headers.
This header has a wide range of fields and directives. Each one tells downstream clients (e.g., proxies, shared caches, and end browsers)
how to handle caching for a particular resource.&lt;/p&gt;
&lt;p&gt;Getting this right can be complicated, and it can become brittle when web server configuration also affects the response.&lt;/p&gt;
&lt;h2&gt;Enter CDN-Cache-Control&lt;/h2&gt;
&lt;p&gt;CDN-Cache-Control is a recently proposed header specified in
&lt;a href="https://datatracker.ietf.org/doc/html/draft-cdn-control-header-01"&gt;https://datatracker.ietf.org/doc/html/draft-cdn-control-header-01&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The draft RFC states:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;specification&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;defines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;convention&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HTTP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;header&lt;/span&gt;
&lt;span class="nv"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;directives&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;controlling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;caching&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;targeted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;
&lt;span class="nv"&gt;specific&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;caches&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;classes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;caches&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;also&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;defines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;such&lt;/span&gt;
&lt;span class="nv"&gt;header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;field&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;targeted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="nv"&gt;Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Delivery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Network&lt;/span&gt;]&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;learning&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;cdn&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;CDN&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;caches&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What does this mean in practice? Imagine a Magento application where pages should be cacheable by a shared cache
but not by a browser. A Cache-Control header could look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: max-age=0, s-max-age=600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells browser caches not to reuse the response, while shared caches may cache it for 600 seconds.&lt;/p&gt;
&lt;p&gt;What if the application does not want every shared cache to store the resource, because the application already sends purges
to the cache when content changes?&lt;/p&gt;
&lt;p&gt;Cache-Control does not give you that separation. The header above enables any shared cache to store the resource
for the specified time. With CDN-Cache-Control, the application could instead send:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: max-age=0, s-max-age=60
CDN-Cache-Control: max-age=3600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells the browser not to cache the page, allows a shared cache to keep the page for 60s,
and allows the CDN to keep it for one hour.&lt;/p&gt;
&lt;h2&gt;Targeted CDN-Cache-Control&lt;/h2&gt;
&lt;p&gt;What if you need to target a specific CDN only? Use the provider's targeted CDN-Cache-Control header.&lt;/p&gt;
&lt;p&gt;For example, Peakhour-CDN-Cache-Control instructs Peakhour only to cache the resource.
Other CDNs in the request path will not honour this header.&lt;/p&gt;
&lt;h2&gt;Header format&lt;/h2&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;p&gt;The following header fields instruct a CDN cache
to consider the response fresh for 600 seconds, other shared caches
for 120 seconds, and any remaining caches for 60 seconds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These header fields instruct a CDN cache to consider the
response fresh for 600 seconds, while all other caches are
prevented from storing it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: no-store
CDN-Cache-Control: max-age=600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because CDN-Cache-Control is not present, this header field
prevent all caches from storing the response:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: no-store
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Whereas these prevent all caches except CDN caches from
storing the response:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Cache-Control: no-store
CDN-Cache-Control: none
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(note that 'none' is not a registered cache directive; it is used here to
avoid sending a header field with an empty value, because such a
header might not be preserved in all cases).&lt;/p&gt;</content><category term="Learning"></category><category term="Caching"></category><category term="CDN"></category><category term="Rate Limiting"></category><category term="Drupal"></category><category term="Web Performance"></category></entry><entry><title>Cache-Status</title><link href="https://www.peakhour.io/blog/cdn-cache-status-header/" rel="alternate"></link><published>2022-02-25T13:00:00+11:00</published><updated>2022-02-25T13:00:00+11:00</updated><author><name>AC</name></author><id>tag:www.peakhour.io,2022-02-25:/blog/cdn-cache-status-header/</id><summary type="html">&lt;p&gt;Cache-Status is a proposed standard header to provide visibility into how caching providers interact and handle a request.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Diagnosing &lt;a href="/learning/cdn/"&gt;CDN&lt;/a&gt; caching can be complex, with multiple cache layers, Origin Shielding, and local caching.
Understanding how these layers interact can mean spending weeks working through RFCs for the
finer details of ETag, Cache-Control, and Last-Modified headers - before you even account for advanced controls
that override them.&lt;/p&gt;
&lt;p&gt;When you have a problem, or are trying to optimise caching, the first thing you need is visibility into how a request was handled.&lt;/p&gt;
&lt;p&gt;This is where the new Cache-Status header helps. The new draft RFC, RFC draft-ietf-httpbis-cache-header-08, aims to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;aide&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debugging&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;standardising&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;various&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;standard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;used&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;major&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CDN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;semantics&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;these&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;often&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unclear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vary&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;between&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;implementations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The draft RFC proposes a new header, Cache-Status, with a uniform format for showing how multiple
caching providers interact and handle a request. The Cache-Status header forms a list. Each member of the list
represents a cache that has handled the request, and the last member belongs to the cache that most recently
served the user. The header is only applicable to responses directly generated
by an origin server. Each member can add a parameter indicating how it handled the request.&lt;/p&gt;
&lt;p&gt;A Cache-Status header looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;OriginCache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;1100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;CDN Company Here&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;uri-miss&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is formatted and labelled, with each cache in the line separated in list format by a ','.&lt;/p&gt;
&lt;h6&gt;The format of the Cache-Status header is a list comprising of the following possible parameters:&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;hit&lt;/strong&gt;          = boolean&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fwd&lt;/strong&gt;          = (bypass, method, uri-miss, vary-miss, request, stale, partial)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fwd-status&lt;/strong&gt;   = integer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ttl&lt;/strong&gt;          = integer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;stored&lt;/strong&gt;       = boolean&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;collapsed&lt;/strong&gt;    = boolean&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;key&lt;/strong&gt;          = string&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;detail&lt;/strong&gt;       = token / string&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What the parameters mean&lt;/h2&gt;
&lt;h3&gt;Hit&lt;/h3&gt;
&lt;p&gt;The hit parameter signifies that a request was satisfied by the cache. It is a boolean parameter meaning
that its presence indicates a cache hit.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Peakhour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Fwd&lt;/h3&gt;
&lt;p&gt;The Fwd parameter indicates when a response was forwarded to an origin server - and why. The Fwd parameter
contains one of the following arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bypass&lt;/strong&gt; - The cache was configured to not handle this request&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;method&lt;/strong&gt; - The request method's semantics require the request to be
   forwarded&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uri-miss&lt;/strong&gt; - The cache did not contain any responses that matched
   the request URI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vary-miss&lt;/strong&gt; - The cache contained a response that matched the
   request URI, but could not select a response based upon this
   request's headers and stored Vary headers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;miss&lt;/strong&gt; - The cache did not contain any responses that could be used
   to satisfy this request (to be used when an implementation cannot
   distinguish between uri-miss and vary-miss)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;request&lt;/strong&gt; - The cache was able to select a fresh response for the
   request, but the request's semantics (e.g., Cache-Control request
   directives) did not allow its use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;stale&lt;/strong&gt; - The cache was able to select a response for the request,
   but it was stale&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;partial&lt;/strong&gt; - The cache was able to select a partial response for the
   request, but it did not contain all of the requested ranges (or
   the request was for the complete response)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Peakhour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;uri-miss&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Fwd-status&lt;/h3&gt;
&lt;p&gt;The fwd-status parameter indicates the status code the next hop returned in response to the request. It is only
meaningful when "fwd" is present. For example, a complete miss would look like &lt;em&gt;fwd=uri-miss&lt;/em&gt;
and the HTTP status code of the downstream response would be supplied in the fwd-status:&lt;/p&gt;
&lt;p&gt;The following example shows that the cache did not satisfy the request and that the downstream server
indicated an HTTP 304 response - HTTP Not Modified.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Peakhour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;uri-miss&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd-status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;304&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;ttl&lt;/h3&gt;
&lt;p&gt;Each cache item is associated with a lifetime, referred to as the Time To Live (TTL). A TTL is in seconds
and indicates the remaining  &lt;em&gt;freshness&lt;/em&gt; of the resource. This value is calculated by the cache.&lt;/p&gt;
&lt;p&gt;For example, a cache hit showing that the resource has a &lt;em&gt;freshness&lt;/em&gt; of 376 seconds.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ExampleCache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;376&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another example shows a cache hit with &lt;em&gt;negative freshness&lt;/em&gt;  - a stale resource.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ExampleCache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-412&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;stored&lt;/h3&gt;
&lt;p&gt;Indicates whether the received response was stored by the cache. This example shows a cache miss and the
cache storing the response for the next hit.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ExampleCache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;uri-miss&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stored&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;collapsed&lt;/h3&gt;
&lt;p&gt;Indicates whether the received response was collapsed with another request.&lt;/p&gt;
&lt;h3&gt;key&lt;/h3&gt;
&lt;p&gt;The key is the lookup index into a cache. Cache keys convey a representation of how the cache will
look up the resource used for the response. The cache key is implementation-specific.&lt;/p&gt;
&lt;p&gt;This example shows a cache hit, the cache key and secondary key, and the remaining TTL of the resource.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;cache-status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;peakhour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;io&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://example.com/calendar.css&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secondary-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;encoding::gzip&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;30674859&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;detail&lt;/h3&gt;
&lt;p&gt;Allows additional implementation-specific information not captured by other parameters.&lt;/p&gt;
&lt;h3&gt;Multiple layers of caching&lt;/h3&gt;
&lt;p&gt;The header allows multiple layers of caching. For example, a global CDN may sit in front of a local varnish server.
Each cache appends its cache-status to the header, so the last item is the closest cache
to the actual application and the first item is the closest cache to the accessing user.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Cache-Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;OriginCache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;1100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;CDN Company Here&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;545&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;There are security implications to consider with this header. Making it public gives an attacker insight
into how the cache is configured, which may help them bypass a cache entirely and access an origin server directly.
Cache header security is provider-specific, but could involve enabling it only when required, restricting access to specific
IP addresses, or requiring a custom request header to trigger the cache-status header.&lt;/p&gt;
&lt;p&gt;Peakhour.IO regularly sees automated scans sending other providers' headers to trigger a cache-status header response.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The Cache-Status header gives clear insight into how cache layers interact
on a website. It provides a standardised format for showing how a cache handled a request and
allows multiple caches to report their part of the request path.&lt;/p&gt;
&lt;p&gt;Peakhour fully supports this new header, and it can be enabled/disabled and secured in the dashboard.&lt;/p&gt;</content><category term="Learning"></category><category term="Caching"></category><category term="CDN"></category><category term="Drupal"></category><category term="HTTP"></category><category term="Rate Limiting"></category><category term="Web Performance"></category></entry><entry><title>Website Optimisation</title><link href="https://www.peakhour.io/blog/eliminating-blocking-resources/" rel="alternate"></link><published>2021-05-17T13:00:00+10:00</published><updated>2021-05-17T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2021-05-17:/blog/eliminating-blocking-resources/</id><summary type="html">&lt;p&gt;Even if you have the fastest server in the world, your website might still seem very slow to end users if you have lots of render blocking resources, learn how to deal with them.&lt;/p&gt;</summary><content type="html">&lt;p&gt;We've previously covered ways to find &lt;a href="https://www.peakhour.io/blog/common-issues-that-impact-site-speed/#blocking"&gt;resources that block rendering in a browser&lt;/a&gt;.
Now we'll cover techniques for loading those resources without letting them block rendering. Before making changes,
always run some &lt;a href="/blog/introduction-to-website-performance-testing/"&gt;website performance tests&lt;/a&gt;
using your favourite testing tool to get a baseline so you can measure any improvements. We recommend
&lt;a href="/blog/testing-website-speed-webpagetest/"&gt;testing with webpagetest.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before we get into the techniques, it is worth defining the problem.&lt;/p&gt;
&lt;h2&gt;What is a Blocking Resource?&lt;/h2&gt;
&lt;p&gt;When a browser loads a page from a website it reads the HTML markup from top to bottom. If it
encounters a CSS or JavaScript file while it&amp;apos;s reading, the browser stops while it downloads and parses
that file. While the browser is waiting it can’t process the rest of the HTML or display
content to the user. Rendering is blocked.&lt;/p&gt;
&lt;h2&gt;Why is this a problem?&lt;/h2&gt;
&lt;p&gt;It would not be a problem if every page included only the information required to display it. Most websites do not work that way.
They are typically built using prebuilt themes and third-party libraries that can contain lots of
CSS and JavaScript. Only a tiny fraction of this code might be used on the current page, or it might only be needed for ‘below the fold’
content, or on another page of the site. &lt;strong&gt;Note: Below the fold means the content of a page that
doesn't initially fit on the screen&lt;/strong&gt;. Any unnecessary information keeps the browser blocked for longer than
needed, slowing the load experience for the user.&lt;/p&gt;
&lt;p&gt;CSS and JavaScript files are usually at the very top of the HTML document before any of the content. This means they
have to be downloaded and parsed before the browser can display anything. Even a website that has extremely fast server response
times can still seem very slow if it has blocking resources.&lt;/p&gt;
&lt;p&gt;Take a simple example: a website that includes a live chat widget. The JavaScript for the widget is
included at the very top of the page in the &lt;head&gt; section. The browser has to stop, download, and parse the CSS
and JavaScript for the widget (usually downloaded from a third-party domain) before any content is displayed to the user.
The chat widget could appear after the rest of the content without affecting the user experience.&lt;/p&gt;
&lt;h2&gt;Things you should always be doing&lt;/h2&gt;
&lt;p&gt;Before targeting CSS- or JavaScript-specific techniques, cover the basics for both.&lt;/p&gt;
&lt;h3&gt;1. Minify all files&lt;/h3&gt;
&lt;p&gt;Minification is the removal of all non-essential characters in a file, e.g. irrelevant whitespace and code comments. It
can make a substantial difference to the file size.&lt;/p&gt;
&lt;h3&gt;2. Ensure compression is enabled on your server&lt;/h3&gt;
&lt;p&gt;Make sure your server is configured to use either gzip or Brotli compression when serving CSS and JavaScript.&lt;/p&gt;
&lt;h3&gt;3. Self host files&lt;/h3&gt;
&lt;p&gt;If the CSS or JavaScript is on a third-party domain, i.e. not the domain name your website is on, you should strongly
consider uploading the file to your website and serving it from your domain. This might not always be possible, but if it
is it eliminates the overhead of the browser
opening a connection to another domain, and it removes the possibility that the third party is not compressing, minifying,
or using HTTP/2.&lt;/p&gt;
&lt;p&gt;After the implementation of &lt;a href="https://www.peakhour.io/blog/cache-partitioning-firefox-chrome/"&gt;cache partitioning in the major browsers&lt;/a&gt;,
there is no longer any &lt;em&gt;potential&lt;/em&gt; advantage to using third-party CDNs to serve assets like JavaScript, fonts, or CSS. Make a copy on your server and host
them on your domain.&lt;/p&gt;
&lt;h3&gt;4. If you can't self host then preconnect to third party domains&lt;/h3&gt;
&lt;p&gt;If external assets are on third-party domains, and you absolutely can't self host them, then you can improve
loading by telling the browser to &lt;code&gt;preconnect&lt;/code&gt; to the third-party domain.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;preconnect&lt;/code&gt; tells the browser to establish an early connection to the domain before it has discovered the asset
while reading the HTML. Use &lt;code&gt;preconnect&lt;/code&gt; in the head of the HTML, e.g.:&lt;/p&gt;
&lt;p&gt;&lt;link rel="preconnect" href="https://example.com"&gt;&lt;/p&gt;
&lt;p&gt;Establishing early connections can shave 100-500ms off third-party load times, which is worth having. You should only use
&lt;code&gt;preconnect&lt;/code&gt; on critical third-party resources. For all the others you can use &lt;code&gt;dns-prefetch&lt;/code&gt;, e.g.:&lt;/p&gt;
&lt;p&gt;&lt;link rel="dns-prefetch" href="http://example.com"&gt;&lt;/p&gt;
&lt;p&gt;This tells the browser to perform DNS resolution of the domain early, which is similar to looking up a phone number
in the phone book. Pre-resolving DNS can save 20-120ms. That sounds like small numbers, but remember, &lt;a href="/website-performance/"&gt;differences as small
as 100ms can have large measurable impacts on conversion rates&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;5. Select only what you need from frameworks&lt;/h3&gt;
&lt;p&gt;It is common for users of frameworks like Bootstrap or jQuery UI to only use a fraction of the functionality provided.
If this is you, then the first step is to cut out what you're not using. Bootstrap and jQuery UI are modular, you can
either download everything in one bundle, or you can break it up to take just the bits you are using.&lt;/p&gt;
&lt;p&gt;These points will ensure that blocking resources are downloaded as quickly as possible. Now we can discuss some
specific techniques that will help minimise blocking and get your page displaying quickly. Please be aware that
this is not an exhaustive overview, but these techniques will probably get you 90% of the benefit with 10% of the work.
Getting that last 10% requires deeper technical work. If you want to go there, Google’s web.dev
website is a good resource.&lt;/p&gt;
&lt;h2&gt;Techniques for Optimising Blocking Resources&lt;/h2&gt;
&lt;h3&gt;Javascript&lt;/h3&gt;
&lt;p&gt;There are a few different techniques for optimising the loading of JavaScript. First, let's look at the default
loading behaviour. &lt;em&gt;Credit for the images goes to Daniel Imms and his website Growing with the web&lt;/em&gt;. As stated earlier,
the default behaviour is to stop parsing the HTML document when a script is encountered, download the script and execute it.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/javascript-loading-legend.png" alt="Javascript loading legend" width="100%""/&gt;
&lt;img src="/static/images/blog/default-javascript-blocking-behaviour.png" alt="Default Javascript loading behaviour" width="100%"/&gt;&lt;/p&gt;
&lt;p&gt;Now let's look at how we can change this behaviour.&lt;/p&gt;
&lt;h4&gt;1. Moving scripts to the very bottom of the page, right before the closing &lt;/body&gt; tag.&lt;/h4&gt;
&lt;p&gt;This is the original optimisation technique, before defer and async were introduced. It works by moving scripts to
the very end of the HTML document, where they are downloaded and parsed after everything else.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/javascript-loading-end-of-html.png" alt="Javascript end of page load" width="100%""/&gt;&lt;/p&gt;
&lt;p&gt;In our example in the previous section, the chat widget would now load and pop up after the rest of the content has been displayed to the user.&lt;/p&gt;
&lt;h4&gt;2. Defer and Async&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags that have a &lt;code&gt;src&lt;/code&gt; attribute can be marked as either deferred &lt;code&gt;defer&lt;/code&gt;, or asynchronous &lt;code&gt;async&lt;/code&gt;, or both.
For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;script src=”https://www.somedomain.com/somescript.js” defer async&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells the browser to change the script loading behaviour.&lt;/p&gt;
&lt;h4&gt;Defer&lt;/h4&gt;
&lt;p&gt;Defer was the original browser-based support for improved JavaScript loading. It tells the
browser to download the script asynchronously while it keeps reading the HTML, and then execute it once it has finished reading the whole HTML document. Here's the loading behaviour
with defer enabled.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/javascript-loading-defer.png" alt="Javascript loading defer" width="100%""/&gt;&lt;/p&gt;
&lt;p&gt;As you can see the script no longer blocks the browser from doing anything else while downloading. Defer preserves
script execution order. This can be very important if a script depends on one declared earlier in the page.&lt;/p&gt;
&lt;p&gt;As noted earlier, you can only mark &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags that have a &lt;code&gt;src&lt;/code&gt; attribute as deferred. Inline scripts, e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;console.log(&amp;quot;Hi&lt;span class="w"&gt; &lt;/span&gt;I&amp;#39;m&lt;span class="w"&gt; &lt;/span&gt;some&lt;span class="w"&gt; &lt;/span&gt;inline&lt;span class="w"&gt; &lt;/span&gt;script!&amp;quot;);
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any attempt to defer that inline block will simply be ignored. This can cause problems if you have inline script scattered through your code
and rely on a deferred third-party library, e.g. jQuery. There are two potential solutions if you can't simply move the
code to the bottom of the page:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move each inline code block into its own file and include it using the &lt;code&gt;src&lt;/code&gt; attribute so you can defer it.&lt;/li&gt;
&lt;li&gt;Or you can try declaring the block as a &lt;code&gt;module&lt;/code&gt;. Test this carefully, as browser support may be limited and it also
   places the script into &lt;code&gt;strict&lt;/code&gt; mode, which may break it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Async&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; attribute tells the browser to download the script now and execute it as soon as it has finished. Like &lt;code&gt;defer&lt;/code&gt;, the
downloading is done asynchronously. Unlike &lt;code&gt;defer&lt;/code&gt;, the script is executed as soon as it is downloaded. Here is the behaviour:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/javascript-loading-async.png" alt="Javascript loading async" width="100%""/&gt;&lt;/p&gt;
&lt;p&gt;As you can see the browser doesn't stop while downloading, but does pause once downloading is finished so it can execute
the script. &lt;strong&gt;&lt;code&gt;async&lt;/code&gt; doesn't preserve script order&lt;/strong&gt;, which can potentially cause issues when there are script dependencies.&lt;/p&gt;
&lt;p&gt;All three methods have pros and cons. &lt;code&gt;Defer&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; result in faster page loads overall as the scripts are downloaded
while the browser reads the HTML. Moving the script to the bottom of the page shifts the sequence around.&lt;/p&gt;
&lt;p&gt;Your first option should be to &lt;code&gt;defer&lt;/code&gt; all scripts. Then, if some above the fold content is taking too long because it has a
JavaScript dependency, e.g. a carousel in the hero section, you can try making the necessary scripts &lt;code&gt;async&lt;/code&gt; instead.&lt;/p&gt;
&lt;h3&gt;Optimising CSS&lt;/h3&gt;
&lt;p&gt;The key to fast CSS loading is to prioritise the CSS needed for the immediate above the fold content and then defer
the rest. Many articles advocate extracting the precise CSS and then including it inline
in the HTML document in a style block, i.e.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;.accordion-btn&lt;span class="w"&gt; &lt;/span&gt;{background-color:&lt;span class="w"&gt; &lt;/span&gt;#ADD8E6;color:&lt;span class="w"&gt; &lt;/span&gt;#444;cursor:&lt;span class="w"&gt; &lt;/span&gt;pointer;padding:&lt;span class="w"&gt; &lt;/span&gt;18px;width:&lt;span class="w"&gt; &lt;/span&gt;100%;border:&lt;span class="w"&gt; &lt;/span&gt;none;text-align:&lt;span class="w"&gt; &lt;/span&gt;left;outline:&lt;span class="w"&gt; &lt;/span&gt;none;font-size:&lt;span class="w"&gt; &lt;/span&gt;15px;transition:&lt;span class="w"&gt; &lt;/span&gt;0.4s;}.container&lt;span class="w"&gt; &lt;/span&gt;{padding:&lt;span class="w"&gt; &lt;/span&gt;0&lt;span class="w"&gt; &lt;/span&gt;18px;display:&lt;span class="w"&gt; &lt;/span&gt;none;background-color:&lt;span class="w"&gt; &lt;/span&gt;white;overflow:&lt;span class="w"&gt; &lt;/span&gt;hidden;}h1&lt;span class="w"&gt; &lt;/span&gt;{word-spacing:&lt;span class="w"&gt; &lt;/span&gt;5px;color:&lt;span class="w"&gt; &lt;/span&gt;blue;font-weight:&lt;span class="w"&gt; &lt;/span&gt;bold;text-align:&lt;span class="w"&gt; &lt;/span&gt;center;}
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, you have to do this on every possible landing page where the critical CSS might be different per page. Inlining
CSS also adds to the download size for each page, and forces the browser to reparse the CSS rules for every load rather
than being able to use a cached file for repeat views.&lt;/p&gt;
&lt;p&gt;We advocate for putting the critical CSS into its own file and loading that normally, and then deferring any other non
critical CSS. Identifying the critical CSS is the main task. The first thing to do is to look at the included
CSS on your website and see if you can identify any non-core files. You can defer those files using this pattern:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/styles.css&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;onload=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;this.onload=null;this.rel=&amp;#39;stylesheet&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&amp;lt;link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/styles.css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;as="style"&lt;/code&gt; lets the browser download the file asynchronously. The onload changes the type to stylesheet, telling the
browser to parse the file. Finally, we include a &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; to enable the CSS to load normally if JavaScript is turned off.&lt;/p&gt;
&lt;p&gt;Once you've deferred non-core CSS files you can still check whether your core ones contain lots of unused rules.
Google Chrome's coverage tool can show unused rules, but it
doesn’t let you easily export used and unused rules. You have to go through it yourself, programmatically, or use
a third-party tool to make two files: the critical CSS, and the non-critical CSS which can be deferred.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Eliminating, or at least minimising, blocking resources can be one of the biggest improvements to user experience you can make to your
site. With &lt;a href="/blog/web-vitals/"&gt;Google Web Vitals&lt;/a&gt; being introduced soon as a search signal, it is important
to make sure your website loads as fast as possible so your users stay longer and buy more
from your site.&lt;/p&gt;</content><category term="Performance"></category><category term="Web Performance"></category><category term="Caching"></category><category term="Drupal"></category><category term="Rate Limiting"></category><category term="WordPress"></category><category term="Core Web Vitals"></category></entry><entry><title>Secure Dynamic Content Caching</title><link href="https://www.peakhour.io/blog/caching-dynamic-content-with-a-cdn/" rel="alternate"></link><published>2021-02-09T13:00:00+11:00</published><updated>2021-02-09T13:00:00+11:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2021-02-09:/blog/caching-dynamic-content-with-a-cdn/</id><summary type="html">&lt;p&gt;Comprehensive guide to secure dynamic content caching that improves server performance whilst maintaining security controls. Learn how modern application security platforms integrate caching with threat protection for optimal performance-security balance.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last time we covered how &lt;a href="/blog/common-issues-that-impact-site-speed/#slow" target="issues"&gt;slow server performance&lt;/a&gt; can
have a negative, sometimes &lt;strong&gt;very&lt;/strong&gt; negative, effect on your website load times. The causes of slow server responses
are many and varied, and not necessarily tied to the server specification. Diagnosing and dealing with them can be difficult,
time-consuming, and costly. One practical way to reduce the impact is to look for opportunities to cache
&lt;a href="/learning/dynamic-content-caching/"&gt;dynamic content&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What is Dynamic Content?&lt;/h2&gt;
&lt;p&gt;Content delivered by a web server is categorised as either static or dynamic. Static content is the same for every user
and is delivered without being generated or processed by the server. Static content is fast to deliver
and does not tax a server's resources.&lt;/p&gt;
&lt;p&gt;Dynamic content is generated by the server for every request. That can involve querying a database several times and executing
a large amount of code. Depending on the work required to generate the result, dynamic content can be resource-heavy.&lt;/p&gt;
&lt;p&gt;Traditionally CDNs have only cached and served the static content of websites, usually the images, CSS files,
Javascript files, etc. They required the webmaster to upload these resources to the CDN's servers and to modify their website
source HTML to access the resources from the CDN. For example,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://www.yourdomain.com/image1.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;would be changed to be something like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://cdn.yourdomain.com/image1.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Modern CDNs, like Peakhour, act as a reverse proxy{:target="learning"}, which means they sit between the
end user and the website's origin server. This enables them to &lt;em&gt;transparently&lt;/em&gt; cache a copy of &lt;em&gt;anything cacheable&lt;/em&gt; being returned by the
origin server. By transparently caching, we mean the caching happens without changes to the original website.&lt;/p&gt;
&lt;h3&gt;Full Page Caching&lt;/h3&gt;
&lt;p&gt;Full Page Caching (FPC) is where the actual HTML document of a web page is cached.&lt;/p&gt;
&lt;p&gt;Most websites are built using a Content Management System (CMS). Widely used CMS platforms are Wordpress,
Drupal, Magento, etc. By default, every time a page is viewed the CMS has to generate the content
from its database. Most of the time this generation is unnecessary. The content is either the
same for every user, changes very rarely, or only differs by a small amount of personalisation. In each case it
is possible to perform Full Page Caching to improve page load times and to cut server load. Let's have a look at the
difference full page caching makes to one of our clients, Magento 2 store &lt;a href="/case-studies/savvysupporter/"&gt;savvysupporter.com.au&lt;/a&gt;.&lt;/p&gt;
&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/savvy-before.jpg" width="100%" alt="Savvysupporter before"/&gt;
&lt;em&gt;Main document load &lt;strong&gt;before&lt;/strong&gt; caching: &lt;strong&gt;2.07s&lt;/strong&gt;&lt;/em&gt;
&lt;/div&gt;

&lt;div class="text-center" style="padding: 20px 0px"&gt;
&lt;img src="/static/images/savvy-after.jpg" width="100%" alt="Savvysupporter after"/&gt;
&lt;em&gt;Main document load &lt;strong&gt;after&lt;/strong&gt; caching: &lt;strong&gt;82ms!!&lt;/strong&gt;&lt;/em&gt;
&lt;/div&gt;

&lt;p&gt;Caching the page has cut nearly &lt;strong&gt;2 whole seconds&lt;/strong&gt; from the download time. That matters: load differences
as small as 100 milliseconds have measurable impacts on website conversion rates. With a Magento 2
website, it's possible to cache all full pages outside the checkout process and the customer/admin area. This can reduce load
on the origin in the order of &lt;strong&gt;60-70%&lt;/strong&gt; and make the customer experience much better.&lt;/p&gt;
&lt;h3&gt;API (Application Programming Interface) Caching&lt;/h3&gt;
&lt;p&gt;Many API calls used by web applications are for the retrieval of information to be displayed to the end user. Examples
 include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pricing and product information&lt;/li&gt;
&lt;li&gt;Form auto completion&lt;/li&gt;
&lt;li&gt;Product catalogue searches&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all strong candidates for caching, reducing load on your server and making websites faster.&lt;/p&gt;
&lt;h2&gt;Handling Stale Information&lt;/h2&gt;
&lt;p&gt;The one potential drawback of caching dynamic content is the possibility of returning out of date information to the
end user. There are two strategies to deal with this risk.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Setting a short Time To Live (TTL) with the caching provider&lt;/strong&gt;. By only keeping content cached for a short time, e.g. 5
   minutes, the cache will never be without up to date information for very long. Cached content will expire and the new
   version fetched from the origin server. The drawback with this method is that, unless your site is very busy, cache hit
   rates can be low, users can frequently get slow loading pages, and stale content is still possible. However, for very
   busy sites this can be an effective, low-overhead strategy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flushing content when it changes&lt;/strong&gt;. This strategy sets very long time to live in the cache, months or even years. When
   content is updated the cache is informed and the new version fetched. This notification of new content could happen
   manually or, in the case of some CMSs, automatically. For example, Magento 2 and Drupal 8 have a built in framework
   for integrating caching providers to handle flushing when content/stock changes. This strategy ensures very high hit
   rates, but unless the flushing is accurate and fast it can result in stale content.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Security-Performance Integration&lt;/h2&gt;
&lt;p&gt;Modern &lt;a href="/learning/application-security/what-is-application-security-platform/"&gt;Application Security&lt;/a&gt; platforms like Peakhour combine caching with comprehensive security controls so performance optimisation does not weaken application protection:&lt;/p&gt;
&lt;h3&gt;Edge Security Processing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WAF/WAAP Integration&lt;/strong&gt;: Security rules are processed at the edge before content is cached, ensuring malicious requests never reach your origin&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bot Management&lt;/strong&gt;: Caching adapts based on traffic classification - legitimate users benefit from cached content whilst malicious bots are filtered out&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Protection&lt;/strong&gt;: Secure caching of API responses with appropriate security headers and access controls&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cache Security Controls&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Secure Purging&lt;/strong&gt;: Authorised cache invalidation through secure API endpoints with proper authentication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Classification&lt;/strong&gt;: Different caching policies for public, authenticated, and sensitive content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Header Security&lt;/strong&gt;: Automatic injection of security headers (CSP, HSTS, etc.) into cached responses&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Secure dynamic &lt;a href="/products/advanced-caching/"&gt;content caching&lt;/a&gt; works best when performance optimisation and application security are handled together. By implementing caching within an Application Security Platform, organisations can achieve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Superior Performance&lt;/strong&gt;: Dramatic improvements in load times and server capacity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Protection against threats at the edge before they impact cached content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational Efficiency&lt;/strong&gt;: Reduced origin server load whilst maintaining security posture&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Optimisation&lt;/strong&gt;: Lower infrastructure costs through intelligent caching and edge processing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For modern applications and APIs, secure dynamic caching should form part of the performance and security strategy, improving the user experience whilst maintaining threat protection.&lt;/p&gt;</content><category term="Performance"></category><category term="Drupal"></category><category term="Caching"></category><category term="WordPress"></category><category term="Web Performance"></category><category term="CDN"></category><category term="Rate Limiting"></category></entry><entry><title>Common Issues That Affect Website Performance</title><link href="https://www.peakhour.io/blog/common-issues-that-impact-site-speed/" rel="alternate"></link><published>2020-11-30T13:00:00+11:00</published><updated>2020-11-30T13:00:00+11:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2020-11-30:/blog/common-issues-that-impact-site-speed/</id><summary type="html">&lt;p&gt;After covering testing we're going to get an overview of the common issues that impact website load times and how to check for them.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Our last three website performance articles covered the why and how of
&lt;a href="/blog/introduction-to-website-performance-testing/"&gt;testing website performance&lt;/a&gt;,
and introduced our two favourite performance testing tools, &lt;a href="/blog/testing-website-speed-webpagetest/"&gt;WebPageTest.org&lt;/a&gt;, and
&lt;a href="https://www.peakhour.io/blog/testing-sitespeed-lighthouse/"&gt;Lighthouse&lt;/a&gt;. This article covers the common causes of slow
loading times, and how to spot them using the same testing tools.&lt;/p&gt;
&lt;h2&gt;1. Latency&lt;/h2&gt;
&lt;p&gt;Latency is the time it takes for a request from a client's browser to traverse the internet to reach the website server.
A number of factors affect latency, with physical distance usually the main one.
Data on the internet travels at the speed of light, so distance may not sound like a major concern.
In practice, small delays compound quickly. Here are some realistic examples of request
latency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sydney to Melbourne: 5ms&lt;/li&gt;
&lt;li&gt;Sydney to Perth: 25ms&lt;/li&gt;
&lt;li&gt;Sydney to San Francisco: 75ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Common tools used to determine latency between servers are Ping and Traceroute, they will provide you with
&lt;strong&gt;Request Round Trip (RTT)&lt;/strong&gt; latency, ie the time it takes for a request to get to the server and back. So 2 times the numbers above.&lt;/p&gt;
&lt;p&gt;Here is an example of latency during a webpage load. We'll ignore internet speed and any potential
network congestion, and focus only on latency. We'll request a website hosted in San Francisco from a
browser located in Sydney.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browser establishes a TLS (Secure) connection with server, &lt;em&gt;6 * 75ms&lt;/em&gt; = &lt;strong&gt;450ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Browser sends HTTP Request for the main page = &lt;strong&gt;75ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Server sends HTTP Response containing page which specifies 10 assets = &lt;strong&gt;75ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Browser requests the 10 additional assets = &lt;strong&gt;75ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Server responds with 10 assets &lt;em&gt;10 * 75&lt;/em&gt; = &lt;strong&gt;750ms&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this example, a website with 10 assets, which is a fairly simple page, has nearly &lt;strong&gt;1.5s&lt;/strong&gt; added to
the page load time through latency alone. If the same site was hosted in Melbourne, the time due to latency would be just
&lt;strong&gt;95ms&lt;/strong&gt;. To solve this problem you would either move your website server closer to your customers, or use Peakhour Edge caching.&lt;/p&gt;
&lt;h3&gt;How do I check for latency problems?&lt;/h3&gt;
&lt;p&gt;If there is a long distance between your server and your customers, eg your website is hosted in the US and your customers
are in Australia, page load times will be significantly affected by latency. A good tool for indicative RTT times between cities is
provided by &lt;a href="https://wondernetwork.com/pings"&gt;wonder network&lt;/a&gt;. Webpagetest.org also provides a Traceroute tool which
can give you indicative RTT times between its testing locations and your website.&lt;/p&gt;
&lt;h2&gt;2. Old version of HTTP&lt;/h2&gt;
&lt;p&gt;Browsers communicate with websites using a protocol called HTTP. The protocol formalises the steps needed to connect a
browser and server so a webpage can be downloaded. Since the introduction of the web, HTTP has gone through
a number of revisions. The currently widely adopted version is HTTP/2.&lt;/p&gt;
&lt;p&gt;Even though HTTP/2 was introduced over 5 years ago, over &lt;a href="https://w3techs.com/technologies/details/ce-http2" target="trends"&gt;50% of websites&lt;/a&gt;
are still only served over HTTP/1.1. Without getting too technical, HTTP/2 has significant advantages over older versions
because it reduces the number of connections between a browser and server, and transfers information more efficiently.&lt;/p&gt;
&lt;p&gt;Serving your website over HTTP/2 can improve page load times by &lt;strong&gt;10-15%&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;How do I identify the version of HTTP my website is served over?&lt;/h3&gt;
&lt;p&gt;&lt;a href="/blog/testing-website-speed-webpagetest/" target="testing"&gt;Run a performance test of your website&lt;/a&gt; using WebPageTest.org, once complete
click on the 'Details' link in the report navigation. You will see the Waterfall View. Click on the first request, circled
below in this image:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/http2-waterfall.jpg" alt="Webpagetest waterfall view" style="width: 100%;margin-bottom: 20px"/&gt;&lt;/p&gt;
&lt;p&gt;It will bring up the request details including the Protocol used, circled below:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/request-detail-http2.jpg" alt="HTTP Request Detail" style="width: 100%;margin-top: 20px"/&gt;&lt;/p&gt;
&lt;h2&gt;3. &lt;a name="slow"&gt;&lt;/a&gt; Slow Server Performance&lt;/h2&gt;
&lt;p&gt;A slow initial response from the server is a common cause of poor page load
performance. The majority of websites are built using some sort of Content Management System (CMS), eg Wordpress, Magento,
Drupal, Shopify, to name a few. By default, a CMS has to construct a page each time a browser requests it, even when the
content has not changed. That process can involve executing a lot of code and querying a database several times
before returning the HTML that forms the page.&lt;/p&gt;
&lt;p&gt;The specification of your server, the number of CMS plugins, the state of your database, and the number of simultaneous
users can all affect the response time. A slow server may take 10s or more to respond, while even a fast server can still take over
a second to generate a page. That is enough to pretty much make you fail the new Core Web Vitals guidelines before you even
get started.&lt;/p&gt;
&lt;h3&gt;How do I check for slow server performance?&lt;/h3&gt;
&lt;p&gt;Server performance can be checked from the waterfall view in WebPageTest.org. The time taken to download the main document
indicates whether server performance is affecting your page load. Here's an example:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/server-performance-waterfall.jpg" alt="Server Performance Waterfall" style="width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;The total time taken to download the main document here is over 1.3s. That is not too bad, but it has already used up over half
the 2.5s required to achieve 'Good' for the Largest Contentful Paint (LCP) metric in &lt;a href="/blog/web-vitals/" target="webvitals"&gt;web vitals&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4. Page Weight&lt;/h2&gt;
&lt;p&gt;Even though internet speeds are getting faster, they are still a limiting factor to how fast a browser can download a page.
If the requested page and the associated resources, eg images, javascript, CSS, are large files, it will take longer
for the browser to download all the required information to display a page. Unoptimised images are a common culprit
for inflating page weight. Unoptimised CMS themes and third party javascript libraries are another.&lt;/p&gt;
&lt;h3&gt;How do I check my page weight?&lt;/h3&gt;
&lt;p&gt;WebPageTest.org reports the page weight in the far right of its summary, circled here:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/page-weight.jpg" alt="Page Weight" style="width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;You should be aiming for 2mb or less. This particular website is more than a little obese, coming in at around 30mb...
WebPageTest also has a section called 'Content Breakdown' which shows where the weight is, ie in images, javascript, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/content-breakdown.jpg" alt="Content Breakdown" style="width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;Over 27mb in images is what's weighing down this page.&lt;/p&gt;
&lt;p&gt;Peakhour also has a &lt;a href="https://www.peakhour.io/pages/page-weight" target="pageweight:"&gt;pageweight tool&lt;/a&gt; that you
can run for a page on your website and receive a full optimisation report for the images on the page, along with downloadable
optimised images.&lt;/p&gt;
&lt;h2&gt;5. &lt;a name="blocking"&gt;&lt;/a&gt;Blocking Resources&lt;/h2&gt;
&lt;p&gt;Resources that can block a page include CSS and javascript. When the main HTML page is downloaded and parsed, the browser
will not render anything to the screen until the CSS and javascript files that are referenced are downloaded and parsed.
If your website includes a lot of CSS and javascript, which is not uncommon for pre built themes for CMS's like Wordpress
and Magento, the downloading and parsing of these files can delay the browser from showing any content for several
seconds.&lt;/p&gt;
&lt;h3&gt;How do I identify blocking resources?&lt;/h3&gt;
&lt;p&gt;The easiest way to check is to use &lt;a href="/blog/testing-sitespeed-lighthouse/"&gt;Google Lighthouse&lt;/a&gt;) to identify them for you.
After running the report, go to the opportunities section and expand the 'Eliminate render-blocking resources' section
to see what it finds.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/lighthouse-opportunities.jpg" alt="Lighthouse Opportunities" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;h2&gt;6. Third Party Resources&lt;/h2&gt;
&lt;p&gt;It is very common for websites to include third party resources. These are files that have to be fetched
from a domain/url other than the one that the page is being requested on. Eg if you are requesting www.domain.com.au,
it might include a resource from a third party, eg www.anotherdomain.com.au. Common third party resources might be
analytics scripts (eg Google analytics), marketing tools (eg Mailchimp)&lt;/p&gt;
&lt;p&gt;This forces the browser to open another connection to the third party. The time taken to do this, combined with the possibility
that the third party might be slow to respond (see latency and server performance above), can often ruin load times. If the
resource in question is also a blocking resource the problem is compounded.&lt;/p&gt;
&lt;h3&gt;Spotting a problem with third party resources&lt;/h3&gt;
&lt;p&gt;WebPageTest has a section 'Domains' which displays all the individual domains that the browser connected to when loading
the page:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/third-party.jpg" alt="Lighthouse Opportunities" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;If your website is requesting resources from more than 10 separate domains then you should consider why that is happening
and whether they are necessary. If you are using external CDNs to load javascript or CSS then you should probably
move them onto your domain.&lt;/p&gt;
&lt;p&gt;Social sharing plugins are notorious for pulling in a lot of resources from external domains. You should replace any share
buttons using external scripts with simple static buttons. It is simple to do, and your website will be much smaller and
faster. By using the javascript shares that social sites prescribe, you are slowing down your website
and allowing third parties to track your clients across the internet.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There are many factors that can slow down your website, drive away customers, and cost you money. You have to regularly
&lt;a href="/blog/introduction-to-website-performance-testing/"&gt;test your website&lt;/a&gt; to check for issues and address them when you find
them. Next we'll cover what you can do to fix the issues we've mentioned here.&lt;/p&gt;</content><category term="Performance"></category><category term="Web Performance"></category><category term="CDN"></category><category term="Caching"></category><category term="Core Web Vitals"></category><category term="WordPress"></category><category term="Rate Limiting"></category></entry><entry><title>Test Your Website Performance With Google Lighthouse</title><link href="https://www.peakhour.io/blog/testing-sitespeed-lighthouse/" rel="alternate"></link><published>2020-09-14T13:00:00+10:00</published><updated>2020-09-14T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2020-09-14:/blog/testing-sitespeed-lighthouse/</id><summary type="html">&lt;p&gt;This installment on website performance introduces Google Lighthouse as a measuring tool. Read on to see how we use it here at Peakhour.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today we're introducing our other favourite tool for testing website performance: Google Lighthouse &lt;em&gt;(from here we'll just
call it Lighthouse)&lt;/em&gt;. Lighthouse measures page experience across accessibility, performance, SEO, and
Progressive Web Apps for desktop and mobile devices.&lt;/p&gt;
&lt;p&gt;Lighthouse is the engine behind web.dev/measure and PageSpeed Insights. It is also available in Chrome DevTools,
via npm, or as a browser extension in Chrome and Firefox. At time of writing Lighthouse is up to version 6, which introduced
&lt;a href="/blog/web-vitals/"&gt;Web Vitals&lt;/a&gt; as the basis for &lt;a href="https://googlechrome.github.io/lighthouse/scorecalc/"&gt;scoring&lt;/a&gt;.
If you are unsure which version of the tool you are using, then scroll right to the bottom of the report it generates
where it will state the version.&lt;/p&gt;
&lt;p&gt;Lighthouse generates its report by simulating a specific device and network speed, rather than running at the full speed
of your computer. That matters because speed issues are more noticeable on slower devices, and users are not all on newer
devices or fast internet connections. You should test for a good load experience across that range.
The current simulated mobile device is a Moto G4 on a ~1.5 megabit connection. For reference, it would take over 5s to
download 1mb of data at this speed. If your page weight is typical, ie over 2.5mb, you should not expect a strong score.&lt;/p&gt;
&lt;h2&gt;How to use Google Lighthouse&lt;/h2&gt;
&lt;p&gt;There are two ways you can run a Google Lighthouse report:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In your local browser;&lt;/li&gt;
&lt;li&gt;Online via web.dev/measure or PageSpeed Insights.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We recommend running Google Lighthouse in your local browser because the online versions operate out of the US. If your website
and customers are elsewhere, that extra network latency can pull the score down.&lt;/p&gt;
&lt;p&gt;Here we'll focus on running Lighthouse from within Chrome DevTools.
To do this, click on the three vertical dots in the top right-hand corner, then select 'More Tools', then 'Developer Tools'.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/dev-tools.jpg" alt="open dev tools" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;The developer tools will then be displayed. Along the top of the tools window are a number of tabs. Select the 'Lighthouse'
tab.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/dev-tools-2.jpg" alt="open lighthouse tab" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;Since we're only interested in performance, make sure only the Performance category is ticked. You also want to make sure
'Clear storage' is ticked &lt;em&gt;(in the top left)&lt;/em&gt; to simulate a first load of your site. Finally, choose the device you want
to report on, mobile or desktop, and click 'Generate report'.&lt;/p&gt;
&lt;p&gt;While the report is being generated, avoid doing anything else on your computer, and don't leave it busy with background
tasks. Otherwise, the score can be affected.&lt;/p&gt;
&lt;h2&gt;Understanding the Score&lt;/h2&gt;
&lt;p&gt;Once the report has finished you'll see a performance summary, like this mobile one we ran on Peakhour.io while we
were developing the website:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/lighthouse-score-summary.jpg" alt="open lighthouse tab" style="max-width: 100%"//&gt;&lt;/p&gt;
&lt;p&gt;Scoring in version 6 is based on Google's &lt;a href="/blog/web-vitals/"&gt;web vitals&lt;/a&gt;, which are metrics that indicate a good user
experience, and Webpagetest's speed index, which measures visual loading performance.
Each metric is colour coded as good, ok, or bad. If the measurement is good you get a green
circle to the left, if it's ok you get an orange square, if it is bad you get a red triangle.&lt;/p&gt;
&lt;p&gt;Each raw metric &lt;em&gt;(the number listed in the report)&lt;/em&gt; is compared to real website performance data sourced from the
&lt;a href="https://httparchive.org/"&gt;HTTP archive&lt;/a&gt; and converted into a score out of 100. This is done by grading the reference data
on a curve, so if your website performs in the top 8% of websites, it gets a score of 90. Similarly, if it scores in the top 25%, it
gets a score of 50. If you are interested in the technical details, Google has in-depth explanations of the scoring at
&lt;a href="https://web.dev/performance-scoring/"&gt;web.dev&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each metric is assigned a weight, and the scores are tallied into one overall number based on the weighting. Here is a
breakdown of the test we just ran &lt;em&gt;(in the screen shot above)&lt;/em&gt;, obtained by clicking on the 'See Calculator' link between
the Metrics section and the screen shots:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/lighthouse-calculator.jpg" alt="open lighthouse tab" style="max-width: 100%"//&gt;&lt;/p&gt;
&lt;h3&gt;Score Variability&lt;/h3&gt;
&lt;p&gt;79 is a good result for a mobile device. However, we ran it several times and obtained scores between 60 on the low end
and 85 on the high end. Scores can fluctuate widely, even when testing on the same device repeatedly. Reasons for this
include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Small differences in internet performance.&lt;/li&gt;
&lt;li&gt;Your computer CPU load when performing the test.&lt;/li&gt;
&lt;li&gt;Web server variability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Again, Google has &lt;a href="https://github.com/GoogleChrome/lighthouse/blob/master/docs/variability.md"&gt;in-depth documentation&lt;/a&gt; around what
might be causing this.&lt;/p&gt;
&lt;h2&gt;Opportunities&lt;/h2&gt;
&lt;p&gt;If your site loads slowly then Lighthouse will list addressable reasons in the opportunities section of the report.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/lighthouse-opportunities.jpg" alt="Lighthouse Opportunities" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;This is the part we generally find most useful. It identifies items that slow the initial load and items that
affect the rendering of a website once it is downloaded. A page can be downloaded very quickly, but the end user still sees a slow site
because CSS and Javascript are blocking rendering. This is a common problem in Wordpress and Magento themes.
These themes include large amounts of third party code that ultimately never gets used for a particular site, but which
the browser still has to download and parse before it can display anything.&lt;/p&gt;
&lt;p&gt;In this case, the main bottleneck appears to be a font loaded from Google Fonts. This is delaying the rendering of our
page by 1.3s.&lt;/p&gt;
&lt;h2&gt;Diagnostics&lt;/h2&gt;
&lt;p&gt;The diagnostics section provides additional information you can use to improve load times.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/lighthouse-diagnostics.jpg" alt="Lighthouse Diagnostics" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;Here we have a few small problems, mainly associated with the development status of our site.&lt;/p&gt;
&lt;h2&gt;web.dev and PageSpeed Insights&lt;/h2&gt;
&lt;p&gt;If you do choose to run your report online, we recommend using &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;PageSpeed Insights&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition to the generated report, PageSpeed Insights also shows you &lt;strong&gt;Field Data&lt;/strong&gt; for the page you are testing,
and an &lt;strong&gt;Origin Summary&lt;/strong&gt; for all pages on the website.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/images/blog/page-speed-insights-field-data.jpg" alt="Page Speed Insights Field Data" style="max-width: 100%"/&gt;&lt;/p&gt;
&lt;p&gt;This is real-world data gathered from Chrome users who have
opted in to allowing Google to gather their data. If your site isn't very busy then Google might not have any data to
share. It is not truly representative, but it is useful information and can often tell a very different story
to your Lighthouse score.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Regular measurement matters because performance issues are often specific and easy to miss. Lighthouse is useful for
identifying issues that affect website performance, and when used in conjunction with
&lt;a href="/blog/testing-website-speed-webpagetest/"&gt;Webpagetest.org&lt;/a&gt;, you'll be in a better position to provide a good experience
for your users. Next we'll cover &lt;a href="/blog/common-issues-that-impact-site-speed/"&gt;common issues that can impact site speed&lt;/a&gt;,
so read on.&lt;/p&gt;</content><category term="Performance"></category><category term="Web Performance"></category><category term="Analytics"></category><category term="Core Web Vitals"></category><category term="Caching"></category><category term="Rate Limiting"></category><category term="Browser Fingerprinting"></category></entry><entry><title>Application Performance Optimisation</title><link href="https://www.peakhour.io/blog/introduction-to-website-performance-testing/" rel="alternate"></link><published>2020-09-12T13:00:00+10:00</published><updated>2020-09-12T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2020-09-12:/blog/introduction-to-website-performance-testing/</id><summary type="html">&lt;p&gt;A practical primer for finding where website requests lose time, from cache state and origin work to browser rendering.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Website performance testing is most useful when it explains where a request lost time. A single score can tell you that a page is slow, but it rarely tells the site team what to change next. The better starting point is the request path: where the visitor is, where the origin is, whether the response was cached, how much the browser had to download, and what work blocked rendering or interaction.&lt;/p&gt;
&lt;p&gt;This article is a primer for that diagnosis. Start with a representative page, test it from a location that matches your users, then read the evidence in order.&lt;/p&gt;
&lt;h2&gt;Start With the First Request&lt;/h2&gt;
&lt;p&gt;The browser cannot render a page until it receives the main HTML document. That first request includes DNS lookup, TCP connection setup, TLS negotiation, any redirect, cache handling, origin processing, and the first byte coming back. When the origin is far away, latency compounds. Peakhour's performance material uses simple Australian examples: Sydney to Melbourne is about 5 ms one way, Sydney to Perth about 25 ms, and Sydney to San Francisco about 75 ms. Those numbers become larger when a page load needs several round trips.&lt;/p&gt;
&lt;p&gt;This is why the main document matters in &lt;a href="/blog/testing-website-speed-webpagetest/"&gt;WebPageTest&lt;/a&gt;. In one Peakhour example, the main HTML document took 149 ms, which is fast. Many sites take 2 to 5 seconds before the browser receives that document. If the main response is already slow, the page has little chance of a good Largest Contentful Paint because the browser has not yet discovered the resources needed to paint the largest content.&lt;/p&gt;
&lt;p&gt;Cache state is part of the same first request. A cache hit at the edge should look different from a miss that forwards to origin. Headers such as &lt;code&gt;Cache-Status&lt;/code&gt; can show hit, miss, TTL, stored state, cache key, and collapsed request behaviour. Without that evidence, teams often guess whether a slow page is caused by the CDN, the origin, the application, or a cache-bypass rule.&lt;/p&gt;
&lt;h2&gt;Use WebPageTest for the Waterfall&lt;/h2&gt;
&lt;p&gt;WebPageTest is useful because it loads the page in a real browser and lets you choose test locations and connection profiles. That matters for Australian sites because a test from the wrong continent can make a local problem look worse or hide a regional problem from view.&lt;/p&gt;
&lt;p&gt;The waterfall is the main working view. Read the first rows before looking at the rest of the page. A redirect on the first request adds delay before the useful page is even requested. Long DNS, connect, or TLS blocks point to connection setup or third-party domains. A long wait on the main document points to cache miss, origin processing, or backend work. Large downloads point to page weight. Red rows show broken requests, and the domain view shows how many external services the browser had to contact.&lt;/p&gt;
&lt;p&gt;The filmstrip is just as important. It shows what the user saw while the waterfall was happening. If the HTML arrived quickly but the filmstrip stayed blank, the issue may be render-blocking CSS, JavaScript, fonts, or a hero image. If the page starts to render quickly but then jumps, you are looking at layout stability, not just network speed.&lt;/p&gt;
&lt;h2&gt;Use Lighthouse for Browser Work&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/testing-sitespeed-lighthouse/"&gt;Lighthouse&lt;/a&gt; is good at surfacing work inside the browser. It runs a controlled test, reports Core Web Vitals-related metrics, and lists opportunities such as eliminating render-blocking resources, reducing unused CSS, deferring JavaScript, compressing assets, and reducing main-thread work.&lt;/p&gt;
&lt;p&gt;Treat the score as a prompt, not a verdict. Lighthouse scores can vary between runs because the local CPU, network conditions, and server response can vary. The useful part is the diagnostics. If Lighthouse points to a font, a theme stylesheet, or a third-party script that delays rendering, compare that with the WebPageTest waterfall and filmstrip. If both tools point to the same resource, you have a stronger case for change.&lt;/p&gt;
&lt;h2&gt;Connect Metrics to Causes&lt;/h2&gt;
&lt;p&gt;Core Web Vitals are easier to act on when each metric is tied to the part of the path it describes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Where to look&lt;/th&gt;
&lt;th&gt;Likely next question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High TTFB&lt;/td&gt;
&lt;td&gt;WebPageTest first row, cache headers, origin logs&lt;/td&gt;
&lt;td&gt;Did the request hit cache, miss to origin, or wait on application work?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow FCP&lt;/td&gt;
&lt;td&gt;Waterfall, filmstrip, render-blocking resources&lt;/td&gt;
&lt;td&gt;Did HTML, CSS, or synchronous JavaScript stop the first paint?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow LCP&lt;/td&gt;
&lt;td&gt;Main document timing, hero media, image weight&lt;/td&gt;
&lt;td&gt;Was the largest element discovered and delivered early enough?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High CLS&lt;/td&gt;
&lt;td&gt;Filmstrip, image dimensions, injected banners, fonts&lt;/td&gt;
&lt;td&gt;Did content move after the visitor started reading?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Poor INP&lt;/td&gt;
&lt;td&gt;Lighthouse main-thread diagnostics, third-party scripts&lt;/td&gt;
&lt;td&gt;Is JavaScript delaying the next paint after interaction?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High page weight&lt;/td&gt;
&lt;td&gt;WebPageTest content breakdown&lt;/td&gt;
&lt;td&gt;Are images, JavaScript, fonts, or unused assets carrying the load?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Too many domains&lt;/td&gt;
&lt;td&gt;WebPageTest domains view&lt;/td&gt;
&lt;td&gt;Which third-party services are adding connection setup and blocking work?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unclear cache behaviour&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cache-Status&lt;/code&gt;, CDN analytics, debug headers&lt;/td&gt;
&lt;td&gt;Which paths are hits, misses, bypasses, stale responses, or collapsed misses?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This table is not a checklist to run forever. It is a triage map. Pick the symptom that matches the page, then follow the evidence to the next request-path decision.&lt;/p&gt;
&lt;h2&gt;Diagnose the Common Failures&lt;/h2&gt;
&lt;p&gt;Latency is the first failure to rule in or out. If the origin is in the United States and most customers are in Australia, the page can lose time before WordPress, Magento, Drupal, or a custom application has done any work. Edge caching helps when the response is safe to reuse, because the first byte can come from a location closer to the visitor.&lt;/p&gt;
&lt;p&gt;Page weight is the next obvious drag. WebPageTest's content breakdown shows whether images, JavaScript, CSS, fonts, or other assets dominate the transfer. Unoptimised images are common, especially on CMS and ecommerce sites. Image variants in AVIF or WebP, responsive sizes, compression, and stable dimensions can improve both download time and LCP.&lt;/p&gt;
&lt;p&gt;Render-blocking resources explain why a page can download quickly and still look blank. CSS and synchronous JavaScript in the head can stop the browser from painting. Large theme bundles and plugin scripts often include code that is not needed on the current page. The fix might be removing unused files, deferring non-critical scripts, splitting code by route, self-hosting critical third-party resources, or using &lt;code&gt;preconnect&lt;/code&gt; only where the first view depends on a third-party domain.&lt;/p&gt;
&lt;p&gt;Third-party domains need a sober review. Analytics, marketing tags, chat widgets, social embeds, payment scripts, and fonts can all be legitimate. They can also add DNS, TCP, TLS, download, parsing, and main-thread cost. If a third-party script is not needed for the first view, it should not block the first view.&lt;/p&gt;
&lt;h2&gt;Where Peakhour Evidence Fits&lt;/h2&gt;
&lt;p&gt;Peakhour performance work should show both user experience and origin relief. For caching, that means hit ratio, miss causes, &lt;code&gt;Cache-Status&lt;/code&gt;, purge state, cache keys, shielded misses, collapsed requests, and origin fetch volume. For images, it means original size, transformed size, selected format, responsive variant, and cache hit state. For Core Web Vitals, it means LCP, CLS, INP, TTFB, page weight, and the same page tested before and after changes.&lt;/p&gt;
&lt;p&gt;Security belongs in the performance review when it changes the request path. Bot filtering, WAF rules, rate limits, and login protection can reduce origin load by stopping abusive or noisy traffic before PHP, database, search, or API work begins. They can also create friction if rules are too broad. Measure the edge decision, the latency, the origin effect, and the false-positive risk. Do not treat "security enabled" as a generic performance story.&lt;/p&gt;
&lt;p&gt;Good performance testing ends with a specific change to validate: cache this public route, purge it by tag, move this script later, replace this image variant, reduce these third-party domains, protect this login path, or investigate this slow origin query. Then run the same test again from the same location and compare the evidence.&lt;/p&gt;</content><category term="Performance"></category><category term="Application Security"></category><category term="DevSecOps"></category><category term="Drupal"></category><category term="DDoS"></category><category term="Threat Detection"></category><category term="Rate Limiting"></category></entry><entry><title>WordPress Performance Optimisation</title><link href="https://www.peakhour.io/blog/wordpress-performance-optimisation-security-cdn/" rel="alternate"></link><published>2019-05-27T13:00:00+10:00</published><updated>2019-05-27T13:00:00+10:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2019-05-27:/blog/wordpress-performance-optimisation-security-cdn/</id><summary type="html">&lt;p&gt;How to speed up WordPress by separating public cacheable pages from private, expensive, and abused request paths.&lt;/p&gt;</summary><content type="html">&lt;p&gt;WordPress speed problems are usually request-path problems. A public article, product page, or campaign landing page should not make PHP, plugins, and the database rebuild the same HTML for every visitor. A login attempt, checkout session, admin request, or private API call should not be treated like public content just because the site is under load.&lt;/p&gt;
&lt;p&gt;The job is to separate those paths clearly. Cache what can be reused, protect the routes that are expensive or abused, and keep enough evidence to prove that the change improved the visitor experience without hiding origin risk.&lt;/p&gt;
&lt;h2&gt;Start With Public Page Caching&lt;/h2&gt;
&lt;p&gt;Most WordPress sites have a large set of pages that are dynamic only because WordPress generated them. The content itself is public and often identical for many visitors: posts, pages, category archives, product listings, campaign pages, media assets, CSS, and JavaScript. These are the paths where full-page caching and edge delivery can change the result quickly.&lt;/p&gt;
&lt;p&gt;When a public page is served from cache, the browser avoids the long trip to origin and the origin avoids running WordPress for a repeat response. That can move Time to First Byte and Largest Contentful Paint in the right direction before anyone touches the theme. Peakhour's older full-page caching examples showed the practical size of this change: a Magento main document fell from 2.07 seconds before caching to 82 ms after caching. WordPress sites have different internals, but the same pattern applies when anonymous pages are safe to reuse.&lt;/p&gt;
&lt;p&gt;The cache policy should be route-aware, not blanket. A simple operating model looks like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;WordPress path&lt;/th&gt;
&lt;th&gt;Delivery stance&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Posts, pages, category pages, campaign pages&lt;/td&gt;
&lt;td&gt;Cache publicly with tags and purge controls&lt;/td&gt;
&lt;td&gt;Confirm logged-out content is shared and fresh after publishing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Featured images, media library files, theme assets&lt;/td&gt;
&lt;td&gt;Cache and optimise variants&lt;/td&gt;
&lt;td&gt;Track image weight, format, dimensions, and cache hit state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WooCommerce product and category pages&lt;/td&gt;
&lt;td&gt;Cache when no cart/session dependency changes the response&lt;/td&gt;
&lt;td&gt;Keep stock, price, and promotion purges tied to content changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cart, checkout, account, previews, admin&lt;/td&gt;
&lt;td&gt;Bypass shared cache&lt;/td&gt;
&lt;td&gt;Preserve session privacy and correctness.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wp-login.php&lt;/code&gt;, &lt;code&gt;/wp-admin/&lt;/code&gt;, &lt;code&gt;xmlrpc.php&lt;/code&gt;, sensitive plugin endpoints&lt;/td&gt;
&lt;td&gt;Protect and rate-limit before origin&lt;/td&gt;
&lt;td&gt;Keep noisy automation away from PHP workers and admin paths.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Publishing Should Not Clear the Whole Site&lt;/h2&gt;
&lt;p&gt;Caching WordPress is easy until someone edits content. Clearing the whole cache after every post update is safe in the narrow sense, but it damages hit ratio and pushes avoidable traffic back to origin. During a busy publishing period or campaign, that can make the site slower exactly when fresh content is being promoted.&lt;/p&gt;
&lt;p&gt;Cache tags are a better fit. Tags label cached responses by the content or template they depend on, so a post update can purge the post, related archives, and affected modules without invalidating unrelated pages. The updated Peakhour WordPress plugin generates cache tags automatically and sends purge requests when content changes in the WordPress admin. That lets teams set longer cache lifetimes for public content while still publishing with confidence.&lt;/p&gt;
&lt;p&gt;This is where &lt;a href="/products/advanced-caching/"&gt;advanced caching&lt;/a&gt; becomes operational rather than theoretical. The site team can review which tags were purged, which routes stayed cached, and whether the next request was a hit, miss, or stored response.&lt;/p&gt;
&lt;h2&gt;Images and Browser Work Still Matter&lt;/h2&gt;
&lt;p&gt;Page caching improves the start of the request path. It does not fix a 3 MB hero image, missing image dimensions, unused CSS, or a third-party script that blocks rendering. WordPress themes and plugin stacks often ship CSS and JavaScript for features that are not used on the current page. The browser still has to download and parse that code before it can paint useful content.&lt;/p&gt;
&lt;p&gt;Use Lighthouse to find render-blocking resources and main-thread pressure. Use WebPageTest to see whether the main HTML arrived quickly but the filmstrip still stayed blank while CSS, fonts, scripts, or images loaded. Those are different failures, and they need different fixes.&lt;/p&gt;
&lt;p&gt;For images, the best results usually come from serving the right variant rather than only compressing the original. &lt;a href="/products/image-optimisation-and-transformation/"&gt;Peakhour image optimisation&lt;/a&gt; can generate AVIF or WebP outputs, choose responsive sizes, and cache the resulting variants. That helps LCP when the largest visible element is an image, and it helps CLS when dimensions are kept stable.&lt;/p&gt;
&lt;p&gt;For CSS and JavaScript, remove unused files where possible, defer non-critical scripts, self-host critical third-party assets when practical, and reserve &lt;code&gt;preconnect&lt;/code&gt; for third-party domains that genuinely affect the first view. Moving every script later can break dependencies, so test the actual page type rather than applying a generic rule across the whole theme.&lt;/p&gt;
&lt;h2&gt;Protect Expensive WordPress Paths&lt;/h2&gt;
&lt;p&gt;Performance and security meet at origin capacity. Login floods, XML-RPC abuse, aggressive crawlers, scraper traffic, and noisy plugin endpoints can consume PHP workers and database connections that should be serving real visitors. If those requests are filtered only after WordPress has loaded, the site can look like it has a speed problem when it really has an unsorted traffic problem.&lt;/p&gt;
&lt;p&gt;For WordPress, protection should be specific. &lt;code&gt;wp-login.php&lt;/code&gt;, &lt;code&gt;/wp-admin/&lt;/code&gt;, &lt;code&gt;xmlrpc.php&lt;/code&gt;, the REST API, and plugin-specific endpoints should have their own bot, WAAP, and rate-limit policy. WooCommerce needs separate handling again: public catalogue pages can often be cached, but cart, checkout, account, and payment paths must stay dynamic and private.&lt;/p&gt;
&lt;p&gt;This does not mean putting heavy checks in front of every visitor. It means making edge decisions before origin work: allow clean public page requests, serve cache hits, challenge or rate-limit suspicious login traffic, bypass cache for private sessions, and log what happened.&lt;/p&gt;
&lt;h2&gt;Measure the Outcome&lt;/h2&gt;
&lt;p&gt;The evidence should line up across tools. WebPageTest should show a faster main document on cache hits, fewer slow origin fetches, and a waterfall where critical resources are visible early. Lighthouse should show fewer render-blocking opportunities and less main-thread pressure. Core Web Vitals should move where the page had the relevant bottleneck: LCP for slow HTML or heavy hero media, CLS for unstable layout, and INP for JavaScript and interaction work.&lt;/p&gt;
&lt;p&gt;Peakhour evidence should add the delivery side: cache hit ratio, miss causes, purge state, &lt;code&gt;Cache-Status&lt;/code&gt;, image savings, shielded misses, blocked login or XML-RPC abuse, and origin request volume. That combination tells the site team whether WordPress is faster because visitors received lighter pages from the edge, because abusive traffic stopped draining origin, or because browser work was reduced.&lt;/p&gt;
&lt;p&gt;Fast WordPress is not a plugin list. It is a set of clear route decisions backed by before-and-after measurements.&lt;/p&gt;</content><category term="Performance"></category><category term="WordPress"></category><category term="Drupal"></category><category term="Core Web Vitals"></category><category term="Rate Limiting"></category><category term="Web Performance"></category><category term="Application Security"></category></entry><entry><title>Boost Your Website Speed with Peakhour's Full Page Caching</title><link href="https://www.peakhour.io/blog/wordpress-plugin/" rel="alternate"></link><published>2019-04-02T13:00:00+11:00</published><updated>2019-04-02T13:00:00+11:00</updated><author><name>Dan</name></author><id>tag:www.peakhour.io,2019-04-02:/blog/wordpress-plugin/</id><summary type="html">&lt;p&gt;Experience a significant boost in website speed and performance with Peakhour's Full Page Caching feature, now easily accessible through our Wordpress plugin.&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Why Full Page Caching Matters&lt;/h2&gt;
&lt;p&gt;Site speed affects user experience, conversion, and server load. Slow pages can increase bounce rates and cost revenue. &lt;a href="/blog/opencart/opencart-3-caching-plugin/"&gt;Full Page&lt;/a&gt; Caching improves response times by storing and serving static versions of dynamic pages. This reduces load on your server and gives visitors quicker page loads.&lt;/p&gt;
&lt;h2&gt;How Peakhour Optimises Your Site&lt;/h2&gt;
&lt;p&gt;Peakhour helps speed up and secure your website with a DNS change. Unlike basic caching solutions, Peakhour serves these static pages from its global ANYCast network. Your site's visitors download content from a server close to them, reducing latency and speeding up downloads.&lt;/p&gt;
&lt;h2&gt;Peakhour's Transparent Caching and Delivery&lt;/h2&gt;
&lt;p&gt;In addition to Full Page Caching, Peakhour can act as a transparent delivery and cache layer. It caches and optimises static assets like CSS, JavaScript, and images. You don't need to make any other changes to your site; a DNS change is all it takes.&lt;/p&gt;
&lt;h2&gt;Wordpress Plugin for Easy Integration&lt;/h2&gt;
&lt;p&gt;During our beta phase, many clients used early versions of our WordPress plugin. The plugin integrates with Peakhour's API to automate content flushing when you make edits in the WordPress admin panel. This simplifies publishing and allows you to set longer lifetimes for your dynamic content in our global cache.&lt;/p&gt;
&lt;h2&gt;Improved Performance Metrics&lt;/h2&gt;
&lt;p&gt;With Peakhour, sites can see faster download times, a higher cache hit rate, and reduced load on the origin server. Site owners get lower origin demand; visitors get faster pages.&lt;/p&gt;</content><category term="CMS"></category><category term="Caching"></category><category term="Web Performance"></category><category term="WordPress"></category><category term="Drupal"></category><category term="CDN"></category><category term="Rate Limiting"></category></entry></feed>