# CSRF protection for MENA portals: a request review

A procurement manager is signed into a portal when another website induces the browser to submit a change to it. The request carries a valid session cookie. The manager never approved the change.

That is the failure a cross-site request forgery (CSRF) defence must prevent. Microsoft's [ASP.NET Core antiforgery guide](https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-10.0) explains why automatically attached credentials create this risk and why HTTPS alone does not remove it. Authentication identifies the session; it does not establish that a request came through the intended application workflow.

For teams building Arabic-English business portals, the difficult cases often sit around the main form: a second application on a sibling subdomain, an expired session, or a provider returning a browser to the portal. This guide proposes a review for cookie-authenticated administrative actions. It is an engineering design, not a penetration-test result or a claim of national compliance.

*Cover: original SultanByte artwork showing a browser request passing through request-context and token checks before a protected change.*

## Map the routes that can change something

Start with a bounded workflow, such as changing a supplier's contact details. List every endpoint that can perform that change, including legacy forms and alternate API routes. Record the authentication mechanism and accepted request formats beside each route.

Do not classify the whole application as safe because its main frontend uses JSON. A forgotten form handler can expose the same business action through a different path. In the proposed review, the unit of coverage is an executable route, not a framework badge.

Keep ordinary navigation separate from mutations. [Django's CSRF documentation](https://docs.djangoproject.com/en/5.2/ref/csrf/) requires safe methods such as GET to be free of dangerous side effects. A link that approves a supplier or changes an email address needs redesign, not a reassuring confirmation message after the action.

For a hypothetical UAE deployment and Saudi deployment, maintain separate route and origin inventories where their hostnames or integrations differ. These are implementation boundaries, not different CSRF laws. An Arabic locale does not select a security policy, and a country selector must not expand the trusted-origin list.

## Use the framework's token contract

[OWASP's CSRF prevention guidance](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) recommends using maintained framework protection before inventing a token scheme. For a stateful application, its synchronizer-token pattern requires the server to validate the submitted token against the session. Tokens belong in the supported form field or request header, not URLs or routine logs.

Treat that mechanism as an integration contract. The form renderer must issue the expected value, the browser must submit it through the documented channel, and the server must validate it before applying the change. A token visible in HTML proves only that one part exists.

Django 5.2 provides a concrete example: its CSRF middleware checks unsafe requests, validates Origin when present and performs strict Referer checking for HTTPS requests without Origin. Its secret changes at login. Those are version-specific framework behaviours, not instructions to copy Django's cookie format into another stack.

For the proposed portal, keep a route-level test that removes the submitted token while retaining the authenticated session. Require rejection and an unchanged business record. Repeat through the deployed reverse proxy rather than testing only a development controller.

## Same-site is a wider boundary than same-origin

The [IETF's cookie specification draft](https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html#attribute-samesite) distinguishes the site boundary from an individual host. A portal and another HTTPS application on a sibling subdomain can be same-site without being the same origin. That matters when one sibling hosts less-trusted content or is operated by a different team.

Choose cookie attributes deliberately. SameSite=Strict restricts cross-site use more than Lax, but can also omit the cookie on an initial navigation from another site. Lax permits certain top-level navigations. SameSite=None requires Secure, and browser restrictions can still affect cross-site cookie availability.

For this design, document why the session cookie needs its selected setting and test the actual entry paths. Avoid changing every cookie to None because one provider handoff failed. Investigate whether the affected route needs the main session cookie at all and whether the integration offers a more narrowly scoped return mechanism.

Give every trusted sibling an owner. An organisation's domain suffix is not, by itself, an adequate approval record for every application deployed beneath it.

## Add a request-context check without creating a bypass

The [W3C Fetch Metadata working draft](https://www.w3.org/TR/fetch-metadata/) defines Sec-Fetch-Site values including same-origin, same-site, cross-site and none. They describe the relationship between the request initiator and destination. They do not identify the user or authorize a supplier update.

For the ordinary administrative routes proposed here, reject cross-site mutation attempts. Treat same-site requests as a separate decision rather than automatically granting every sibling access. Retain the framework's token validation and explicitly configured origin policy.

Write down the missing-header behaviour too. In this design, an absent or unusable metadata value does not skip protection: the request must still satisfy the approved framework checks, or the application refuses the mutation. Test supported embedded browsers before promising compatibility.

Keep protocol callbacks outside this ordinary-route rule only when their own reviewed validation justifies it. Record the exact callback route, expected initiator and required verification. Do not exempt an entire API prefix merely to make one callback work.

![Proposed CSRF review: identify the mutation route, validate request context, validate the framework token, then check current permission before changing the record. Reject failed checks without performing the business action.](https://cdn.hashnode.com/uploads/covers/60ecf4a0fc37a15ec15655e8/ff55af6d-42fc-41b5-8582-f6c412554287.png)

*Original infographic: SultanByte. Proposed review framework informed by OWASP, Django, WHATWG and W3C documentation, October 2026. It shows design responsibilities, not measured security performance.*

## A CORS error does not prove the action was blocked

The [WHATWG Fetch Standard's CORS protocol](https://fetch.spec.whatwg.org/#http-cors-protocol) governs cross-origin response sharing and preflight handling. A browser refusing to expose a response to JavaScript is not equivalent to the server refusing to execute the request.

For credentialed response sharing, the standard does not permit Access-Control-Allow-Origin: * with credentials mode include. An explicit permitted origin and the appropriate credentials response header are required. That still leaves the application responsible for its mutation policy.

In the proposed API review, test whether an endpoint accepts a browser-submittable form format as well as JSON. Require each accepted format to follow the intended protection path. Do not rely on a frontend convention that says callers normally send a custom header if the server accepts requests without it.

Keep the browser's destination under application control. OWASP also warns about client-side CSRF, where trusted application JavaScript constructs requests from attacker-controlled input. A valid token cannot rescue a client that sends it with the wrong action because a URL parameter told it to.

## Check permission after establishing request legitimacy

[OWASP's authorization guidance](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) requires permission checks on every request. A valid CSRF token must not become permission to edit an arbitrary tenant's supplier.

For the supplier workflow, derive the active tenant from verified application context, load the record within that scope and check the requested action against current permissions. Validate the allowed fields and business transition before committing. These are separate responsibilities from the CSRF check, even if middleware performs some of them together. The diagram groups review responsibilities; it does not prescribe middleware order. Follow the framework's documented sequencing.

The product review should distinguish an ordinary contact edit from a bank-detail change or approval. If a consequential action needs reauthentication or a separate approver, specify that workflow explicitly. A CSRF token is not a signature over the business details the person reviewed.

Do not describe this defence as an answer to script injection. OWASP notes that XSS can defeat CSRF mitigations. Keep the application's injection controls and [CSP rollout](https://www.sultanbyte.com/content-security-policy-mena-portals-rollout) under a separate review.

## Make rejection recoverable in Arabic and English

The recovery screen is part of the implementation. In this design, a confirmed pre-mutation rejection tells the user that the change was not applied and offers a safe route to reload or sign in again. A network timeout has a different outcome: the interface must establish what happened before claiming that nothing changed.

Preserve entered work only under the product's approved account and device policy. Do not silently replay a sensitive submission after a new login. Show the user the current record and require a deliberate submission through the renewed session.

[W3C's status-message guidance](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html) explains how changes such as errors or completion notices can be exposed to assistive technology without moving focus. Apply that to inline rejection messages where appropriate. A new page or dialog changes the interaction and needs its own focus behaviour.

Test the full recovery in both languages, including long Arabic messages, mixed-script identifiers and enlarged text. The acceptance question is whether someone understands the next step without losing track of the record being edited.

## Release against failed requests as well as successful ones

Use synthetic accounts and records in an authorised test environment. The following are proposed acceptance checks, not reported test results:

- Submit a valid edit through each supported interface and confirm the intended record changes.
- Remove or corrupt the submitted CSRF token while retaining the session. Confirm rejection before mutation.
- Submit from an unrelated test origin, then from an unapproved sibling origin. Inspect server state, not only browser console errors.
- Omit Fetch Metadata headers and exercise the documented fallback. Confirm that missing metadata does not disable token or origin checks.
- Reopen an old form after login changes. Require an understandable recovery path rather than a blanket exemption.
- Attempt an authorised-looking request against another tenant's record. Require the separate permission check to deny it.
- Exercise each genuine provider return route and verify that its exception cannot be reused for an ordinary administrative action.

Keep the route inventory, exception owners and rejection reasons in the release record. Record categories rather than raw tokens or session cookies. For a CTO evaluating a portal, ask the supplier to demonstrate both a legitimate edit and a forged request that leaves the database unchanged. For engineers, keep those tests beside the route implementation so the next alternate endpoint does not quietly bypass the protection.

