Readouble

Livewire v3 セキュリティ

セキュリティ

Livewireアプリケーションを安全にし、アプリケーションの脆弱性を露出させないようにすることが重要です。 Livewireには多くのケースを処理するための内部セキュリティ機能がありますが、コンポーネントを安全に保つためには、アプリケーションコードに依存する場合があります。It's important to make sure your Livewire apps are secure and don't expose any application vulnerabilities. Livewire has internal security features to handle many cases, however, there are times when it's up to your application code to keep your components secure.

アクションパラメータの認証Authorizing action parameters

Livewireアクションは非常に強力ですが、Livewireアクションに渡されるパラメータはクライアント上で変更可能であり、信頼できないユーザー入力として扱う必要があります。Livewire actions are extremely powerful, however, any parameters passed to Livewire actions are mutable on the client and should be treated as un-trusted user input.

おそらく、Livewireで最も一般的なセキュリティ上の落とし穴は、データベースに変更を永続化する前に、Livewireアクション呼び出しを検証および認証しないことです。Arguably the most common security pitfall in Livewire is failing to validate and authorize Livewire action calls before persisting changes to the database.

以下は、認証の欠如によるセキュリティ上の脆弱性の例です。Here is an example of an insecurity resulting from a lack of authorization:

<?php

use App\Models\Post;
use Livewire\Component;

class ShowPost extends Component
{
    // ...

    public function delete($id)
    {
        // INSECURE! (安全ではありません!)

        $post = Post::find($id);

        $post->delete();
    }
}
<button wire:click="delete({{ $post->id }})">Delete Post</button>

上記の例が安全でない理由は、悪意のあるユーザーがwire:click="delete(...)"をブラウザで変更して、任意のPost IDを渡すことができるためです。The reason the above example is insecure is that wire:click="delete(...)" can be modified in the browser to pass ANY post ID a malicious user wishes.

アクションパラメータ(この例の $id など)は、ブラウザからの信頼できない入力と同じように扱う必要があります。Action parameters (like $id in this case) should be treated the same as any untrusted input from the browser.

したがって、このアプリケーションを安全に保ち、ユーザーが別のユーザーの投稿を削除できないようにするには、delete()アクションに認証を追加する必要があります。Therefore, to keep this application secure and prevent a user from deleting another user's post, we must add authorization to the delete() action.

まず、次のコマンドを実行して、PostモデルのLaravel Policyを作成しましょう。First, let's create a Laravel Policy[https://laravel.com/docs/authorization#creating-policies] for the Post model by running the following command:

php artisan make:policy PostPolicy --model=Post

上記のコマンドを実行すると、新しいPolicyが app/Policies/PostPolicy.php 内に作成されます。次に、以下のように delete メソッドでその内容を更新できます。After running the above command, a new Policy will be created inside app/Policies/PostPolicy.php. We can then update its contents with a delete method like so:

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * Determine if the given post can be deleted by the user.
     */
    public function delete(?User $user, Post $post): bool
    {
        return $user?->id === $post->user_id;
    }
}

これで、Livewireコンポーネントから $this->authorize() メソッドを使用して、ユーザーが投稿を削除する前に所有していることを確認できます。Now, we can use the $this->authorize() method from the Livewire component to ensure the user owns the post before deleting it:

public function delete($id)
{
    $post = Post::find($id);

    // If the user doesn't own the post, (ユーザーが投稿を所有していない場合、)
    // an AuthorizationException will be thrown... (AuthorizationExceptionがスローされます...)
    $this->authorize('delete', $post); // [tl! highlight]

    $post->delete();
}

参考資料:Further reading:

  • Laravel GatesLaravel Gates[https://laravel.com/docs/authorization#gates]
  • Laravel PoliciesLaravel Policies[https://laravel.com/docs/authorization#creating-policies]

パブリックプロパティの認証Authorizing public properties

アクションパラメータと同様に、Livewireのパブリックプロパティは、ユーザーからの信頼できない入力として扱う必要があります。Similar to action parameters, public properties in Livewire should be treated as un-trusted input from the user.

以下は、投稿の削除に関する上記の例と同じものを、別の方法で安全でない方法で記述したものです。Here is the same example from above about deleting a post, written insecurely in a different manner:

<?php

use App\Models\Post;
use Livewire\Component;

class ShowPost extends Component
{
    public $postId;

    public function mount($postId)
    {
        $this->postId = $postId;
    }

    public function delete()
    {
        // INSECURE! (安全ではありません!)

        $post = Post::find($this->postId);

        $post->delete();
    }
}
<button wire:click="delete">Delete Post</button>

ご覧のとおり、wire:click から delete メソッドに $postId をパラメータとして渡す代わりに、Livewireコンポーネントのパブリックプロパティとして保存しています。As you can see, instead of passing the $postId as a parameter to the delete method from wire:click, we are storing it as a public property on the Livewire component.

このアプローチの問題は、悪意のあるユーザーがページに次のようなカスタム要素を挿入できることです。The problem with this approach is that any malicious user can inject a custom element onto the page such as:

<input type="text" wire:model="postId">

これにより、彼らは「Delete Post」を押す前に $postId を自由に修正できます。 delete アクションは $postId の値を認証しないため、ユーザーは自分が所有しているかどうかにかかわらず、データベース内の任意の投稿を削除できるようになります。This would allow them to freely modify the $postId before pressing "Delete Post". Because the delete action doesn't authorize the value of $postId, the user can now delete any post in the database, whether they own it or not.

このリスクから保護するためには、2つの可能な解決策があります。To protect against this risk, there are two possible solutions:

モデルプロパティの使用Using model properties

パブリックプロパティを設定する場合、Livewireは文字列や整数などのプレーンな値とは異なり、モデルを特別に扱います。 このため、コンポーネントのプロパティとして投稿モデル全体を保存すると、LivewireはIDが改ざんされないようにします。When setting public properties, Livewire treats models differently than plain values such as strings and integers. Because of this, if we instead store the entire post model as a property on the component, Livewire will ensure the ID is never tampered with.

以下は、単純な $postId プロパティの代わりに $post プロパティを保存する例です。Here is an example of storing a $post property instead of a simple $postId property:

<?php

use App\Models\Post;
use Livewire\Component;

class ShowPost extends Component
{
    public Post $post;

    public function mount($postId)
    {
        $this->post = Post::find($postId);
    }

    public function delete()
    {
        $this->post->delete();
    }
}
<button wire:click="delete">Delete Post</button>

このコンポーネントは、悪意のあるユーザーが $post プロパティを別のEloquentモデルに変更する方法がないため、安全になりました。This component is now secured because there is no way for a malicious user to change the $post property to a different Eloquent model.

プロパティのロックLocking the property

プロパティが不要な値に設定されるのを防ぐ別の方法は、ロックされたプロパティ和訳)を使用することです。 プロパティのロックは、#[Locked] 属性を適用することで行われます。 ユーザーがこの値を改ざんしようとすると、エラーがスローされます。Another way to prevent properties from being set to unwanted values is to use locked properties[https://livewire.laravel.com/docs/locked]. Locking properties is done by applying the #[Locked] attribute. Now if users attempt to tamper with this value an error will be thrown.

Locked属性を持つプロパティはバックエンドで変更できますが、信頼できないユーザー入力がLivewire関数に渡されないように注意する必要があります。Note that properties with the Locked attribute can still be changed in the back-end, so care still needs to taken that untrusted user input is not passed to the property in your own Livewire functions.

<?php

use App\Models\Post;
use Livewire\Component;
use Livewire\Attributes\Locked;

class ShowPost extends Component
{
    #[Locked] // [tl! highlight]
    public $postId;

    public function mount($postId)
    {
        $this->postId = $postId;
    }

    public function delete()
    {
        $post = Post::find($this->postId);

        $post->delete();
    }
}

プロパティの認証Authorizing the property

モデルプロパティの使用が望ましくない場合は、delete アクション内で投稿の削除を手動で認証することもできます。If using a model property is undesired in your scenario, you can of course fall-back to manually authorizing the deletion of the post inside the delete action:

<?php

use App\Models\Post;
use Livewire\Component;

class ShowPost extends Component
{
    public $postId;

    public function mount($postId)
    {
        $this->postId = $postId;
    }

    public function delete()
    {
        $post = Post::find($this->postId);

        $this->authorize('delete', $post); // [tl! highlight]

        $post->delete();
    }
}
<button wire:click="delete">Delete Post</button>

これで、悪意のあるユーザーは $postId の値を自由に修正できますが、delete アクションが呼び出されると、ユーザーが投稿を所有していない場合、$this->authorize()AuthorizationException をスローします。Now, even though a malicious user can still freely modify the value of $postId, when the delete action is called, $this->authorize() will throw an AuthorizationException if the user does not own the post.

参考資料:Further reading:

  • Laravel GatesLaravel Gates[https://laravel.com/docs/authorization#gates]
  • Laravel PoliciesLaravel Policies[https://laravel.com/docs/authorization#creating-policies]

ミドルウェアMiddleware

Livewireコンポーネントが、次のようなルートレベルのAuthorization Middlewareを含むページにロードされると:When a Livewire component is loaded on a page containing route-level Authorization Middleware[https://laravel.com/docs/authorization#via-middleware], like so:

Route::get('/post/{post}', App\Livewire\UpdatePost::class)
    ->middleware('can:update,post'); // [tl! highlight]

Livewireは、これらのミドルウェアが後続のLivewireネットワークリクエストに再度適用されるようにします。 これは、Livewireのコアで「永続ミドルウェア」と呼ばれます。Livewire will ensure those middlewares are re-applied to subsequent Livewire network requests. This is referred to as "Persistent Middleware" in Livewire's core.

永続ミドルウェアは、初期ページロード後に認証ルールまたはユーザー権限が変更されたシナリオから保護します。Persistent middleware protects you from scenarios where the authorization rules or user permissions have changed after the initial page-load.

そのようなシナリオのより詳細な例を次に示します。Here's a more in-depth example of such a scenario:

Route::get('/post/{post}', App\Livewire\UpdatePost::class)
    ->middleware('can:update,post'); // [tl! highlight]
<?php

use App\Models\Post;
use Livewire\Component;
use Livewire\Attributes\Validate;

class UpdatePost extends Component
{
    public Post $post;

    #[Validate('required|min:5')]
    public $title = '';

    public $content = '';

    public function mount()
    {
        $this->title = $this->post->title;
        $this->content = $this->post->content;
    }

    public function update()
    {
        $this->post->update([
            'title' => $this->title,
            'content' => $this->content,
        ]);
    }
}

ご覧のとおり、can:update,post ミドルウェアはルートレベルで適用されます。 これは、投稿を更新する権限を持たないユーザーはページを表示できないことを意味します。As you can see, the can:update,post middleware is applied at the route-level. This means that a user who doesn't have permission to update a post cannot view the page.

ただし、ユーザーが次のことを行うシナリオを考えてください。However, consider a scenario where a user:

  • ページをロードするLoads the page
  • ページロード後に更新権限を失うLoses permission to update after the page loads
  • 権限を失った後に投稿を更新しようとするTries updating the post after losing permission

Livewireが既にページを正常にロードしているため、こう自問するかもしれません。「Livewireがポストを更新するために後続のリクエストを行うとき、can:update,postミドルウェアは再度適用されるのか?あるいは、権限のないユーザーがポストを正常に更新できるようになるのか?」Because Livewire has already successfully loaded the page you might ask yourself: "When Livewire makes a subsequent request to update the post, will the can:update,post middleware be re-applied? Or instead, will the un-authorized user be able to update the post successfully?"

Livewireには、元のエンドポイントからミドルウェアを再度適用するための内部メカニズムがあるため、このシナリオでは保護されています。Because Livewire has internal mechanisms to re-apply middleware from the original endpoint, you are protected in this scenario.

永続的なミドルウェアの設定Configuring persistent middleware

デフォルトでは、Livewireは以下のミドルウェアをネットワークリクエスト全体で永続化します。By default, Livewire persists the following middleware across network requests:

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Laravel\Jetstream\Http\Middleware\AuthenticateSession::class,
\Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\RedirectIfAuthenticated::class,
\Illuminate\Auth\Middleware\Authenticate::class,
\Illuminate\Auth\Middleware\Authorize::class,

上記のいずれかのミドルウェアが最初のページロードに適用されている場合、それらは永続化され(再度適用され)、将来のネットワークリクエストに適用されます。If any of the above middlewares are applied to the initial page-load, they will be persisted (re-applied) to any future network requests.

ただし、アプリケーションからカスタムミドルウェアを最初のページロードに適用し、それをLivewireリクエスト間で永続化したい場合は、次のようにアプリケーションのService Providerからこのリストに追加する必要があります。However, if you are applying a custom middleware from your application on the initial page-load, and want it persisted between Livewire requests, you will need to add it to this list from a Service Provider[https://laravel.com/docs/providers#main-content] in your app like so:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Livewire;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Livewire::addPersistentMiddleware([ // [tl! highlight:2]
            App\Http\Middleware\EnsureUserHasRole::class,
        ]);
    }
}

Livewireコンポーネントが、アプリケーションのEnsureUserHasRoleミドルウェアを使用するページにロードされる場合、それは永続化され、そのLivewireコンポーネントへの将来のネットワークリクエストに再度適用されます。If a Livewire component is loaded on a page that uses the EnsureUserHasRole middleware from your application, it will now be persisted and re-applied to any future network requests to that Livewire component.

warning Warning! ミドルウェアの引数はサポートされていません Livewireは現在、永続的なミドルウェア定義のミドルウェア引数をサポートしていません。[!warning] Middleware arguments are not supported Livewire currently doesn't support middleware arguments for persistent middleware definitions.

// Bad...
Livewire::addPersistentMiddleware(AuthorizeResource::class.':admin');

// Good...
Livewire::addPersistentMiddleware(AuthorizeResource::class);

グローバルなLivewireミドルウェアの適用Applying global Livewire middleware

あるいは、すべてのLivewire更新ネットワークリクエストに特定のミドルウェアを適用したい場合は、任意のミドルウェアを使用して独自のLivewire更新ルートを登録することでそれを行うことができます。Alternatively, if you wish to apply specific middleware to every single Livewire update network request, you can do so by registering your own Livewire update route with any middleware you wish:

Livewire::setUpdateRoute(function ($handle) {
	return Route::post('/livewire/update', $handle)
        ->middleware(App\Http\Middleware\LocalizeViewPaths::class);
});

サーバへのLivewire AJAX/fetchリクエストはすべて上記のエンドポイントを使用し、コンポーネントの更新を処理する前にLocalizeViewPathsミドルウェアを適用します。Any Livewire AJAX/fetch requests made to the server will use the above endpoint and apply the LocalizeViewPaths middleware before handling the component update.

Installation page和訳)で、更新ルートのカスタマイズについて詳しく学んでください。Learn more about customizing the update route on the Installation page[https://livewire.laravel.com/docs/installation#configuring-livewires-update-endpoint].

スナップショットのチェックサムSnapshot checksums

すべてのLivewireリクエストの間で、Livewireコンポーネントのスナップショットが取得され、ブラウザに送信されます。このスナップショットは、次のサーバラウンドトリップ中にコンポーネントを再構築するために使用されます。Between every Livewire request, a snapshot is taken of the Livewire component and sent to the browser. This snapshot is used to re-build the component during the next server round-trip.

Livewireスナップショットの詳細については、Hydrationドキュメントを参照してください。和訳Learn more about Livewire snapshots in the Hydration documentation.[https://livewire.laravel.com/docs/hydration#the-snapshot]

fetchリクエストはブラウザで傍受および改ざんされる可能性があるため、Livewireは各スナップショットの「チェックサム」を生成し、それと一緒に送信します。Because fetch requests can be intercepted and tampered with in a browser, Livewire generates a "checksum" of each snapshot to go along with it.

このチェックサムは、次のネットワークリクエストで、スナップショットがまったく変更されていないことを確認するために使用されます。This checksum is then used on the next network request to verify that the snapshot hasn't changed in any way.

Livewireがチェックサムの不一致を検出すると、CorruptComponentPayloadExceptionがスローされ、リクエストは失敗します。If Livewire finds a checksum mismatch, it will throw a CorruptComponentPayloadException and the request will fail.

これにより、悪意のある改ざんのあらゆる形態から保護され、そうでない場合はユーザーに無関係のコードを実行または変更する機能を与えることになります。This protects against any form of malicious tampering that would otherwise result in granting users the ability to execute or modify unrelated code.

章選択

パッケージ

設定

バージョン変更
linkv3 linkv2
明暗テーマ
light_mode
dark_mode
brightness_auto システム設定に合わせる
テーマ選択
photo_size_select_actual デフォルト
photo_size_select_actual モノクローム(白黒)
photo_size_select_actual Solarized風
photo_size_select_actual GitHub風(青ベース)
photo_size_select_actual Viva(黄緑ベース)
photo_size_select_actual Happy(紫ベース)
photo_size_select_actual Mint(緑ベース)
コードハイライトテーマ選択

明暗テーマごとに、コードハイライトのテーマを指定できます。

テーマ配色確認
スクリーン表示幅
640px
80%
90%
100%

768px以上の幅があるときのドキュメント部分表示幅です。

インデント
無し
1rem
2rem
3rem
原文確認
原文を全行表示
原文を一行ずつ表示
使用しない

※ 段落末のEボタンへカーソルオンで原文をPopupします。

Diff表示形式
色分けのみで区別
行頭の±で区別
削除線と追記で区別

※ [tl!…]形式の挿入削除行の表示形式です。

テストコード表示
両コード表示
Pestのみ表示
PHPUnitのみ表示
OS表示
全OS表示
macOSのみ表示
windowsのみ表示
linuxのみ表示
JSフレームワーク
両フレームワーク
Reactのみ表示
Vueのみ表示
JSのみ表示

(JSが存在しない場合は、他を全表示)

和文変換

対象文字列と置換文字列を半角スペースで区切ってください。(最大5組各10文字まで)

本文フォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

コードフォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

保存内容リセット

localStrageに保存してある設定項目をすべて削除し、デフォルト状態へ戻します。

ヘッダー項目移動

キーボード操作