【入門編】 ウォレット接続におけるセッション管理とクロスサイト・リクエスト・フォージェリ(CSRF)対策 – IoT・OT(制御システム) & ブロックチェーンセキュリティ防御ガイド

みなさんこんにちは!Web3の世界やブロックチェーン開発の現場に飛び込んだばかりの新人エンジニアのみなさん、日々新しい技術のキャッチアップお疲れ様です!

「スマートコントラクトを書けるようになったぞ!」「次はdApp(分散型アプリケーション)のフロントエンドとウォレットを連携させるぞ!」と意気込んでいる頃ではないでしょうか。

MetaMaskなどのウォレットをWebサイトにつなげて、ボタン一つでブロックチェーンにトランザクション(取引)を飛ばせる仕組みって、魔法みたいでわくわくしますよね。でも、この「ウォレット接続」と「セッション管理」、そして「CSRF(クロスサイト・リクエスト・フォージェリ)」という魔物が潜む領域は、セキュリティの初心者が思わずハマりやすい大きな落とし穴があるんです。

今回は、セキュリティバイブルの視点から、攻撃者がどこを狙ってくるのか、そしてどうやって身を守ればいいのかを、身近な例えを交えながら一歩ずつ優しく紐解いていきましょう!

—

1. 家の合鍵と「お留守番のルール」で考えるウォレット接続の正体

まずは、Web3の世界における「ウォレット接続」って、現実世界で例えるとどういう状態なのかイメージしてみましょう。

みなさんの家には玄関の鍵がありますよね。ブロックチェーン上の秘密鍵は、まさにその「絶対に他人に渡しちゃいけない家の本当の鍵」です。
そしてdAppの画面(ブラウザ)は、いわば「信頼できるハウスキーパー(家事代行サービス)さん」のようなものです。

「うちの掃除をしてほしいから、この合鍵を使ってリビングに入っていいよ」と許可を出すのが、ウォレット接続(eth_requestAccountsなど)の瞬間です。

ここで問題になるのが、「一度鍵を渡したら、ハウスキーパーさんはずっと家に出入りして、勝手に高価な壺を売り払ったりしてもいいのか?」という点ですよね。もちろんダメです。そんなことになったら怖くて安心して出かけられません。

だからこそ、dAppの世界でも「今、このセッション(接続状態)は本当に本人のものか?」「この指示は、本当にリビングの主が出したものか?」をしっかり管理する必要があるのです。ここにサボりがあると、悪意ある偽サイトが隙をついて侵入してきます。

—

2. 攻撃者が仕掛ける罠:CSRFとOriginの盲点

ここで登場するのが、今回のテーマである CSRF(クロスサイト・リクエスト・フォージェリ) です。日本語に訳すと「クロスサイト要求偽造」ですが、要するに「あなたのブラウザを悪用して、勝手に裏で悪い命令を実行させちゃう手口」のことです。

現実の例えで言うとこんな感じです。

1. あなたが、とある安全そうなdApp(Aサイト)にウォレットをつなぎ、ログイン状態でお茶を飲んでいます。ブラウザはまだAサイトを信用したままです。
2. その直後、たまたま開いてしまった悪意あるハッカーのサイト(Bサイト)にアクセスしてしまいます。
3. Bサイトの裏側では、こんな悪巧みが実行されています。

  • 「おっ、このユーザーのブラウザには、さっきAサイトで繋いだウォレットのセッションが残ってるぞ!」
  • 「Bサイトのボタンを押したふりをして、裏でこっそりAサイトの機能を呼び出し、この人の全資金をハッカーの口座に送金するトランザクションを作らせちゃおう!」

これがCSRFの恐ろしいところです。ユーザー自身は何も怪しいと思っていないのに、ブラウザが勝手に「信頼されている身分証(セッションCookieやトークン)」を悪用して、裏口から攻撃者の言うことを聞いてしまうんですね。

なぜOriginの検証が必要なのか?

ここで重要になるのが Origin(オリジン)の検証 です。Originとは、簡単に言えば「今、どのウェブサイト(ドメイン)からこのリクエストが飛んできたのか」を示す看板のようなものです。

先ほどの例で言えば、Aサイトのサーバーにリクエストが届いたとき、「おや? このリクエストの看板は『evil-hacker.com(Bサイト)』って書いてあるぞ。うちの正規の『safe-dapp.com(Aサイト)』じゃないから、門前払いにしよう!」と弾く仕組み、これがOrigin検証です。

これを怠ると、玄関のドアに鍵をかけ忘れているのと同じ状態になってしまいます。

—

3. 実装で防ぐ!セッション管理とOrigin検証の具体的なアプローチ

「うわ、なんだか怖そう……どうやってコードを書けば防げるの?」と思ったそこのあなた、安心してください!基本の対策をしっかり押さえれば、不正な侵入をガッチリブロックできます。

