# Threat Protection — Portal Policy Template Bundles

This folder contains **threat-protection** policy template bundles for the Layer7 API Developer Portal. The Portal Templates Guide places this kind of template in the **Threat Protection** category, which is recommended to run **first** in any Policy Template Category chain — *before* authentication, validation, or routing — so that obvious attacks are dropped at the edge before any further processing is performed (see the [Layer7 API Developer Portal Policy Templates Guide](../Layer7%20API%20Developer%20Portal%20Policy%20Templates%20Guide.md) for category guidance).

## Bundles in this folder

### `ThreatProtection-1.0.0.json`

Installs the **`ThreatProtection-1.0`** template. A single composable template that layers every Layer7 API Gateway threat-protection assertion that is generally appropriate for REST/JSON and SOAP/XML APIs:

1. **Request size limit** — `Limit Message Size` (Gateway `<L7p:RequestSizeLimit>`) capped at the publisher-supplied `maxRequestSizeBytes` value. Returns **`413 Payload Too Large`** if exceeded.
2. **SQL injection protection** — `Protect Against SQL Attacks` (`<L7p:SqlAttackProtectionAssertion>`) targeting the URL **query string** and **request body** (the URL path is excluded to avoid false positives on routing tokens). Conservative protection set: `MsSql`, `OraSql`, `MetaText`. Avoids `SqlMeta` on its own (high false-positive rate against legitimate apostrophes/dashes in human-readable fields). Returns **`400 Bad Request`** on detection.
3. **Cross-site scripting protection** — `Protect Against Cross-Site Scripting` (`<L7p:CrossSiteScriptingProtectionAssertion>`) targeting URL query string + body. Returns **`400`** on detection.
4. **Generic code-injection protection** — `Protect Against Code Injection` (`<L7p:CodeInjectionProtectionAssertion>`) targeting URL query string + body. Conservative protection set: `htmlJavaScriptInjection` only. Add `phpEvalInjection`, `shellInjection`, `ldapDnInjection`, and/or `ldapSearchInjection` in environments where they are warranted (they have higher false-positive rates against natural-language content). Returns **`400`** on detection.
5. **Document-structure threat protection (content-type aware)** — branches on the inbound `Content-Type` header so JSON-only and XML-only assertions are never run against the wrong payload type:
   - `Content-Type` contains `json` → `Protect Against JSON Document Structure Threats` (`<L7p:JsonDocumentStructureAssertion>`) with the limits below.
   - `Content-Type` contains `xml` → `Protect Against Document Structure Threats` (`<L7p:OversizedTextAssertion>`) with the limits below.
   - Anything else (e.g. `application/x-www-form-urlencoded`, no body) → skipped.
   Returns **`400`** on detection.
6. **Error response** — on detection, the fragment returns a JSON body of the form

   ```json
   { "error": { "code": <status>, "message": "<reason>" } }
   ```

   with the appropriate HTTP status, then short-circuits the parent policy with `<L7p:FalseAssertion/>`. The body intentionally does **not** echo the offending payload (avoids leaking which rule fired to a probing attacker).

The fragment runs each step in sequence and **short-circuits subsequent steps once any check has set `errorStatus`**, so a request rejected for SQL injection is not also evaluated against the XSS, code-injection, or document-structure rules. This keeps cost predictable on rejected traffic.

**Default tunings (intentionally conservative)** — the limits are set to be safe defaults for typical API traffic. Tighten or loosen them by editing the `<L7p:JsonDocumentStructureAssertion>`, `<L7p:OversizedTextAssertion>`, and protection-list elements directly in the policy fragment after import.

| Limit | Default | Set in |
| --- | --- | --- |
| Max request payload size | publisher-supplied (`maxRequestSizeBytes` *) | `Limit Message Size` |
| JSON max container depth | `20` | `<L7p:MaxContainerDepth>` |
| JSON max object entries | `500` | `<L7p:MaxObjectEntryCount>` |
| JSON max array entries | `1000` | `<L7p:MaxArrayEntryCount>` |
| JSON max entry-name length | `256` | `<L7p:MaxEntryNameLength>` |
| JSON max string-value length | `65 536` | `<L7p:MaxStringValueLength>` |
| XML max contiguous text chars | `1 048 576` | `<L7p:MaxTextChars>` |
| XML max attribute value chars | `2 048` | `<L7p:MaxAttrChars>` |
| XML max element nesting depth | `32` | `<L7p:MaxNestingDepth>` |

