Quantcast
Channel: mattintosh note
Viewing all articles
Browse latest Browse all 892

サイト全体にBasic認証をかけて特定のURLだけ認証を無効にしたい

$
0
0

WordPressEC-CUBEとかそういうの使ってると .htaccessにこんな風に書いてある。

WordPress: .htaccess

RewriteEngineOnRewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

EC-CUBE 4.0.5: .htaccess

RewriteEngineOnRewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !^(.*)\.(gif|png|jpe?g|css|ico|js|svg|map)$ [NC]
RewriteRule ^(.*)$ index.php [QSA,L]

どっちも似たようなことを書いているけど、ざっくり説明すると「ファイルが存在しなければ全部 index.phpに投げる」みたいな設定。

WordPressなら /2021/03/diaryみたいなパスや、EC-CUBEなら /products/listみたいなパスで、実際にファイルやディレクトリが存在していないにもかかわらずページが表示されるのは index.phpにリダイレクトされて index.phpが受け取った情報によってページの振り分けをしているから。

さて、「サイト全体にベーシック認証をかけて特定のページだけ認証を無効にしたい(除外したい)」という話だけど、どんなときにそういうことが必要になるかというと、例えば EC-CUBEを使っていて決済通知を受け取るような場合に何を使っているかにもよって変わるけど、「クロネコwebコレクト」だと /shopping/yamato_payment_recv、「GMOペイメントゲートウェイ」だと /shopping/gmo_payment_recvに決済通知システムからのリクエストが来る。ここにベーシック認証がかかっていると決済通知は認証を通れない。本番環境ではあまり無いだろうけど検証環境とかだとこういう構成が必要になってくることがある。

また、AWSなどで Application LoadBalancer(以下 ALB)のヘルスチェックのために認証を外す必要がある。

以下、Apache 2.4 での話。

今回のような場合は下記のように書いたりするかもしれない。

Apache 2.4: .htaccess

RewriteEngineOnRewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !^(.*)\.(gif|png|jpe?g|css|ico|js|svg|map)$ [NC]
RewriteRule ^(.*)$ index.php [QSA,L]

### ベーシック認証設定AuthTypeBasicAuthUserFile /var/www/.htpasswd
AuthName .
Requirevalid-user### リクエストが ``/path/to/noauth''だったら環境変数 ``noauth''を定義するSetEnvIf Request_URI ^/path/to/noauth$ noauth

### ローカルからのアクセスは許可## Apache 2.2#Allow from localhost## Apache 2.4Require local

### 環境変数 ``noauth''が定義されていたら許可## Apache 2.2#Allow from env=noauth## Apache 2.4Require env noauth

上記の設定だと

  • localhostからのアクセスは無制限
  • それ以外のパスには Basic 認証がかかっているが /path/to/noauthは無効

と思われるが、実際には /path/to/noauthにアクセスしても Basic 認証が発生する。順を追ってみると下記のようになってるはず。

  1. /path/to/noauthにアクセスする
  2. 環境変数noauthが定義される
  3. 環境変数noauthがチェックされて許可
  4. /path/to/noauthは存在しないため RewriteRuleによって index.phpにリダイレクトされる
  5. index.phpにアクセスする
  6. index.phpでは環境変数noauthは定義されない
  7. 環境変数noauthがチェックされて拒否

環境変数noautoが定義されるのは /path/to/noauthだけであって index.phpでは発生しない。

「そうか!ならこうすれば良いんだな!」ってことで下記のようにしたとする。

Apache 2.4: .htaccess

SetEnvIf Request_URI ^/index.php$      noauth
SetEnvIf Request_URI ^/path/to/noauth$ noauth

一見これでも目的が達成できているように見える。しかし(いまどきブラウザに打ち込む人は少ないと思うけど)/index.phpに直接アクセスすると認証をすり抜けるという罠がある。

とりあえず index.phpnoauthを設定をするのは止めて ApacheLogLeveldebugにしてログを見てみよう。

Apache 2.4: error_log (一部の情報を省略しています)

authorization result of Require valid-user : denied (no authenticated user yet) authorization result of Require local : denied authorization result of Require env noauth : granted❶noauth が定義されている authorization result of <RequireAny>: granted❷許可 authorization result of Require valid-user : denied (no authenticated user yet) authorization result of Require local : denied authorization result of Require env noauth : denied❸noauth が定義されていない authorization result of <RequireAny>: denied (no authenticated user yet) ❹拒否

認証が 2 回行われていることや、❷で一度は granted されているのに❹で denied されていることがわかる。(ちなみにここの Requireの順番は .htaccessに書いた順番)

index.phpnoauthが引き継げればいいのに…」と思った人は index.php

index.php

<?phpphpinfo();

にして「Apache Environment」のセクションを見てみよう。(Basic 認証はクリアしても無効にしても可)

f:id:mattintosh4:20210318232907p:plain

環境変数の一覧に定義した覚えのない REDIRECT_noauthという環境変数が見つかるはず。(_noauth部分は定義した環境変数によって変わる)

