Livewire 2.x セキュリティ

新しいLivewire開発者には、Livewireでの体験はちょっとした魔法のようなものです。ページが読み込まれると、Livewire コンポーネントがサーバ上に存在し、ブラウザからの更新を待ち、リアルタイムに応答しているかのように感じられます。

これは、Phoenix LiveViewのような他の類似したツールの動作と変わりありません。

Livewireは、似ているようでいて、内部構造は全く異なり、それぞれに長所、短所、セキュリティ上の影響があります。

Livewireコンポーネントは「ステートフル」に感じられますが、完全に「ステートレス」です。サーバ上にブラウザのインタラクションを待ち、長時間稼働するLivewireインスタンスはありません。それぞれのインタラクションは、全く新しいできたてのリクエスト/レスポンスです。

このメンタルモデルをもっと理解するため、次のようなシンプルな「カウンター」コンポーネントを手始めに考えてみましょう。

class Counter extends Component
{
    public $count = 1;

    public function increment()
    {
        $this->count++;
    }

    public function render()
    {
        return view('livewire.counter');
    }
}

app/Http/Livewire/Counter.php

<div>
    <h1>{{ $count }}</h1>

    <button wire:click="increment">+</button>
</div>

resources/views/livewire/counter.blade.php

この「カウンター」をユーザーの視点で使ってみると、ユーザーがページを読み込み、「1」という数字を見て、「+」ボタンをクリックし、次に「2」という数字を見ることになります。

以下に、Livewireが実際にどのような動作をするかを図示します。

Livewire lifecycle timeline

要約すると、ユーザーが"counter"コンポーネントを含むページにアクセスすると"counter"の初期表示がレンダーされますが、HTMLのレンダリングに加えて、Livewireはコンポーネントの状態(パブリックプロパティ)を「デハイドレイド」または「シリアライズ」して、フロントエンドに渡します。

これで現状、フロントエンドがコンポーネントの状態を把握しているので、更新がトリガーされると(このケースでは"+"をクリックすると)、最後に把握したコンポーネントの状態を含んだリクエストがサーバーに送信されます。サーバーは、その状態からコンポーネントを「ハイドレート」または「デシリアライズ」し、更新を行います。

コンポーネントは再びデハイドレイドされ、新たにレンダリングされたHTMLと更新済みの状態をブラウザへ提供し、後のインタラクションリクエストで使用できるようになります。

次に、こうしたリクエスト時における、実際のコンポーネントのライフサイクルをより深く図示します。

Livewire lifecycle flow

Livewire が内部でどのように動作するか、より正確なメンタルモデルを理解していただければ、幸いです。これにより、より懸命に問題をデバッグしたり、Livewire を使用することによるパフォーマンスやセキュリティへの影響を理解できます。

セキュリティ対策

前述の通り、Livewireの各リクエストは「ステートレス」であり、状態を維持するため長時間稼働するサーバインスタンスは存在しません。状態はブラウザに保存され、リクエストの間にサーバーとの間でやり取りされます。

状態がブラウザに保存されるため、フロントエンドによる操作には脆弱です。セキュリティ対策が施されていなければ、悪意のある人により、リクエスト間でブラウザ内のコンポーネントの状態を簡単に操作されてしまいます。

先ほどの「カウンター」の例では、そのコンポーネントの「カウント」のような些細で一時的なものを操作しても、実際には悪影響はありませんが、例えば削除ボタン付きの「投稿編集」コンポーネントのように、より多くの問題を抱えるコンポーネントでは、セキュリティ対策を講じる必要があります。

チェックサム

Livewireを支える基本的なセキュリティは、リクエスト/レスポンスと一緒に移動する「チェックサム」であり、サーバーからの状態がブラウザ内で改ざんされていないことを検証するために使用されます。

さらに説明すると、上記の「カウンター」コンポーネントを考えてみましょう。単に [{ count: 1 }]{style="white-space: nowrap"} をブラウザに渡すのではなく、Livewire は安全な鍵を使ってそのペイロードのハッシュ(チェックサム)を生成し、それを状態と一緒に渡します。

「カウンター」のためのLivewireペイロードをより現実的に表現すると、次のようになります。

{
    state: { count: 1 },
    checksum: "A6jHn359Ku3lFc82arW8",
}

ここで、悪意のある人がリクエストの間にブラウザの状態を改ざんした場合、Livewireがコンポーネントの更新を処理する前に、ペイロードのハッシュがチェックサムと一致しないことがわかり、エラーが発生します。

持続ミドルウェア

Livewire が施す、セキュリティ対策の2つ目は「永続的ミドルウェア」です。つまり、Livewireは「最初のリクエスト」の際に使用された認証/認可ミドルウェアを捕捉し、その後のリクエストに再適用します。

この対策がなければ、ユーザーがアプリケーションからログアウトした後に、Livewire の後続リクエストがキャプチャされ、再実行される可能性があり、そうしたコードパスへのアクセスはできなくなります。

デフォルトでは、Laravelアプリに用意されている認証と認可のミドルウェアを適用します。ここでは、デフォルト設定を一部紹介します。

[
    ...
    \Illuminate\Auth\Middleware\Authenticate::class,
    \Illuminate\Auth\Middleware\Authorize::class,
]

独自のミドルウェアを追加してキャプチャし、存在する場合に再適用したい場合は、以下のAPIを使ってアプリのサービスプロバイダで行うことができます。

Livewire::addPersistentMiddleware([
    YourOwnMiddleware::class,
]);

追加したミドルウェアは、コンポーネントがロードされた元のルートにミドルウェアが割り当てられていれば、その後のLivewireリクエストでも再適用されます。

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

言語
バージョン

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる