🌟

viteのbreaking change (CORSがひっかかる場合)

2025/01/30に公開

https://github.com/vitejs/vite/releases

  • v5.4.12
  • v6.0.9

で発生している

laravelの場合とその対処法

curl -s "https://laravel.build/example-app?with=mysql" | bash
cd example-app
./vendor/bin/sail up -d

とかして現状の最新を持ってきて起動の後

./vendor/bin/sail npm install
./vendor/bin/sail npm list
html@ /var/www/html
+-- autoprefixer@10.4.20
+-- axios@1.7.9
+-- concurrently@9.1.2
+-- laravel-vite-plugin@1.2.0
+-- postcss@8.5.1
+-- tailwindcss@3.4.17
`-- vite@6.0.11

とすると 6.0.11 が入る。つまりbreaking changeにひっかかっている。

breeze

あるいは

./vendor/bin/sail composer require laravel/breeze --dev
./vendor/bin/sail artisan breeze:install react
./vendor/bin/sail npm list
html@ /var/www/html
+-- @headlessui/react@2.2.0
+-- @inertiajs/react@2.0.3
+-- @tailwindcss/forms@0.5.10
+-- @vitejs/plugin-react@4.3.4
+-- autoprefixer@10.4.20
+-- axios@1.7.9
+-- concurrently@9.1.2
+-- laravel-vite-plugin@1.2.0
+-- postcss@8.5.1
+-- react-dom@18.3.1
+-- react@18.3.1
+-- tailwindcss@3.4.17
`-- vite@6.0.11

まあ根本的にviteは5系か6系か入るけどバージョンが引き上がってbreaking changesにひっかかってしまう。

従来動いていたhmrの書き方

まあリモートでhmrを仕掛けようって人もそうおらんと思うが

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    server: {
        hmr: {
            host: '35.77.5.224',
        }
    },

    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            refresh: true,
        }),
        react(),
    ],
});

これはダメになった。

以下のように変更する

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    server: {
        cors: true,
        origin: 'http://35.77.5.224:5173',
        hmr: {
            host: '35.77.5.224',
        }
    },

    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            refresh: true,
        }),
        react(),
    ],
});

loadEnv方式に変更する場合

VITE_APP_NAME="${APP_NAME}"
VITE_PORT=5173
VITE_HMR_HOST=35.77.5.224

こんな感じで仕込んでおく。VITE_PORTもここでセットしておいた。

vite.config.js
import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, process.cwd(), '');

    return {
        server: {
            port: env.VITE_PORT || 5173,
            origin: `http://${env.VITE_HMR_HOST}:${env.VITE_PORT || 5173}`,
            cors: true,
            hmr: {
                host: env.VITE_HMR_HOST || 'localhost',
            },
        },
        plugins: [
            laravel({
                input: 'resources/js/app.jsx',
                refresh: true,
            }),
            react(),
        ],
    };
});

urlをParseしてもいいかもしれないけど一応VITE_PORTっていう値がlaravel sailのdocker-composeで定義されているので、そこに従うとこんな感じかなという気がします。

【補足】 セキュリティー修正ドキュメント

https://github.com/vitejs/vite/security/advisories/GHSA-vg6x-rcgg-rjx6

chatgptによる翻訳をバコっと貼り付けとく

Vite 5.4.12のBreaking Changesまとめ

概要

Vite 5.4.12では、デフォルトのCORS設定の緩さWebSocketのOriginヘッダ検証不足 により、開発サーバーが任意のウェブサイトからのリクエストを許可し、レスポンスを読み取れる脆弱性が報告されました。この問題を修正するため、いくつかの変更が加えられました。

アップグレードパス

次の条件のいずれにも該当しない場合、Viteの新しいバージョンに追加の設定なしでアップグレードできます:

  • バックエンド統合機能 を使用している
  • Viteの前にリバースプロキシを配置 している
  • localhost*.localhost 以外のドメインで開発サーバーにアクセス している
  • WebSocketをブラウザから直接利用するプラグインやフレームワークを使用 している

バックエンド統合機能を使用している場合

server.origin を設定していない場合は、バックエンドサーバーのオリジンを server.cors.origin に明示的に設定 する必要があります。

server: {
    cors: {
        origin: 'http://your-backend.example.com', // バックエンドのオリジンを指定
    },
}

* を設定すると、すべてのオリジンからアクセス可能になるため セキュリティリスク があります。

リバースプロキシを使用している場合

Viteに送信されるリクエストのホスト名が localhost 以外の場合、server.allowedHostsそのホスト名を追加 する必要があります。

server: {
    allowedHosts: ['vite'], // 例: http://vite:5173 にリバースプロキシを設定している場合
}

localhost 以外のドメインで開発サーバーにアクセスする場合

開発サーバーを localhost 以外のドメイン(例: http://foo.example.com:8080)で利用する場合、server.allowedHosts に追加する必要があります。

server: {
    allowedHosts: ['foo.example.com'],
}

WebSocketを直接利用するプラグインやフレームワークを使用している場合

Viteの新しいバージョンにアップグレードし、WebSocket接続が正しく動作するかを確認 してください。

もしWebSocketが動作しない場合、以下のどちらかを行うことが可能です:

  1. プラグインやフレームワークのコードを修正 し、新しいViteの仕様に適応させる。
  2. 一時的に legacy.skipWebSocketTokenCheck: true を設定して、WebSocketのOriginチェックをスキップする。
server: {
    legacy: {
        skipWebSocketTokenCheck: true
    }
}

この設定はセキュリティリスクを伴う ため、慎重に使用する必要があります。

Viteをアップグレードせずに脆弱性を回避する方法

[1] デフォルトのCORS設定の緩さ

server.corsfalse にする または server.cors.origin を信頼できるオリジンのみに限定する。

server: {
    cors: {
        origin: 'http://trusted.example.com',
    },
}

[2] WebSocketのOriginヘッダの検証不足

この問題の回避策は Viteのアップグレード しかありません。

[3] HTTPリクエストのHostヘッダ検証不足

  • Chrome 94以降のブラウザを使用する
  • 開発サーバーをHTTPSで動作させる
server: {
    https: true,
}

技術的な詳細

Viteが脆弱だったのは、次の3つの理由によるものです。

[1] デフォルトのCORS設定の緩さ

  • Viteは server.cors のデフォルト値を true にしていた。
  • その結果、Access-Control-Allow-Origin: * が設定され、任意のオリジンからリソースを取得できる状態 になっていた。

[2] WebSocketのOriginヘッダの検証不足

  • Viteは HMR (Hot Module Replacement) のために WebSocket サーバー を使用。
  • WebSocketの Origin ヘッダを 検証していなかった ため、クロスサイト WebSocket ハイジャック (CSWSH) 攻撃 が可能だった。

[3] HTTPリクエストのHostヘッダ検証不足

  • Viteの開発サーバーは Hostヘッダの検証を行っていなかった
  • DNSリバインディング攻撃によって、攻撃者がVite開発サーバーに任意のリクエストを送信できる 状態だった。

影響

  • ソースコードの流出
  • HMR経由でプラグインの情報漏洩
  • DNSリバインディングによる不正アクセス

Chrome 94+ では一部の攻撃がブロックされるが、HTTPS環境での開発が推奨される。

まとめ

Vite 5.4.12 以降では CORSやWebSocketのセキュリティ対策が強化 され、明示的な server.originserver.allowedHosts の設定が必要になりました。セキュリティリスクを防ぐため、適切な設定を行いましょう。

Discussion