HTML
JavaScript
nginx
HTML5
Web

画像の保存を禁止する方法とその回避方法

Webサイトによっては掲載する画像を保存できないようにしなければいけない時があります。
今回は画像がダウンロードできないようにするための対策とその回避方法を紹介します。
回避方法に関しては既存のサイトでも使えるかもしれないので、悪用厳禁です!
また、ここに載っている方法は回避可能なので他の方法を検討しなければいけません。
個々の内容は昔からあるテクニックなので何番煎じな内容ですが、まとめ記事として残しておきます。

TL;DR

環境

  • フロントエンドはChromeで確認しています。
  • バックエンドはnginx、Node.jsで確認しています。
  • OSはmacOS 10.13で確認しています。

透明の画像を被せる

保存されたくない画像の上に透明の画像をかぶせます。
これで右クリックから画像を保存しても、透明の画像が保存されるようになり画像を守ります。
実装は簡単で同サイズまたはそれより大きいサイズの透明な画像を用意し、z-indexを指定するだけです。

<img src="/images/somepic.png" alt="保存されたくない画像" width="800" height="600"/>
<img src="/images/dummy.png" alt="透明の画像" width="800" height="600" style="z-index: 2"/>

回避方法☠

これは簡単です。
開発者ツール(devTools)のElementsタブを開き、透明の画像を指定しているHTML要素を削除するだけです。

右クリックを禁止する

右クリックをできないようにすることで画像の保存をできないようにします。
これはoncontextmenuにreturn false;を設定します。

ページ全体を右クリック禁止をしたい場合
<body oncontextmenu="return false;">
画像のみ右クリック禁止をしたい場合
<img src="/images/somepic.png" alt="保存されたくない画像" oncontextmenu="return false;" />
JavaScriptで制御
document.oncontextmenu = function(){ return false; };
document.body.oncontextmenu = "return false;"

回避方法☠

JavaScriptでoncontextmenuに設定しているreturn false;を削除します。
開発者ツール(devTools)のConsoleタブを開き、以下を実行します。

document.oncontextmenu='';
document.body.oncontextmenu='';

ドラッグを禁止する

これは前項の『右クリックを禁止する』と似ています。
onselectstartとonmousedownにreturn false;を設定します。

ページ全体を右クリック禁止をしたい場合
<body onselectstart="return false;" onmousedown="return false;">
画像のみ右クリック禁止をしたい場合
<img src="/images/somepic.png" alt="保存されたくない画像"  onselectstart="return false;" onmousedown="return false;" />
JavaScriptで制御
document.onselectstart = function(){ return false; };
document.onmousedown = function(){ return false; };
document.body.onselectstart = "return false;"
document.body.onmousedown = "return false;"

回避方法☠

JavaScriptでonselectstartとonmousedownに設定しているreturn false;を削除します。
開発者ツール(devTools)のConsoleタブを開き、以下を実行します。

document.onselectstart='';
document.onmousedown='';
document.body.onselectstart='';
document.body.onmousedown='';

画像のURLから直接アクセスできないようにする

まずは画像のURLをそのままブラウザで開いたりcurlやwgetでダウンロードするのを防ぐ方法を紹介します。
バックエンド側で対応します。

Refererでフィルタリングする

Refererが自ドメインで無ければ403を返すようにします。
nginxでの設定は以下の通りです。

location ~* /images/.*\.(jpg|png|gif|jpeg|webp)$ {
    valid_referers server_names *.yoursite.com;
    if ($invalid_referer) {
        return 403;
    }
}

Node.jsで行う場合は以下のようにパターンマッチで確認するとよいでしょう。

if (!/^https?.*\.yoursite.com/).test(req.referer) {
  res.send(403);
}

回避方法☠

curlやwgetでRefererをリクエスト時に付与するだけです。

curl -OL http://www.yoursite.com/images/sample.png -H "Referer: http://www.yoursite.com"
wget http://www.yoursite.com/images/sample.png --referer=http://www.yoursite.com

参考

あとがき

フロントエンドの技術やリクエストヘッダーなどユーザーが設定できるような方法では画像の保存を防ぐことはできないことがわかりました。
ここに載せた方法以外の対策を行っても絶対に保存できないようにすることは難しいと思います。
インターネットに公開するとはそういうことだと思います。
複数の方法を組み合わせたり、ユーザーが何か操作するたびにoncontextmenuをreturn false;にするなど工夫して対策するしかないかと思います。
不備、質問、他にも良い方法があればコメント欄かTwitter(@shisama_)にて教えていただければ幸いです。

最後までお読み頂きありがとうございました。