2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Authorization ヘッダーを環境変数で扱うために CGIPassAuth を有効にする

Last updated at Posted at 2016-09-10

概要

Apache HTTP Server 2.4.13 で CGIPassAuth ディレクティブ (公式マニュアル) がコア機能に追加されました。このディレクティブのデフォルト値は Off です。On をセットすると CGI (FactCGI) で Authorization ヘッダーを環境変数で扱うことができるようになります。CGIPassAuth ディレクティブは .htaccess でも使うことができるので、共用のホスティングサービスでも利用できることを意味します。

以前のバージョンでは mod_rewrite の RewriteRule ディレクティブを使うかコンパイル時に SECURITY_HOLE_PASS_AUTHORIZATION フラグを指定する必要がありました。これらの方法と比べて CGIPassAuth ディレクティブのほうがかんたんです。

mod_cgimod_cgidmod_proxy_fcgimod_proxy_scgi といった ap_add_common_vars() を使うモジュールであれば CGIPassAuth ディレクティブを考慮します。mod_includemod_ext_filter といったリクエストを扱わないモジュールにも影響します。

Authorization ヘッダーがデフォルトで扱えない理由

コンパイルオプションの SECURITY_HOLE_PASS_AUTHORIZATION フラグに関連するコードを読むと Authorization ヘッダーをデフォルトで読み込めないようにしているのは ps -e で盗み見ることができることが挙げられています。

server/util_script.c
# https://github.com/apache/httpd/blob/ea64e031b97533efc10b5f73c8902fe72de9bd7e/server/util_script.c#L197.L209

/*
 * You really don't want to disable this check, since it leaves you
 * wide open to CGIs stealing passwords and people viewing them
 * in the environment with "ps -e".  But, if you must...
 */
#ifndef SECURITY_HOLE_PASS_AUTHORIZATION
else if (!ap_cstr_casecmp(hdrs[i].key, "Authorization")
         || !ap_cstr_casecmp(hdrs[i].key, "Proxy-Authorization")) {
    if (conf->cgi_pass_auth == AP_CGI_PASS_AUTH_ON) {
        add_unless_null(e, http2env(r, hdrs[i].key), hdrs[i].val);
    }
}
#endif

mod_rewrite による対応方法

比較のために mod_rewrite の RewriteRule ディレクティブを使う方法を示します。

# http://symfony.com/doc/current/setup/web_server_configuration.html
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

検証

Docker の公式イメージによる環境構築

コマンドツールの docker および docker-compose が導入されていることを前提とします。OS は Alpine Linux としました。PHP や HTML ファイルは www フォルダに設置します。Docker のほかの設定ファイルの例はこちらをご参照ください。

docker-compose.yml
app:
  image: alpine:3.4
  volumes:
    - ./www:/usr/local/apache2/htdocs
  command: /bin/true
php:
  image: php:7.1-fpm-alpine
  ports:
    - '9000:9000'
  volumes_from:
    - app
apache:
  build: ./
  ports:
    - '80:80'
  volumes_from:
    - app
  links:
    - php
Dockerfile
FROM httpd:2.4-alpine

RUN { \
  echo 'LoadModule proxy_module modules/mod_proxy.so'; \
  echo 'LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so'; \
  echo ''; \
  echo 'DirectoryIndex index.php index.html'; \
  echo '<FilesMatch \.php$>'; \
  echo '    CGIPassAuth On'; \
  echo '    SetHandler "proxy:fcgi://php:9000"'; \
  echo '</FilesMatch>'; \
} >> /usr/local/apache2/conf/httpd.conf

SetHandlerProxyPassMatch

Dockerfile に記載されている SetHandler "proxy:fcgi://php:9000"phpdocker-compose.yml で指定した名前です。Docker を使っていなければ localhost127.0.0.1 に書き換えることができます。SetHandler による php-fpm の設定方法は Apache 2.4.10 から利用できます。

以前から使われていた ProxyPass もしくは ProxyPassMatch の場合、PATH_INFO 環境変数がセットされないために、SCRIPT_NAME が正しく決定されない問題があります (PHP のバグレポート)。くわしくは mod_proxy_fcgi のマニュアルの環境変数の項目をご参照ください。

サービスの起動と停止

docker-compose.ymlDockerfilewww/index.php を設置したフォルダのなかで次のコマンドを実行すればサービスが起動します。

docker-compose up --build -d

サービスを停止させるには次のコマンドを実行します。

docker-compose stop

HTTP クライアントで確かめる

コマンドツールの curl で確かめてみましょう。

curl -H 'Accept-Charset: utf-8' -H 'Authorization: hello' http://localhost:3000

サーバー側のスクリプト は次のようになります。HTTP_AUTHORIZATION が存在することを確認します。

index.php
<?php

var_dump('hello' === $_SERVER['HTTP_AUTHORIZATION']);
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?