これはリダイレクトした際に Apacheが新たに定義する環境変数で、プレフィックスとして REDIRECT_が付与される。他には REDIRECT_URLREDIRECT_STATUSなどがある。

つまり最初に定義した noauth環境変数index.phpにリダイレクトした際に消えたのではなく REDIRECT_noauthに置き換えられたということ。なのでこれを許可してやればいいことになる。

SetEnvIf Request_URI ^/path/to/noauth$ noauth

Require env noauth
Require env REDIRECT_noauth

なお、Require envの書式は Require env env-env [env-var] ...となっているので下記のようにまとめて書いても良い。動作はドキュメントに Access is allowed only if one of the given environment variables is set.とある通り、どれか 1 つの環境変数が含まれていれば granted となる。

Require env noauth REDIRECT_noauth

もう一度 /path/to/noauthにアクセスすれば 1 回目は Require env noauth: granted、2 回目は Require env REDIRECT_noauth: grantedとなっているはず。

Apache 2.4: error_log (一部の情報を省略しています)

# /path/to/noauth の認証 authorization result of Require valid-user : denied (no authenticated user yet) authorization result of Require local : denied authorization result of Require env noauth: granted authorization result of : granted # index.phpの認証 authorization result of Require valid-user : denied (no authenticated user yet) authorization result of Require local : denied authorization result of Require env noauth: denied authorization result of Require env REDIRECT_noauth: granted authorization result of : granted

直接 index.phpにアクセスした場合は REDIRECT_noauthが存在しないので Basic 認証が発生する。


一応ネット上の情報も調べてみたが下記のように REDIRECT_STATUSでやっている人もいた。これは index.phpにリダイレクトされたときに自動的に定義される REDIRECT_STATUSをリダイレクト元にも設定してしまえ、というもの…だと思う。

Apache 2.4: .htaccess

SetEnvIf Request_URI ^/path/to/noauth$ REDIRECT_STATUS
Require env REDIRECT_STATUS

一見お手軽そうだが、リダイレクト元で定義された REDIRECT_STATUS(暗黙的に REDIRECT_STATUS=1) は index.phpにリダイレクトされると REDIRECT_プレフィックスが付与されて REDIRECDT_REDIRECT_STATUS=1となり、index.phpでは新たに REDIRECT_STATUS=200が定義されるため少々微妙に思える。

/path/to/noauth index.php
REDIRECT_STATUS 1 200
REDIRECT_REDIRECT_STATUS 未定義 1

f:id:mattintosh4:20210318235957p:plain


まとめとして EC-CUBEで ALB のヘルスチェックファイルや「クロネコwebコレクト」、「GMOペイメントゲートウェイ」、「Paidy」の決済通知先を Basic 認証の対象外にする例を下記に書いておく。(私はネットワークレベルで制限するから .htaccessで設定しないんだけどレンタルサーバなら有用かも…)

Apache 2.4: .htaccess

AuthTypeBasicAuthName .
AuthUserFile /var/www/.htpasswd

# デフォルトでは RequireAny なので# ローカルからのアクセスや valid-user、環境変数(noauth または REDIRECT_noauth)が定義されていれば許可Require local
Requirevalid-userRequire env noauth REDIRECT_noauth

# ロードバランサー ヘルチェックファイル用SetEnvIf Request_URI ^/healthcheck.php$ noauth

# クロネコwebコレクト 決済通知用SetEnvIf Request_URI ^/shopping/yamato_payment_recv$ noauth

# GMO-PG 決済通知用SetEnvIf Request_URI ^/shopping/gmo_payment_recv$ noauth

# Paidy 決済通知用SetEnvIf Request_URI ^/paidy_webhook$ noauth

複雑な例として Apache環境変数に任意の値を使ったお遊びを下記に書いておく。

Apache 2.4: .htaccess

# アクセスを許可する URL (noauth 環境変数にレベル付する)SetEnvIf Request_URI ^/path/to/1$ noauth=1
SetEnvIf Request_URI ^/path/to/5$ noauth=5

### index.php 用# REDIRECT_noauth が ``1''以上Require expr %{env:REDIRECT_noauth} -ge 1

### /path/to/1 用# noauth 環境変数が ``1''かつプライベート IP からのアクセス<RequireAll>
    Require expr %{env:noauth} -eq 1
    Require ip 10 172.16.0.0/12 192.168
</RequireAll>

### /path/to/5 用# noauth 環境変数が ``5''かつローカルからのアクセス<RequireAll>
    Require expr %{env:noauth} -eq 5
    Require local
</RequireAll>

Require envは書式が Require env env-var [env-ver] ...環境変数が定義されているかどうかで値のチェックができないため Require env noauth=1のように書きたい場合は Require exprを使わなければならない。

ALB 使っていて mod_remoteip とか mod_extract_forwarded の設定をしてない人は IP で制限しようとすると面倒になるので注意した方がいいかも。


Viewing all articles
Browse latest Browse all 892

Trending Articles