JavaScript | Web API:クリップボード・共有 - セキュリティ制限

JavaScript JavaScript
スポンサーリンク

クリップボードのセキュリティ制限は「ユーザーを守るための強いガード」

クリップボードには、ユーザーがコピーしたあらゆる情報が入ります。
パスワード、クレカ番号、住所、仕事の文章、社外秘のコード——全部です。

もし Web ページが、ユーザーの知らないところで

  • 勝手にクリップボードを読み取れる
  • 勝手にクリップボードを書き換えられる

としたら、それだけでかなり危険ですよね。

だからブラウザは、Clipboard API に対して
かなり強めの「セキュリティ制限」をかけています。

ここをちゃんと理解しておくと、

「なんで動かないの?」ではなく
「これはブラウザがユーザーを守っているんだな」

と、挙動に納得できるようになります。


大前提:Clipboard API は「安全なコンテキスト」でしか基本的に動かない

HTTPS じゃないと、そもそも門前払いされることが多い

Clipboard API(navigator.clipboard.*)は、
ほとんどのブラウザで「安全なコンテキスト」でしか使えません。

安全なコンテキストとは、ざっくり言うと

  • https:// で始まるページ
  • もしくは http://localhost(ローカル開発用の特別扱い)

です。

例えば、こんなコードを書いたとします。

async function copyText() {
  await navigator.clipboard.writeText("hello");
}
JavaScript

これを http://example.com みたいな
「ただの HTTP ページ」で動かそうとすると、
navigator.clipboard 自体が undefined だったり、
呼び出し時にエラーになったりします。

「なんで?」の答えはシンプルで、

「安全じゃない通信のページに、
OS のクリップボードを触らせたくない」

からです。

開発者としては、

  • 本番は必ず HTTPS
  • ローカル開発は http://localhost

という前提で考えるのが基本になります。


もうひとつの大前提:ユーザー操作に紐づいていないとほぼ拒否される

「勝手に」コピー・ペーストはさせてもらえない

Clipboard API の呼び出しは、
基本的に「ユーザー操作に紐づいている必要」があります。

例えば、次のようなコードはほぼアウトです。

// ページ読み込み直後に勝手にコピーしようとする
window.addEventListener("load", async () => {
  await navigator.clipboard.writeText("勝手にコピー");
});
JavaScript

ブラウザからすると、

「ユーザーは何もしていないのに、
このページがいきなりクリップボードをいじろうとしている」

という状態なので、当然拒否します。

一方で、次のようなコードは「許されやすい」です。

button.addEventListener("click", async () => {
  await navigator.clipboard.writeText("ユーザーがボタンを押したのでコピー");
});
JavaScript

ここでは、

  • ユーザーがボタンをクリック
  • そのイベントハンドラの中で Clipboard API を呼ぶ

という流れになっているので、
ブラウザは「ユーザーの意思に基づく操作」と判断しやすくなります。

ペースト(readText)も同じで、

pasteBtn.addEventListener("click", async () => {
  const text = await navigator.clipboard.readText();
  console.log(text);
});
JavaScript

のように、「ユーザーが今貼り付けたい」と示した瞬間にだけ
読み取りを試みるのが基本形です。


読み取りは「書き込み」よりさらに厳しく見られる

なぜ読み取りが特に厳しいのか

書き込み(コピー)は、
「ユーザーのクリップボードの中身を上書きする」操作です。

もちろんこれも重要ですが、
読み取り(ペースト)はもっと重いです。

読み取りは、

  • ユーザーが何をコピーしたか
  • どんなパスワードや個人情報を扱っているか

を、サイト側が知れてしまう可能性があるからです。

だからブラウザは、読み取りに対して特に厳しく、

  • HTTPS であること
  • ユーザー操作に紐づいていること
  • 場合によっては権限ダイアログで「許可」されていること

といった条件を満たしていないと、
navigator.clipboard.readText() を普通に失敗させます。

コードとしてはこう書きます。

pasteBtn.addEventListener("click", async () => {
  try {
    const text = await navigator.clipboard.readText();
    console.log("クリップボード:", text);
  } catch (err) {
    console.error("読み取りに失敗しました:", err);
  }
});
JavaScript

ここで try...catch が必須なのは、
「セキュリティ制限で失敗することがある」のが前提だからです。


