Πώς να χρησιμοποιείτε σωστά τους συνδέσμους POST

Σε web εφαρμογές, ειδικά σε διαχειριστικά interfaces, θα έπρεπε να είναι βασικός κανόνας ότι οι ενέργειες που αλλάζουν την κατάσταση του server δεν θα έπρεπε να εκτελούνται μέσω της μεθόδου HTTP GET. Όπως υποδηλώνει το όνομα της μεθόδου, η GET θα έπρεπε να χρησιμεύει μόνο για τη λήψη δεδομένων, όχι για την αλλαγή τους. Για ενέργειες όπως η διαγραφή εγγραφών, είναι προτιμότερη η χρήση της μεθόδου POST. Αν και η ιδανική θα ήταν η μέθοδος DELETE, αλλά αυτή δεν μπορεί να κληθεί χωρίς JavaScript, γι' αυτό ιστορικά χρησιμοποιείται η POST.

Πώς να το κάνετε στην πράξη; Χρησιμοποιήστε αυτό το απλό κόλπο. Στην αρχή του template, δημιουργήστε μια βοηθητική φόρμα με το αναγνωριστικό postForm, την οποία στη συνέχεια θα χρησιμοποιήσετε για τα κουμπιά διαγραφής:

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

Χάρη σε αυτή τη φόρμα, μπορείτε αντί για τον κλασικό σύνδεσμο <a> να χρησιμοποιήσετε ένα κουμπί <button>, το οποίο μπορεί να διαμορφωθεί οπτικά ώστε να μοιάζει με συνηθισμένο σύνδεσμο. Για παράδειγμα, το CSS framework Bootstrap προσφέρει τις κλάσεις btn btn-link με τις οποίες επιτυγχάνετε το κουμπί να μην διαφέρει οπτικά από τους άλλους συνδέσμους. Με το attribute form="postForm" το συνδέουμε με την προετοιμασμένη φόρμα:

<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>

Κατά το κλικ στον σύνδεσμο, καλείται τώρα η ενέργεια delete. Για να διασφαλίσετε ότι τα αιτήματα θα γίνονται δεκτά μόνο μέσω της μεθόδου POST και από τον ίδιο τομέα (που είναι μια αποτελεσματική άμυνα κατά των επιθέσεων CSRF), χρησιμοποιήστε το attribute #[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); // υποθετικός κώδικας που διαγράφει την εγγραφή
		$this->redirect('default');
	}
}

Το attribute υπάρχει από το Nette Application 3.2 και περισσότερα για τις δυνατότητές του θα μάθετε στη σελίδα Πώς να χρησιμοποιήσετε το attribute #Requires.

Αν αντί για την ενέργεια actionDelete() χρησιμοποιούσατε το σήμα handleDelete(), δεν είναι απαραίτητο να αναφέρετε sameOrigin: true, επειδή τα σήματα έχουν αυτή την προστασία ρυθμισμένη από προεπιλογή:

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

Αυτή η προσέγγιση όχι μόνο βελτιώνει την ασφάλεια της εφαρμογής σας, αλλά συμβάλλει επίσης στην τήρηση των σωστών web προτύπων και πρακτικών. Χρησιμοποιώντας τις μεθόδους POST για ενέργειες που αλλάζουν την κατάσταση, επιτυγχάνετε μια πιο στιβαρή και ασφαλή εφαρμογή.