Jak správně používat POST odkazy
Ve webových aplikacích, zejména v administrativních rozhraních, by mělo být základním pravidlem, že akce měnící stav serveru by neměly být prováděny prostřednictvím HTTP metody GET. Jak název metody napovídá, GET by měl sloužit pouze k získání dat, nikoli k jejich změně. Pro akce jako třeba mazání záznamů je vhodnější použít metodu POST. I když ideální by byla metoda DELETE, ale tu nelze bez JavaScriptu vyvolat, proto se historicky používá POST.
Jak na to v praxi? Využijte tento jednoduchý trik. Na začátku šablony si vytvoříte pomocný formulář
s identifikátorem postForm
, který následně použijete pro mazací tlačítka:
<form method="post" id="postForm"></form>
Díky tomuto formuláři můžete místo klasického odkazu <a>
použít tlačítko
<button>
, které lze vizuálně upravit tak, aby vypadalo jako běžný odkaz. Například CSS framework
Bootstrap nabízí třídy btn btn-link
se kterými dosáhnete toho, že tlačítko nebude vizuálně odlišné od
ostatních odkazů. Pomocí atributu form="postForm"
ho provážeme s předpřipraveným formulářem:
<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>
Při kliknutí na odkaz se nyní vyvolá akce delete
. Pro zajištění, že požadavky budou přijímány pouze
prostřednictvím metody POST a z téže domény (což je účinná obrana proti CSRF útokům), použijte atribut
#[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); // hypotetický kód mazající záznam
$this->redirect('default');
}
}
Atribut existuje od Nette Application 3.2 a více o jeho možnostech se dozvíte na stránce Jak používat atribut #Requires.
Pokud byste místo akce actionDelete()
používali signál handleDelete()
, není nutné uvádět
sameOrigin: true
, protože signály mají tuto ochranu nastavenou implicitně:
#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
$this->facade->deletePost($id);
$this->redirect('this');
}
Tento přístup nejenže zlepšuje bezpečnost vaší aplikace, ale také přispívá k dodržování správných webových standardů a praxe. Využitím metod POST pro akce měnící stav dosáhnete robustnější a bezpečnější aplikace.