navigator.permissions と権限の状態(概念だけ知っておけばOK)

「このサイトにクリップボードを触らせていいか?」をブラウザが覚えている

一部のブラウザでは、
navigator.permissions という API を通じて
権限の状態を問い合わせられることがあります。

概念としては、こんな感じです。

const status = await navigator.permissions.query({
  name: "clipboard-read"
});

console.log(status.state); // "granted" / "prompt" / "denied" など
JavaScript

clipboard-write についても同様です。

ただし、これはブラウザ差が大きく、
すべての環境で同じように動くわけではありません。

初心者のうちは、

  • Clipboard API を呼ぶ
  • 失敗したら catch で対応する

というシンプルなパターンで十分です。

「権限の状態を事前に確認できることもある」
くらいの理解で OK です。


セキュリティ制限を前提にした「ちゃんとしたコード」の書き方

1. Clipboard API が使えるかどうかを最初に確認する

まずは、ブラウザが Clipboard API に対応しているかをチェックします。

if (!navigator.clipboard) {
  console.log("このブラウザでは Clipboard API が使えません");
}
JavaScript

これをやっておくと、
古いブラウザや特殊な環境での「そもそも無い」ケースを
きれいに弾けます。

2. 失敗する前提で try…catch を必ず書く

コピー処理の例をもう一度、
セキュリティ制限を意識して書き直すとこうなります。

const copyBtn = document.querySelector("#copyBtn");
const status = document.querySelector("#status");

copyBtn.addEventListener("click", async () => {
  if (!navigator.clipboard) {
    status.textContent = "このブラウザではコピー機能が使えません";
    return;
  }

  try {
    await navigator.clipboard.writeText("コピーしたい文字列");
    status.textContent = "コピーしました";
  } catch (err) {
    status.textContent = "コピーに失敗しました: " + err;
  }
});
JavaScript

ここでやっているのは、

  • API が存在するかチェック
  • 実際に呼ぶときは try...catch で囲む
  • 失敗したときにユーザーにちゃんと伝える

という「セキュリティ制限を前提にした書き方」です。


「悪い例」をイメージすると、制限の意味がよく分かる

ページを開いた瞬間にクリップボードを盗み見るコード

もし制限がなかったら、
こんなコードが書けてしまいます。

window.addEventListener("load", async () => {
  const text = await navigator.clipboard.readText();
  // サーバーに送信して盗む、など
});
JavaScript

ユーザーは何もしていないのに、
ページを開いただけでクリップボードの中身が抜かれます。
これは完全にアウトです。

ブラウザのセキュリティ制限は、
こういうコードを「技術的に不可能にする」ために存在しています。

勝手にクリップボードを書き換えるコード

同じく、こんなコードも危険です。

setInterval(async () => {
  await navigator.clipboard.writeText("このサイトの宣伝文");
}, 1000);
JavaScript

ユーザーが何をコピーしても、
1秒ごとに上書きされてしまいます。

これも当然、
ブラウザのセキュリティ制限によって
現実には動かないようにされています。

こういう「悪い例」を頭の中で一度イメージしておくと、

「だから HTTPS が必要なんだ」
「だからユーザー操作に紐づけないとダメなんだ」

という理由が、感覚として腑に落ちてきます。


初心者として「セキュリティ制限」で本当に掴んでほしいこと

Clipboard API のセキュリティ制限は、
細かい仕様を全部覚える必要はありません。

まずは次の感覚だけ、しっかり持っておいてください。

クリップボードは、ユーザーの超プライベートな領域。
だからブラウザは「HTTPS」と「ユーザー操作」を条件にしている。
読み取りは特に厳しく、失敗することを前提に try...catch で書く。
「勝手に読まない・勝手に書き換えない」という倫理も含めて設計する。

そのうえで、次のようなコードを自分の手で書いてみてください。

ボタンを押したときだけテキストをコピーする処理(成功/失敗メッセージ付き)。
ボタンを押したときだけクリップボードの内容を読み取り、画面に表示する処理。

これが自然に書けるようになったとき、
セキュリティ制限は「邪魔な壁」ではなく、
「ユーザーとあなたのアプリの信頼を守るための、大事なルール」
として見えてくるはずです。

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