apache2.4系でBasic認証 or Digest認証、特定IPアドレスからは認証なしで

# はじめに
「このサイト、オープンするまでBasic認証かけておいて」
「めんどくさいから社内からは認証なしでいいんじゃない」
みたいな依頼が多々あると思いますのでその時の設定方法。

## 前提
CentOS7、AmazonLinuxとかでyumでインストールしたApache2.4系です。
モジュールがロードされていないと使えないので、チェック

```shell-session
$ httpd -M | grep auth
...
 auth_basic_module (shared)
 auth_digest_module (shared)
...
```

ロードされていなければ設定が必要

```apache:/etc/httpd/conf.modules.d/00-base.conf
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule auth_digest_module modules/mod_auth_digest.so
```

## Basic認証のかけ方
特定のディレクトリ`<Direcroty>`、もしくはロケーション`<Location>`で下記ディレクティブを設定する。

```apache
<Directory "/var/www/html">
...
    AuthType Basic
    AuthName "Basic Auth"
    AuthUserFile /etc/httpd/conf/.htpasswd
    Require valid-user
...
</Directory>

# もしくは
<Location />
    AuthType Basic
    AuthName "Basic Auth"
    AuthUserFile /etc/httpd/conf/.htpasswd
    Require valid-user
</Location>
```

|ディレクティブ名|概要|
|:----------------|:-------------------|
|AuthType|ユーザ認証の種類で Basic、Digest とか|
|AuthName|HTTP認証の認可領域、ユーザに向けて許可領域を表示させられるけどchromeだと何もでないのかな。|
|AuthUserFile|認証に使うユーザ/パスワードの一覧ファイルを指定|
|Require valid-user|認証されたユーザにディレクトリ、ロケーションへのアクセスを許可する|

AuthUserFileでID/Passwordのファイルを指定するので、htpasswdコマンドで作成。

```shell-session
htpasswd -c <AuthUserFileのファイルパス> <username>

例）
$ sudo htpasswd -c /etc/httpd/conf/.htpasswd hogeuser
New password: パスワード入力
Re-type new password: パスワード再入力
Adding password for user hogeuser

中身はこんな感じ
$ cat /etc/httpd/conf/.htpasswd 
hogeuser:$apr1$1WryeeJ.$MgUtE/Yt0HHBdDdEDCxW9/
```

そしてコンフィグをチェックして、問題なければ再起動で設定完了。

```shell-session
$ apachectl configtest
Syntax OK
$ sudo systemctl reload httpd
```

ちなみに.htaccessが有効なサーバであれば、下記内容の.htaccessを特定のディレクトリに配置すればよい。

```apache:.htaccess
AuthType Basic
AuthName "Basic Auth"
AuthUserFile /etc/httpd/conf/.htpasswd
Require valid-user
```

## Digest認証のかけ方
AuthTypeをDigestにして、Digest認証用のユーザ/パスワードファイルを指定する。

```apache
<Directory "/var/www/html">
...
    AuthType Digest
    AuthName "Digest Auth"
    AuthUserFile /etc/httpd/conf/.htdigest
    Require valid-user
...
</Directory>

# もしくは
<Location />
    AuthType Digest
    AuthName "Digest Auth"
    AuthUserFile /etc/httpd/conf/.htdigest
    Require valid-user
</Location>
```

Digest認証用のユーザ/パスワードファイルを作成するにはhtdigestコマンドで作成。

```shell-session
htdigest -c <AuthUserFileのファイルパス> <AuthName> <username>

例) 
$ sudo htdigest -c /etc/httpd/conf/.htdigest "Digest Auth" hogeuser
```

コンフィグをチェックして、問題なければ再起動で設定完了。

```shell-session
$ apachectl configtest
Syntax OK
$ sudo systemctl reload httpd
```

## 特定のIPアドレスからは認証なし
`<RequireAny>`ディレクティブを使うと`Require`で指定された許可方法のうち、いずれかを満たしていればアクセスできるようになり、今回はIPアドレス許可なので、`Require ip`、もしくは`Require valid-user`のどちらかが許可されればアクセスきるようになります。
Digest認証での設定に追加すると下記の通り。

```apache
<Location />
    <RequireAny>
        AuthType Digest
        AuthName "Digest Auth"
        AuthUserFile /etc/httpd/conf/.htdigest
        Require valid-user
        Require ip 192.168.10.10
    </RequireAny>
</Location>
```

この設定だと192.168.10.10からのアクセスはDigest認証なしでアクセスできます。

##で、Basic認証とDigest認証ってどっちが嬉しいの？
Basic認証はユーザ名とパスワードをBase64エンコードしたものを使う認証で、
Digest認証はユーザ名とパスワードをMD5でハッシュ化したものを使う。

ふむ。Base64エンコードだとデコードすれば中身わかるのでDigestの方が良さそう。
HTTPSであればどちらでも良いかと。

`Authorization`リクエストヘッダで何を送っているかわかります。

#### Basic認証

```
~~
Accept-Language:ja,en-US;q=0.8,en;q=0.6
Authorization:Basic aG9nZXVzZXI6aG9nZXBhc3N3b3Jk
~~
```

base64なのでこういう感じでデコードすると、

```shell-session
$ echo aG9nZXVzZXI6aG9nZXBhc3N3b3Jk | base64 -d
hogeuser:hogepassword
```

まあ、そうだよね、となります。

#### Digest認証

```
~~
Accept-Language:ja,en-US;q=0.8,en;q=0.6
Authorization:Digest username="hogeuser", realm="Digest Auth", nonce="uyVNqaRTBQA=d3cdbce0f20e896498f794025f45ae71297853d0", uri="/", algorithm=MD5, response="cf50dccbe3a6e91996ccd2fbb5f6c7be", qop=auth, nc=00000001, cnonce="fa112885a6fc6360"
~~
```
なんかいろいろと送っているけど、サーバ側から送られてきた情報を基にしてにしてユーザ名、パスワードからこれらを生成してます。

Basic認証はエンコードしているとはいえ平文でユーザ名：パスワードを送っているのと同じなのでおじさんは不安がいっぱいです。
今時のブラウザはDigest認証に対応しているので基本的にはDigest認証でいいんじゃないかな。
ま、上記にも書きましたがHTTPSであればどちらでも良いのかと。

ちなみに「Basic認証かけて」と言ってくる人はDigest認証のことを知らない場合が多い（Digestにしますか、と聞くと「ん？なんのこと？とにかくBasic認証かけてね」というやり取りが発生）のと、ユーザの見た目には変わらないので、「かけましたよ」っていってDigest認証にしておくのもありですね。