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

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

# TL;DR

- フロントエンド: [透明の画像を被せる](#透明の画像を被せる)
- フロントエンド: [右クリックを禁止する](#右クリックを禁止する)
- フロントエンド: [ドラッグを禁止する](#ドラッグを禁止する)
- バックエンド: [画像のURLから直接アクセスできないようにする](#画像のurlから直接アクセスできないようにする)

# 環境

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

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

```html
<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;`を設定します。

```html:ページ全体を右クリック禁止をしたい場合
<body oncontextmenu="return false;">
```

```html:画像のみ右クリック禁止をしたい場合
<img src="/images/somepic.png" alt="保存されたくない画像" oncontextmenu="return false;" />
```

```js:JavaScriptで制御
document.oncontextmenu = function(){ return false; };
document.body.oncontextmenu = "return false;"
```

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

```js
document.oncontextmenu='';
document.body.oncontextmenu='';
```

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

```html:ページ全体を右クリック禁止をしたい場合
<body onselectstart="return false;" onmousedown="return false;">
```

```html:画像のみ右クリック禁止をしたい場合
<img src="/images/somepic.png" alt="保存されたくない画像"  onselectstart="return false;" onmousedown="return false;" />
```

```js: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タブを開き、以下を実行します。

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

# 画像のURLから直接アクセスできないようにする
まずは画像のURLをそのままブラウザで開いたりcurlやwgetでダウンロードするのを防ぐ方法を紹介します。
バックエンド側で対応します。

## Refererでフィルタリングする
Refererが自ドメインで無ければ403を返すようにします。
nginxでの設定は以下の通りです。

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

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

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

### 回避方法☠
curlやwgetでRefererをリクエスト時に付与するだけです。

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

```wget
wget http://www.yoursite.com/images/sample.png --referer=http://www.yoursite.com
```

# 参考
- [右クリック禁止で画像のコピーガード(ドラッグ禁止対策追加) - Web雑記帳。](http://motoshige.net/blog/archives/366)
- [nginx で画像などへの直リンを対策する場合](https://blog.44uk.net/2014/05/13/nginx-block-hotlinks/)

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

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