ここからは、バックエンド(Node.js / Expressなど)でAPIを受け取る際の、具体的な実装コードの例を見ていきましょう。日本語のコメントを丁寧に書いたので、実務の参考にしてみてくださいね。

バックエンドでのOrigin検証のサンプルコード

const express = require('express');
const app = express();

// JSONボディをパースするミドルウェア
app.use(express.json());

// 信頼できるフロントエンドのドメイン(本番環境のURL)
const ALLOWED_ORIGIN = 'https://my-super-secure-dapp.com';

// dAppからの重要なリクエストを受け取るAPIエンドポイント
app.post('/api/v1/execute-transaction', (req, res) => {
    // 1. リクエストのヘッダーから 'Origin' を取得します
    const requestOrigin = req.get('Origin');

    // 2. リクエストの出所(Origin)が、許可されたドメインと一致するか厳密にチェックします
    if (!requestOrigin || requestOrigin !== ALLOWED_ORIGIN) {
        // 看板が偽物、あるいは看板がない場合は容赦なく拒否(403 Forbidden)
        console.warn(`[セキュリティ警告] 不正なOriginからのアクセスを検知しました: ${requestOrigin}`);
        return res.status(403.json({
            error: 'アクセスが拒否されました:不正なオリジンからのリクエストです。'
        }));
    }

    // 3. 次にセッションやJWT(JSON Web Token)の正当性を検証します
    const authHeader = req.headers.authorization;
    if (!verifySessionToken(authHeader)) {
        return res.status(401).json({
            error: '認証エラー:有効なセッションが見つかりません。'
        });
    }

    // 4. すべての安全確認が取れたので、安全に処理を進めます
    // (※実際のブロックチェーンへの署名要求やコントラクト呼び出しのロジックをここに記述)
    
    return res.status(200).json({
        success: true,
        message: 'トランザクションの準備が正常に完了しました!'
    });
});

// ダミーのセッション検証関数
function verifySessionToken(authHeader) {
    // ここでJWTの署名検証や有効期限のチェックを行います
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return false;
    }
    // 検証ロジックが通ればtrueを返す
    return true;
}

app.listen(3000, () => {
    console.log('セキュアなAPIサーバーがポート3000で起動しました。');
});

コードのポイント解説

  • req.get('Origin') によるチェック: どのWebサイトからリクエストが飛んできたのかをブラウザのヘッダーから確実に見張っています。
  • ホワイトリスト方式の採用: 「許可するURL(ALLOWED_ORIGIN)」をあらかじめコード内でしっかり定義し、それ以外はすべて弾くという堅実なアプローチを取っています。
  • セッションの二重チェック: Originの確認だけでなく、APIを叩くユーザーのセッション(Authorizationヘッダーなど)が有効期限内かどうかも毎回チェックしています。

—

4. フロントエンド(dApp側)で意識すべきセキュリティの鉄則

バックエンドだけでなく、ユーザーのブラウザ側(フロントエンド)でも、ウォレットとのやり取りにおいて気をつけるべきポイントがあります。

1. 不要になったらセッションを切断する(Disconnectの実装)

  • ユーザーがアプリを閉じたり、ログアウトボタンを押したりした際は、ウォレット側との接続状態(Providerのステート)をクリーンアップし、ローカルストレージに残った不要なトークンは必ず削除(localStorage.removeItem()など)しましょう。

2. 署名要求(Personal Sign / Typed Data)の内容をユーザーに分かりやすく表示する

  • 「なにに署名させられているのか」がユーザー自身に一目でわかるUIにすることが大切です。よくわからない英数字の羅列に「はい」と押させるような設計は、フィッシング詐欺の温床になります。

—

まとめ:一歩ずつ、堅牢なWeb3アプリを作っていこう!

今回は、ウォレット接続におけるセッション管理とCSRF対策について、身近な例えを交えてお話ししました。

  • ウォレット接続は「家の合鍵を渡すようなもの」だからこそ、厳重な管理が必要
  • 悪意ある別サイトからの不正な要求を防ぐために、バックエンドでの「Origin検証」が不可欠
  • 「誰からのリクエストか」「本当に本人か」の二重チェックを怠らない

セキュリティと聞くと、なんだか難しくて壁が高く感じるかもしれませんが、要は「誰が、どこから、どんな権限でアクセスしてきたか」を一つずつ確認していく丁寧な作業の積み重ねです。

最初は覚えることも多くて大変かもしれませんが、一歩ずつ安全なコードの書き方を身につけていけば、ユーザーから心から信頼される素晴らしいdAppを作れるようになりますよ。

それでは、次回のセキュリティ解説もお楽しみに!一緒に安全でエキサイティングなWeb3の未来を作っていきましょう!

コメント

タイトルとURLをコピーしました