Wie man POST-Links richtig verwendet

In Webanwendungen, insbesondere in Verwaltungsschnittstellen, sollte es eine Grundregel sein, dass Aktionen, die den Zustand des Servers verändern, nicht über die HTTP-GET-Methode durchgeführt werden sollten. Wie der Name der Methode schon sagt, sollte GET nur zum Abrufen von Daten verwendet werden, nicht zum Ändern. Für Aktionen wie das Löschen von Datensätzen ist es angemessener, die POST-Methode zu verwenden. Ideal wäre die Verwendung der DELETE-Methode, die jedoch ohne JavaScript nicht aufgerufen werden kann, weshalb in der Regel POST verwendet wird.

Wie macht man das in der Praxis? Verwenden Sie diesen einfachen Trick. Erstellen Sie am Anfang Ihrer Vorlage ein Hilfsformular mit dem Bezeichner postForm, das Sie dann für die Schaltflächen zum Löschen verwenden werden:

<form method="post" id="postForm"></form>

Mit diesem Formular können Sie ein <button> anstelle des klassischen <a> Link verwenden, der visuell so verändert werden kann, dass er wie ein normaler Link aussieht. Das Bootstrap-CSS-Framework bietet zum Beispiel die Klassen btn btn-link an, mit denen die Schaltfläche optisch nicht von anderen Links zu unterscheiden ist. Mit dem Attribut form="postForm" verknüpfen wir sie mit dem vorbereiteten Formular:

<table>
	<tr n:foreach="$posts as $post">
		<td>{$post->title}</td>
		<td>
			<button class="btn btn-link" form="postForm" formaction="{link delete $post->id}">delete</button>
			<!-- instead of <a n:href="delete $post->id">delete</a> -->
		</td>
	</tr>
</table>

Beim Anklicken des Links wird nun die Aktion delete aufgerufen. Um sicherzustellen, dass Anfragen nur über die POST-Methode und von der gleichen Domäne akzeptiert werden (was ein wirksamer Schutz gegen CSRF-Angriffe ist), verwenden Sie das #[Requires] Attribut:

use Nette\Application\Attributes\Requires;

class AdminPresenter extends Nette\Application\UI\Presenter
{
	#[Requires(methods: 'POST', sameOrigin: true)]
	public function actionDelete(int $id): void
	{
		$this->facade->deletePost($id); // hypothetical code for deleting a record
		$this->redirect('default');
	}
}

Das Attribut ist seit Nette Application 3.2 verfügbar, und Sie können mehr über seine Möglichkeiten auf der Seite How to use the #Requires attribute erfahren.

Wenn Sie das Signal handleDelete() anstelle der Aktion actionDelete() verwenden, ist es nicht notwendig, sameOrigin: true anzugeben, da Signale diesen Schutz implizit gesetzt haben:

#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
	$this->facade->deletePost($id);
	$this->redirect('this');
}

Dieser Ansatz verbessert nicht nur die Sicherheit Ihrer Anwendung, sondern trägt auch zur Einhaltung der richtigen Webstandards und -praktiken bei. Durch die Verwendung von POST-Methoden für zustandsändernde Aktionen erreichen Sie eine robustere und sicherere Anwendung.