Knowledge base

PMTA knowledge base›Block Global›Directive§ 3.3.1.58.4

http-csrf-protection

Globalrestart required

Protecting the web monitor from requests forged by someone else's page
in the configuration this is a linehttp-csrf-protection trueinside the block Global
Why someone else’s browser tab cannot stop your node

The attack this line protects against is simple: a person with the monitor open visits an unrelated page, and that page sends a request to the node from their browser. The browser sends it on its own, and to the monitor it looks like an action by a legitimate user.

The protection does two things. First, it forbids changing state with a GET request — and GET is exactly what any image or link on someone else’s page can send. Second, it requires a POST to carry either an API key or a session token obtained by a previous request to the monitor.

It is enabled by default (true) and does not get in the way in normal operation. It gets in the way of old applications that are used to changing the node’s state with a plain link.

A key does not pass the protection, it replaces it. A request with a valid http-api-key is accepted without a session token — by design: a program has no browser, and its request cannot be forged from outside.

The main trap is disabling protection for the sake of one old application. It is disabled for the whole node and for everyone, including the administrator’s browser with a monitor tab open. The right workaround is to teach the application to come with a key: then protection can stay enabled.
What the Hub does. It does not write it — it leaves it enabled. The Hub calls the monitor with a key, so the protection does not get in its way at all: it has no browser, and the key is the allowed way.
Recommended values

There is almost never a need to disable it:

Value When
true (default) always
false an old application changes state via GET and cannot be rewritten

Before disabling, it is worth trying a key: an application with a key works with protection enabled.

The true default, the ban on state-changing GETs and the requirement of a key or session token on POST come from the manual (§ 3.3.1.58.4). The explanation of the attack itself and the advice to try a key instead of disabling are ours.
Example configuration
# disable it only for a specific application and with a recorded reason
http-mgmt-port 1000
http-csrf-protection false   # application X changes state via GET
A comment with the reason is mandatory: the line weakens protection for the whole node for the sake of one client, and a year later nobody will remember why.
yellow — — directive names, blue — blocks. They are highlighted the same way in the text of the card.
▲

Common mistakes and problems

what people get wrong and how it ends2 mistakes▶

Disabling protection instead of giving the application a key

our experience

What it costsProtection is removed from the whole node and from all clients, including the administrator’s browser. The whole surface is opened for the sake of one application.
How to spot itThe configuration has false, while an API key is declared.
How to do it rightTeach the application to send the key in a header and return to true.

Treating protection as a replacement for the address restriction

§ 3.3.1.58.4

What it costsIt protects against a forged request, not a direct one. Anyone who has reached the port and is on the access list uses the monitor freely.
How to spot itProtection is enabled, but the http-access list is wide.
How to do it rightNarrow the address list; forgery protection is a different line of defense, not a replacement for it.
Compatibility
PowerMTA 6.0
described in the manual of this version · platform: any
The vendor does not state the first version for every directive — there is no note here. The name also appears in the 5.0 edition of the manual.
Reference data
Syntax
http-csrf-protection <boolean>
Values
yes | no | true | false
Default
true § 3.3.1.58.4
Applying
a service restart is required
Queue
will not touch what is already queued
Where to write it
Global
How many times
once in the block
Everything here comes from the manual, with the section.
Inheritance
There is no inheritance: the line is written at the root of the file, in the Global section, and applies to the whole management interface. Protection cannot be disabled selectively — for one address or one application.
How to check on the node
We check with exactly what the protection forbids — a state-changing GET request without a key, from an allowed address:
curl -s -o /dev/null -w '%{http_code}\n' 'http://NODE:1000/command?command=show+version'
A refusal means the protection works. Success without a key means it is disabled. The same request with the X-API-Key header should go through in both cases.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Node security