Nette Documentation Preview

syntax
弱点からの保護
*******

.[perex]
ときおり、また別の名だたるウェブサイトで重大な安全の欠陥が公表されたり、実際に悪用されたりします。いやなことです。ウェブアプリケーションの安全を大切に思うなら、Nette Framework は間違いなく最良の選択です。


Cross-Site Scripting (XSS)
==========================

Cross-Site Scripting は、エスケープされていない出力を悪用してウェブサイトを乱す手口です。攻撃者は自分のコードをページに差し込み、ページを書き換えたり、訪問者の機微なデータを手に入れたりできてしまいます。XSS に対する守りには、出力されるすべての文字列を一貫して正しくエスケープすることが要ります。開発者が一度でもそれを忘れれば、ウェブサイト全体が危うくなります。

攻撃の例としては、ページにコードを差し込む細工をした URL を利用者に渡すことが挙げられます。アプリケーションが出力をきちんとエスケープしていなければ、そのスクリプトは利用者のブラウザで動きます。こうしてたとえば、その人の身元が盗まれます。

```
https://example.com/?search=<script>alert('Successful XSS attack.');</script>
```

Nette Framework は画期的な [Context-Aware Escaping |latte:safety-first#コンテキストに応じたエスケープ]の技術を持ち込み、Cross-Site Scripting の危険を永久に取り除きます。文脈に応じてすべての出力を自動的にエスケープするので、開発者がうっかり何かを忘れることはありません。例を挙げましょうか。開発者が次のテンプレートを書いたとします。

```latte
<p onclick="alert({$message})">{$message}</p>

<script>
document.title = {$message};
</script>
```

`{$message}` という書き方は変数の出力を意味します。ほかのフレームワークでは出力ごとにはっきりエスケープしなければならず、しかも場所ごとに違うやり方が要ります。Nette Framework では何もエスケープする必要がなく、すべてが自動的に、正しく、一貫して行われます。変数を `$message = 'Width 1/2"'` にすると、フレームワークは次の HTML のコードを作ります。

```latte
<p onclick="alert(&quot;Width 1\/2\&quot;&quot;)">Width 1/2&quot;</p>

<script>
document.title = "Width 1\/2\"";
</script>
```


Cross-Site Request Forgery (CSRF)
=================================

Cross-Site Request Forgery の攻撃では、攻撃者が被害者をあるページへ誘い込み、そのページが被害者のブラウザの中で、被害者がログインしているサーバーへのリクエストをこっそり実行します。サーバーはそのリクエストが被害者の意思で行われたと信じてしまいます。こうして被害者の身元で、本人の知らないうちに操作が行われます。データの書き換えや削除、メッセージの送信などです。

Nette Framework は、フォームとプレゼンターのシグナルを別のドメインから送信したり起こしたりできないようにして、**この種の攻撃から自動的に守ります**。保護を切りたいなら、フォームでは次のようにします。

```php
$form->allowCrossOrigin();
```

シグナルの場合はアトリビュートを足します。

```php
use Nette\Application\Attributes\Requires;

#[Requires(sameOrigin: false)]
public function handleXyz()
{
}
```

この保護は `Sec-Fetch-Site` のヘッダー(Fetch Metadata)に頼っています。これはブラウザが自動的に送るもので、サーバー側に XSS の弱点があっても偽れません。記事 [ブラウザがついに CSRF を解決する |https://blog.nette.org/en/quarter-century-of-csrf]で詳しく説明しています。


URL による攻撃、制御コード、正しくない UTF-8
=================================

攻撃者があなたのウェブアプリケーションに *悪意のある* 入力を差し込もうとすることにまつわる、さまざまな言い方です。その結果は幅広く、XML の出力が壊れる(たとえば RSS のフィードが動かなくなる)ことから、データベースの機微な情報やパスワードが得られることまであります。守りは、すべての入力をバイトの水準で一貫して検証することです。正直なところ、実際にそうしている人がどれだけいるでしょうか。

Nette Framework はそれをあなたの代わりに、自動的に行います。何も設定する必要はなく、すべての入力が清められます。


セッションの乗っ取り、セッションの窃取、セッションの固定
===================================

セッションの管理にはいくつかの種類の攻撃がついてまわります。攻撃者はセッション ID を盗むか、自分のものを利用者に植え付けて、利用者のパスワードを知らないままウェブアプリケーションへのアクセスを得ます。そして利用者の知らないうちに、アプリケーションの中でどんな操作でもできてしまいます。守りはサーバーと PHP をきちんと設定することにあります。

Nette Framework は PHP を自動的に設定します。ですからプログラマーはセッションをどう安全にするかを考える必要がなく、アプリケーションの開発に集中できます。ただしこれには `ini_set()` 関数が使えることが要ります。


SameSite クッキー
===============

SameSite クッキーは、ページの読み込みが何によって起きたかを見分けるしくみを与えます。これは安全にとって欠かせません。

SameSite のフラグは 3 つの値を取れます。`Lax`、`Strict`、`None` です(最後のものには HTTPS が要ります)。ページへのリクエストがそのウェブサイト自身から来た場合、あるいは利用者がアドレス欄に直接入れたりブックマークをクリックしたりしてページを開いた場合、ブラウザはすべてのクッキーをサーバーへ送ります(つまり `Lax`、`Strict`、`None` のフラグの付いたものすべてです)。利用者がよそのウェブサイトのリンクからそのウェブサイトへたどり着いた場合は、`Lax` と `None` のフラグの付いたクッキーがサーバーへ渡されます。リクエストがそれ以外のやり方、たとえばよそのオリジンからの POST のフォームの送信、iframe の中での読み込み、JavaScript の利用などで起きた場合は、`None` のフラグの付いたクッキーだけが送られます。

Nette は既定ですべてのクッキーを `Lax` のフラグ付きで送ります。

弱点からの保護

ときおり、また別の名だたるウェブサイトで重大な安全の欠陥が公表されたり、実際に悪用されたりします。いやなことです。ウェブアプリケーションの安全を大切に思うなら、Nette Framework は間違いなく最良の選択です。

Cross-Site Scripting (XSS)

Cross-Site Scripting は、エスケープされていない出力を悪用してウェブサイトを乱す手口です。攻撃者は自分のコードをページに差し込み、ページを書き換えたり、訪問者の機微なデータを手に入れたりできてしまいます。XSS に対する守りには、出力されるすべての文字列を一貫して正しくエスケープすることが要ります。開発者が一度でもそれを忘れれば、ウェブサイト全体が危うくなります。

攻撃の例としては、ページにコードを差し込む細工をした URL を利用者に渡すことが挙げられます。アプリケーションが出力をきちんとエスケープしていなければ、そのスクリプトは利用者のブラウザで動きます。こうしてたとえば、その人の身元が盗まれます。

https://example.com/?search=<script>alert('Successful XSS attack.');</script>

Nette Framework は画期的な Context-Aware Escapingの技術を持ち込み、Cross-Site Scripting の危険を永久に取り除きます。文脈に応じてすべての出力を自動的にエスケープするので、開発者がうっかり何かを忘れることはありません。例を挙げましょうか。開発者が次のテンプレートを書いたとします。

<p onclick="alert({$message})">{$message}</p>

<script>
document.title = {$message};
</script>

{$message} という書き方は変数の出力を意味します。ほかのフレームワークでは出力ごとにはっきりエスケープしなければならず、しかも場所ごとに違うやり方が要ります。Nette Framework では何もエスケープする必要がなく、すべてが自動的に、正しく、一貫して行われます。変数を $message = 'Width 1/2"' にすると、フレームワークは次の HTML のコードを作ります。

<p onclick="alert(&quot;Width 1\/2\&quot;&quot;)">Width 1/2&quot;</p>

<script>
document.title = "Width 1\/2\"";
</script>

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery の攻撃では、攻撃者が被害者をあるページへ誘い込み、そのページが被害者のブラウザの中で、被害者がログインしているサーバーへのリクエストをこっそり実行します。サーバーはそのリクエストが被害者の意思で行われたと信じてしまいます。こうして被害者の身元で、本人の知らないうちに操作が行われます。データの書き換えや削除、メッセージの送信などです。

Nette Framework は、フォームとプレゼンターのシグナルを別のドメインから送信したり起こしたりできないようにして、この種の攻撃から自動的に守ります。保護を切りたいなら、フォームでは次のようにします。

$form->allowCrossOrigin();

シグナルの場合はアトリビュートを足します。

use Nette\Application\Attributes\Requires;

#[Requires(sameOrigin: false)]
public function handleXyz()
{
}

この保護は Sec-Fetch-Site のヘッダー(Fetch Metadata)に頼っています。これはブラウザが自動的に送るもので、サーバー側に XSS の弱点があっても偽れません。記事 ブラウザがついに CSRF を解決するで詳しく説明しています。

URL による攻撃、制御コード、正しくない UTF-8

攻撃者があなたのウェブアプリケーションに 悪意のある 入力を差し込もうとすることにまつわる、さまざまな言い方です。その結果は幅広く、XML の出力が壊れる(たとえば RSS のフィードが動かなくなる)ことから、データベースの機微な情報やパスワードが得られることまであります。守りは、すべての入力をバイトの水準で一貫して検証することです。正直なところ、実際にそうしている人がどれだけいるでしょうか。

Nette Framework はそれをあなたの代わりに、自動的に行います。何も設定する必要はなく、すべての入力が清められます。

セッションの乗っ取り、セッションの窃取、セッションの固定

セッションの管理にはいくつかの種類の攻撃がついてまわります。攻撃者はセッション ID を盗むか、自分のものを利用者に植え付けて、利用者のパスワードを知らないままウェブアプリケーションへのアクセスを得ます。そして利用者の知らないうちに、アプリケーションの中でどんな操作でもできてしまいます。守りはサーバーと PHP をきちんと設定することにあります。

Nette Framework は PHP を自動的に設定します。ですからプログラマーはセッションをどう安全にするかを考える必要がなく、アプリケーションの開発に集中できます。ただしこれには ini_set() 関数が使えることが要ります。

SameSite クッキー

SameSite クッキーは、ページの読み込みが何によって起きたかを見分けるしくみを与えます。これは安全にとって欠かせません。

SameSite のフラグは 3 つの値を取れます。LaxStrictNone です(最後のものには HTTPS が要ります)。ページへのリクエストがそのウェブサイト自身から来た場合、あるいは利用者がアドレス欄に直接入れたりブックマークをクリックしたりしてページを開いた場合、ブラウザはすべてのクッキーをサーバーへ送ります(つまり LaxStrictNone のフラグの付いたものすべてです)。利用者がよそのウェブサイトのリンクからそのウェブサイトへたどり着いた場合は、LaxNone のフラグの付いたクッキーがサーバーへ渡されます。リクエストがそれ以外のやり方、たとえばよそのオリジンからの POST のフォームの送信、iframe の中での読み込み、JavaScript の利用などで起きた場合は、None のフラグの付いたクッキーだけが送られます。

Nette は既定ですべてのクッキーを Lax のフラグ付きで送ります。