Wie man POST-Links richtig verwendet

In Webanwendungen, insbesondere in administrativen Oberflächen, sollte es eine Grundregel sein, dass Aktionen, die den Serverzustand ändern, nicht über die HTTP-Methode GET durchgeführt werden sollten. Wie der Name der Methode andeutet, sollte GET nur zum Abrufen von Daten verwendet werden, nicht zu deren Änderung. Für Aktionen wie das Löschen von Datensätzen ist es besser, die POST-Methode zu verwenden. Obwohl die DELETE-Methode ideal wäre, kann sie ohne JavaScript nicht aufgerufen werden, daher wird historisch POST verwendet.

Wie geht das in der Praxis? Nutzen Sie diesen einfachen Trick. Am Anfang des Templates erstellen Sie ein Hilfsformular mit dem Bezeichner postForm, das Sie anschließend für die Löschbuttons verwenden:

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

Dank dieses Formulars können Sie anstelle eines klassischen Links <a> einen Button <button> verwenden, der visuell so angepasst werden kann, dass er wie ein normaler Link aussieht. Beispielsweise bietet das CSS-Framework Bootstrap die Klassen btn btn-link, mit denen Sie erreichen, dass der Button visuell nicht von anderen Links zu unterscheiden ist. Mit dem Attribut form="postForm" verknüpfen wir ihn 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}">löschen</button>
			<!-- anstelle von <a n:href="delete $post->id">löschen</a> -->
		</td>
	</tr>
</table>

Beim Klicken auf den Link wird nun die Aktion delete aufgerufen. Um sicherzustellen, dass Anfragen nur über die POST-Methode und von derselben Domain akzeptiert werden (was eine wirksame Verteidigung gegen CSRF-Angriffe ist), verwenden Sie das Attribut #[Requires]:

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); // hypothetischer Code zum Löschen des Datensatzes
		$this->redirect('default');
	}
}

Das Attribut existiert seit Nette Application 3.2 und mehr über seine Möglichkeiten erfahren Sie auf der Seite Wie man das Attribut #Requires verwendet.

Wenn Sie anstelle der Aktion actionDelete() das Signal handleDelete() verwenden würden, ist es nicht notwendig, sameOrigin: true anzugeben, da Signale diesen Schutz implizit eingestellt 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 korrekter Webstandards und Praktiken bei. Durch die Verwendung von POST-Methoden für zustandsändernde Aktionen erreichen Sie eine robustere und sicherere Anwendung.