tomy634.com // ブログ

QRコードの安全講座:フィッシングを見抜く&作る側のベストプラクティス【2025年版】

公開日: 2025-11-18 / 更新日: 2025-11-18 セキュリティ実務図解的解説
この記事のゴール
利用者:怪しいQRを見抜く基準を身につける。
配布側:安全に配るためのURL設計・期限・署名・表記の型を学ぶ。

目次

1. 何が危ない?QRフィッシングの典型 / 2. 利用者のチェックリスト(10項目) / 3. 配布側のベストプラクティス(2025) / 4. 期限・署名付きQRの実装例 / 5. 紙・会場での“物理的”対策 / 6. FAQ / 7. まとめ

1. 何が危ない?QRフィッシングの典型

2. 利用者のチェックリスト(10項目)

#チェック理由
1物理的に上貼りされていないかを見る(段差・光沢・ズレ)上貼りは最も多い手口
2URLプレビューを必ず確認(ブラウザで開く前)ドメインを先に見る癖をつける
3httpsと“本物のドメイン”か(鍵マークだけで判断しない)証明書は十分条件ではない
4短縮URL(例:短い乱数)なら一旦避ける最終遷移先を隠せる
5URLが長すぎ/パラメータだらけなら開かないトラッキング/攻撃の混入余地
6決済/ログイン要求は絶対に公式アプリ/ブックマークからQR経由で資格情報を出さない
7公共物・電柱・ベンチ等のQRは原則スルー掲示主体が不明
8プロファイル/アプリのインストールを促すページは閉じる不審な構成プロファイルは危険
9“無料Wi-Fi接続QR”は使わない偽AP誘導の可能性
10メール内QRは送信元と件名の整合を見るアカウント回復を装う偽装が多い

迷ったら「あとで自分のブックマークから開く」。これだけで多くの事故は回避できます。

3. 配布側のベストプラクティス(2025)

URL設計の原則

トークン・期限・署名(Dynamic QRの安全化)

表記・デザインの工夫

4. 期限・署名付きQRの実装例(サンプル)

以下は「署名付きリンク」を生成→サーバで検証する最低限の例です(概念理解用)。

生成(Node.js例)

// 生成側
import crypto from 'node:crypto';
const SECRET = process.env.QR_SECRET; // 長くてランダム

function sign(params){
  const payload = new URLSearchParams(params).toString();   // user=123&exp=1731956400&nonce=...
  const sig = crypto.createHmac('sha256', SECRET).update(payload).digest('hex');
  return `${payload}&sig=${sig}`;
}

// 例:有効期限15分のワンタイムURL
const exp = Math.floor(Date.now()/1000) + 15*60;
const nonce = crypto.randomBytes(8).toString('hex');
const qs = sign({ user:'123', exp, nonce });
const url = `https://example.com/campaign?${qs}`;
console.log(url);

検証(サーバ側・擬似)

// 擬似コード
const used = new Set(); // 実際はDB/TTL付きKVS
function verify(query){
  const {sig, ...params} = query;
  const payload = new URLSearchParams(params).toString();
  const expect = hmacSha256(SECRET, payload);
  if (sig !== expect) return 400;          // 改ざん
  if (Number(params.exp) < now()) return 410; // 期限切れ
  if (used.has(params.nonce)) return 409;     // 再利用
  used.add(params.nonce);
  return 302; // 正規ページへ
}

コマンドライン一発(HMACだけ生成)

# macOS/Linux
PAYLOAD="user=123&exp=1731956400&nonce=abcdef12"
SECRET="長くてランダムな秘密鍵"
SIG=$(printf "%s" "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')
echo "${PAYLOAD}&sig=${SIG}"

※ 実運用ではHTTPS・CSRF・リダイレクト固定・ログ/レート制限も忘れずに。

5. 紙・会場での“物理的”対策

6. FAQ

Q. 短縮URLは絶対NG?

外部の無償短縮は避ける。運用を自分でコントロールできる独自短縮ドメインなら可。最終遷移先は固定・ログは最小限。

Q. 決済QRを安全に配るには?

利用者には「アプリを開いて自分のブックマークからアクセス」を促す。配布側は金額・受取先・有効期限を紙面で明記し、一回性トークンを使う。

Q. Wi-Fi接続QRは?

公衆向けに配るのは非推奨。社内用は掲示板ではなくイントラに掲載し、来訪者には口頭+紙でネットワーク名とパスのみ渡す。

7. まとめ(保存版)

利用者:URLプレビュー→ドメイン確認→決済/ログインはブックマークから。
配布側:自ドメイン直URL・短縮禁止・期限/署名/一回性・人間可読表記・物理対策。
これでQRの“速さ”と“安全”の両立ができます。

関連: AIに任せてはいけない作業 / 1時間で作る個人サイト / 文字数カウンター / パスワード生成
テスト用の受信や確認メールは、広告ゼロの一時メール tomy634.com をどうぞ。