Skip to content

Commit

Permalink
x
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Apr 20, 2024
1 parent 0e5f32f commit 4027d98
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 0 deletions.
1 change: 1 addition & 0 deletions best-practices/cs/@home.texy
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Nette Aplikace
- [Stránkování výsledků databáze |pagination]
- [Dynamické snippety |dynamic-snippets]
- [Jak používat atribut #Requires |attribute-requires]
- [Jak správně používat POST odkazy |post-links]

</div>
<div>
Expand Down
2 changes: 2 additions & 0 deletions best-practices/cs/attribute-requires.texy
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class AdminPresenter extends Nette\Application\UI\Presenter
}
```

Proč byste měli používat POST místo GET pro akce měnící stav a jak na to? [Přečtěte si návod |post-links].

Můžete uvést metodu nebo pole metod. Speciálním případem je hodnota `'*'`, která povolí všechny metody, což standardně presentery z [bezpečnostních důvodů nedovolují |application:presenters#toc-kontrola-http-metody].


Expand Down
52 changes: 52 additions & 0 deletions best-practices/cs/post-links.texy
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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:

```latte .{file:@layout.latte}
<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ů:

```latte .{file:admin.latte}
<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]`: (vyžaduje Nette Application 3.2)

```php .{file:AdminPresenter.php}
#[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');
}
```

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

```php
#[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.


{{sitename: Best Practices}}
2 changes: 2 additions & 0 deletions best-practices/en/attribute-requires.texy
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class AdminPresenter extends Nette\Application\UI\Presenter
}
```

Why should you use POST instead of GET for state changing actions and how to do it? [Read the guide |post-links].

You can specify a method or an array of methods. A special case is the value `'*'` to enable all methods, which presenters do not allow by default for [security reasons |application:presenters#http-method-check].


Expand Down
52 changes: 52 additions & 0 deletions best-practices/en/post-links.texy
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
How to Properly Use POST Links
******************************

In web applications, especially in administrative interfaces, it should be a basic rule that actions changing the state of the server should not be performed via the HTTP GET method. As the method name suggests, GET should be used only to retrieve data, not to change it.
For actions such as deleting records, it is more appropriate to use the POST method. Although the ideal would be to use the DELETE method, this cannot be invoked without JavaScript, hence POST is historically used.

How to do it in practice? Use this simple trick. At the beginning of your template, create a helper form with the identifier `postForm`, which you will then use for the delete buttons:

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

With this form, you can use a `<button>` instead of the classic `<a>` link, which can be visually modified to look like a regular link. For example, the Bootstrap CSS framework offers the classes `btn btn-link` which allow the button to be visually indistinguishable from other links:

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

When clicking the link, the `delete` action is now invoked. To ensure that requests are accepted only through the POST method and from the same domain (which is an effective defense against CSRF attacks), use the `#[Requires]` attribute: (requires Nette Application 3.2)

```php
#[Requires(methods: 'POST', sameOrigin: true)]
public function actionDelete(int $id): void
{
$this->facade->deletePost($id); // hypothetical code for deleting a record
$this->redirect('default');
}
```

If you were using the signal `handleDelete()` instead of the action `actionDelete()`, it is not necessary to specify `sameOrigin: true`, because signals have this protection set implicitly:

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

This approach not only improves the security of your application but also contributes to adhering to proper web standards and practices. By using POST methods for state-changing actions, you achieve a more robust and secure application.


{{sitename: Best Practices}}

0 comments on commit 4027d98

Please sign in to comment.