**Arguments (inputs)**

| Name | Visible to publisher | Notes |
| --- | --- | --- |
| `portal.managed.service.apiId` | hidden (`guiPrompt: false`) | auto-populated by the Portal; used to set `portal.analytics.api.uuid`. |
| `maxRequestSizeBytes` | **mandatory** (`Max Request Payload Size in Bytes (e.g. 1048576 = 1 MB) *`) | Drives the `Limit Message Size` assertion. Must be a positive integer expressed in bytes. |

**Exported context variables (outputs):** `errorStatus`, `errorReason`, `portal.analytics.action`, `portal.analytics.api.uuid`, `portal.analytics.response.code`. These are exposed via `<L7p:ExportVariables>` so a parent template (or the Portal's global analytics policy) can read them after the fragment runs.

**Analytics behaviour** — the fragment always sets `portal.analytics.action` (`${request.http.uri}`) and `portal.analytics.api.uuid` (`${portal.managed.service.apiId}`). On rejection, it additionally sets `portal.analytics.response.code` to the chosen HTTP status (`400` or `413`) so the global Portal analytics policy records the rejection alongside any successful traffic. `portal.analytics.authType` is intentionally *not* set here — this template runs before authentication and that variable is the authentication template's responsibility.

## Where this template fits in a Portal policy chain

The intended order in a Portal policy template chain is:

1. **`ThreatProtection-1.0`** *(this bundle)* — runs first. Drops oversized, malformed, or obviously malicious requests at the edge.
2. **Authentication** — one of [`../Authentication/*`](../Authentication) runs next.
3. **Per-Organization rate/quota** — e.g. [`../RateQuota/OrgLevelRLQ-1.0`](../RateQuota), if applicable.
4. **Per-API rate/quota** — Portal's Standard system templates.
5. **Request validation** — e.g. [`../RequestValidation/ValidateOpenAPISample-1.0`](../RequestValidation).
6. **Routing** — e.g. [`../Routing/RouteRequest-1.0`](../Routing).

Placing threat protection first means cheap pattern-matching checks reject malicious traffic before more expensive assertions (cryptographic auth, schema validation, backend routing) are invoked.

## Customising the bundle

- **Tightening limits.** Edit the `<L7p:JsonDocumentStructureAssertion>`, `<L7p:OversizedTextAssertion>`, and protection-list elements in the policy fragment to match your APIs' actual payload shapes. The defaults are deliberately permissive to avoid false positives on a generic starter template.
- **Adding code-injection protections.** The bundle ships with `htmlJavaScriptInjection` only. To also catch shell, PHP-eval, or LDAP injection, add additional `<L7p:item protectionType="..."/>` entries inside `<L7p:Protections codeInjectionProtectionTypeArray="included">` (supported values: `htmlJavaScriptInjection`, `hexEncodedInjection`, `phpEvalInjection`, `shellInjection`, `ldapDnInjection`, `ldapSearchInjection`).
- **Adding SQL protections.** To enable the more invasive SQL meta-character matching (catches single-tick attacks but produces more false positives on natural language), add `<L7p:item protectionType="SqlMeta"/>` to `<L7p:Protections sqlProtectionTypeArray="included">`.
- **Per-API customisation via the Portal.** Because the template is parameterised on `maxRequestSizeBytes`, publishers can already tune the size budget per API without editing policy. To expose additional knobs (e.g. per-API JSON depth limit), add a new encass argument and reference it from the corresponding `<L7p:Max...>` element via a context variable.

## Conventions

Bundles in this folder follow the same conventions as the other Portal Templates in this repository:

- Distributed as a `*-<version>.json` policy bundle (schema `11.2.1`, `defaultAction: NEW_OR_UPDATE`).
- Installs a policy fragment under `/Portal Templates/` and an encapsulated assertion in the Policy Manager assertion palette (`customAssertions` palette folder).
- Designed to be composed with the bundles under [`../Authentication/`](../Authentication), [`../RateQuota/`](../RateQuota), [`../RequestValidation/`](../RequestValidation), and [`../Routing/`](../Routing) so that threat protection runs first and authentication, validation, and routing follow.

Contributions are welcome — drop a new `*-<version>.json` bundle into this folder and add a corresponding entry in the **Bundles in this folder** section above.
