ようこそゲストさん

Magical Diary, beta version

メッセージ欄

分類 【Apache】 で検索

一覧で表示する

[Apache] mod_rewrite の小技

2007/08/13 0:22 HIRATA Yasuyuki

ループ処理

mod_rewrite でループ処理を行うには、[N] (next) フラグを利用する。たとえば、/hoge/1/bar/2/baz/3/ を /hoge/index.cgi?foo=1&bar=2&baz=3 としたい (その際、パラメータの個数が不定) 場合、下記の通り記述する。"QSA" (query string append) フラグは、書き換え後の QUERY_STRING 部分のみ "追加" の扱いとする。

RewriteEngine on
RewriteLog /var/log/httpd/rewrite.log
RewriteLogLevel 9
# Rule 1:
RewriteRule ^(/hoge/.*/)([^/]+)/([^/]+)/$ $1?$2=$3&path=$1 [QSA,N]
# Rule 2:
RewriteRule ^/hoge/([^/]+)/$ /hoge/index.cgi?foo=$1 [QSA]

処理の流れは以下の通り。

  1. path = "/hoge/1/bar/2/baz/3/", QUERY_STRING="" → Rule 1
  2. path = "/hoge/1/bar/2/", QUERY_STRING="baz=3" → Rule 1
  3. path = "/hoge/1/", QUERY_STRING="bar=2&baz=3" → Rule 2
  4. path = "/hoge/index.cgi", QUERY_STRING="foo=1&bar=2&baz=3"

日本語のファイル名に見せかけてSEO

ファイル名はSEOを考慮すると日本語 (UTF-8) で付けた方が良いが、日本語のファイル名はUnix上で扱いづらいという欠点がある。mod_rewrite を利用することで URL path中の日本語文字列を任意のファイル名 (英数字) にマッピングすることができる。

  1. httpd.conf に以下の行を追加
    RewriteEngine on
    RewriteLog /var/log/httpd/rewrite.log
    RewriteLogLevel 9
    RewriteMap foo_kanji_ascii txt:/www/etc/map/naiyo_kanji_ascii.txt
    RewriteRule ^/(.*[^!-~]+.*) /www/htdocs/${naiyo_kanji_ascii:$1}.html
    
  2. /www/etc/map/naiyo_kanji_ascii.txt に UTF-8 で以下の内容を記載。
    萌え	moe
    
  3. httpd の再起動。
  4. http://www.example.com/%E8%90%8C%E3%81%88 へアクセスすると /www/htdocs/moe.html の内容が表示される。

大規模に書き換えを行う場合には、性能上の観点からテキストファイルではなくDBMファイルで用意することが望ましい。

[Apache] 画像への直接リンクを防ぐ (補足)

2007/07/28 23:45 HIRATA Yasuyuki

画像への直接リンクを防ぐ (2007/07/23) の補足。

RFC 2616 で Referer: は以下の通り定義されており、絶対URIの他、相対URIを含めることも許されている。

Referer = "Referer" ":" ( absoluteURI | relativeURI )

RFC 2616: Hypertext Transfer Protocol (HTTP/1.1), 14.36 Referer

したがって、

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www\.example\.jp/ [NC]
RewriteCond %{REQUEST_URI} !^/tmp/eroero\.gif$
RewriteRule \.(jpg|png|gif)$ http://www.example.jp/tmp/eroero.gif [R,NC]

は、下記の通りとするべきである。

RewriteCond %{HTTP_REFERER} ^http://
RewriteCond %{HTTP_REFERER} !^http://www\.example\.jp/ [NC]
RewriteCond %{REQUEST_URI} !^/tmp/eroero\.gif$
RewriteRule \.(jpg|png|gif)$ http://www.example.jp/tmp/eroero.gif [R,NC]

なお、(アンチウイルスソフトによっては) Referer: に blocked by XXXX とかいう訳のわからん文字列を突っ込んできます との指摘があったが、今回の修正で救われる。とはいえ、これはRFCに違反するそのベンダと利用者の責任であるため、積極的に救う必要は無いだろう。

[Apache] 画像への直接リンクを防ぐ

2007/07/23 20:28 HIRATA Yasuyuki

画像等を外部から直接参照させる形で利用されることを防止する方法。Apache 1.3 + mod_rewrite を利用する。

自サイトが http://www.example.com/ で、それ以外からの直接リンクを避けるには httpd.conf に以下の設定を行う。この設定では、代替画像として http://www.example.jp/tmp/eroero.gif へリダイレクト ("R"; redirect) される。また、"NC" (no case) が指定されているため、大文字と小文字を区別しない。

RewriteEngine on
RewriteLog /var/log/httpd/rewrite.log
RewriteLogLevel 9
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www\.example\.jp/ [NC]
RewriteCond %{REQUEST_URI} !^/tmp/eroero\.gif$
RewriteRule \.(jpg|png|gif)$ http://www.example.jp/tmp/eroero.gif [R,NC]

HTTPで通常アクセスされない領域に代替画像を置き、リダイレクトを行うことなくその画像そのものを返す方法もある。(RewriteCondの記載は省略しているが必要。)

RewriteRule \.(jpg|png|gif)$ /www/tmp/eroero.gif [NC]

また、特定のサイト (http://www.example.com/, http://www.example.net/) からを排除するのみで事足りる場合には、HTTP_REFERER に関する条件を下記のように設定する。なお、いずれかに該当すればよいため、"OR" (logical or) の指定を行っている。

RewriteCond %{HTTP_REFERER} ^http://www\.example\.com/ [OR,NC]
RewriteCond %{HTTP_REFERER} ^http://www\.example\.net/ [NC]

問題点

この方法で制限を行った場合、img による指定や、背景画像として利用されることは防止できるが、通常のリンク (a; アンカータグ) によって参照する場合にも代替画像にリダイレクト (または置換) されてしまう。これを避ける方法は無い。

また、不正に参照しているサイトへのアクセス後、正規のサイト (http://www.example.jp/) へアクセスした場合、正規のサイトから参照されているにも関わらず、(ブラウザのキャッシュにより) 代替画像が表示される可能性がある。このような事象を避けるには、"Expires: 過去の日付", "Pragma: no-cache", "Cache-Control: no-cache" などを出力することで対応できる。これは、send-as-is ハンドラやCGIプログラムを利用することで出力することが出来る。以下、send-as-is ハンドラを利用する場合の設定について記載する。

  1. Apacheのhttpd.confに以下の指定をする。(RewriteCondの記載は省略しているが必要。)
    AddHandler send-as-is asis
      ...
    RewriteRule \.(jpg|png|gif)$ /www/tmp/eroero.gif.asis [NC,L]
    
  2. ヘッダ付きの画像を作成する。
    % cd /www/tmp
    % (cat; cat eroero.gif) > eroero.gif.asis
    Status: 200 OK
    Content-Type: image/gif
    Expires: Thu, 01 Jan 1970 00:00:00 GMT
    Pragma: no-cache
    Cache-Control: no-cache
       ← 空行
    ^D   ← CTRL+D
    
  3. Apacheを再起動する。
    # /usr/local/etc/rc.d/apache.sh restart
    
  • 画像への直接リンクを防ぐ (補足) Magical Diary, beta version HIRATA Yasuyuki
    画像への直接リンクを防ぐ (2007/07/23)の補足。RFC 2616で Referer: は以下の通り定義されており、絶対URIの他、相対URIを含めることも許されている。Referer = "Referer" ":&q...

[Apache] mod_perl用Apacheを分離

2007/07/22 15:11 HIRATA Yasuyuki

Perlを高速に動かすためにはApache HTTPDにmod_perlを組み込むが、mod_perlを読み込んだApacheはメモリを大量に消費する。このため、本格的なサービスを行う場合にはバックエンドでmod_perl用の専用サーバを動作させるが、そこまで用意しなくてもmod_perlだけは分離したいという要求は多い。ここでは、1つのサーバ内でApacheを複数動作させ、mod_perlを分離する方法を以下に解説する。

設計

  • 通常 (mod_perlなし) のApache (a) は *:80 で待ち受け。
  • Apache + mod_perl のApache (b) は 127.0.0.1:8000 で待ち受け。
  • 共通する設定は別ファイルに書いておいて、それぞれの設定ファイルから Include する。
  • アクセスは一度 (a) で受け取って、特定のパスに対しては (b) に逆プロクシする。
   the net
     | ^
     v |
+-----------+
| *:80      |
| Apache(a) |
+-----------+
     | ^  reverse
     v |  proxy
+-----------+
| L:8000    |
| Apache(b) |
+-----------+

設定

  1. 現在利用している httpd.conf を共通設定ファイルとしてファイル名を変更する。
    # cd /usr/local/etc/apache
    # mv httpd.conf httpd.common.conf
    
  2. /usr/local/etc/apache/httpd.conf を下記内容で作成する。これは /myapp/ 以下を mod_perl を組み込んだ Apache に対するプロクシアクセスとする例である。
    Include /usr/local/etc/apache/httpd.common.conf
    ProxyRequests Off
    ProxyPass /myapp/ http://localhost:8000/myapp/
    ProxyPassReverse /myapp/ http://localhost:8000/myapp/
    
  3. /usr/local/etc/apache/httpd.mod_perl.conf を下記内容で作成する。この例では、/myapp/ 以下で Catalyst の MyApp を動作させている。
    Include /usr/local/etc/apache/httpd.common.conf
    Listen 127.0.0.1:8000
    PidFile /var/run/httpd.mod_perl.pid
    ScoreBoardFile /var/run/httpd.mod_perl.scoreboard
    ErrorLog /var/log/httpd/mod_perl/error.log
    CustomLog /var/log/httpd/mod_perl/access.log combined
    AddModule mod_perl.c
    <Location /myapp/>
      <Perl>
        use lib qw[/www/app/MyApp/lib];
      </Perl>
      SetHandler perl-script
      PerlHandler MyApp
    </Location>
    
  4. サーバ (a) は今までどおり起動されるが、サーバ (b) は別途起動スクリプトを用意する必要があるので、/usr/local/etc/rc.d/apache.mod_perl.sh を作成する。
    # cd /usr/local/etc/rc.d
    # sed 's/apache/apache_mod_perl/g' apache.sh > apache.mod_perl.sh 
    # vi apache.mod_perl.sh
    # chmod 555 apache.mod_perl.sh
    
    viでは以下を書き換える。
    apache_mod_perl_flags="-f /usr/local/etc/apache/httpd.mod_perl.conf"
    apache_mod_perl_pidfile="/var/run/httpd.mod_perl.pid"
    
  5. /etc/rc.conf に下記内容を追加する。
    apache_enable="YES"
    apache_mod_perl_enable="YES"
    
  6. Apache (a) を再起動、Apache (b) を起動する。
    # /usr/local/etc/rc.d/apache.sh restart
    # mkdir /var/log/httpd/mod_perl/
    # /usr/local/etc/rc.d/apache.mod_perl.sh start
    

以上の設定により、http://server/myapp/ 以下へのアクセスが、mod_perl 側サーバへのプロクシアクセスとなる。

問題点

  • 1つのサーバ内で複数のApacheを起動するため混乱しやすい。
  • Apache (b) では常に REMOTE_ADDR が 127.0.0.1 となる。このため、HTTP_X_FORWARDED_FOR を参照するか、Apache (a) 側で処理を行う必要がある。

mod_rewrite

mod_rewriteを使用して逆プロクシを設定する場合には、下記のように設定する。これは、/moe/*.cgi についてのみ Apache (b) へのプロクシを実施する。ディレクトリ単位で設定すると、プログラム以外の画像ファイルまで Apache (b) で処理されることもあるため、mod_rewrite で処理するほうが望ましいと言える。

RewriteEngine on
RewriteLog /var/log/httpd/rewrite.log
RewriteLogLevel 9
RewriteRule ^/moe/([^/]+\.cgi)$ http://localhost:8000/moe/$1 [P]

[Apache] Apache 1.3 + mod_access_rbl

2007/07/16 23:17 HIRATA Yasuyuki

メールサーバでは接続元のIPアドレスを元に接続を拒否するため、DNSBL (またはRBL) と呼ばれるブラックリストの仕組みが利用されている。

あるIPアドレスがDNSBLに載っているかどうかの調査は、以下の文字列を連結したホスト名の存在をチェックすることで可能となる。

  • DNSの逆引きの場合と同様にIPアドレスの順番を入れ替えたもの
  • DNSBL のドメイン名

たとえば dnsbl.example.com でサービスする DNSBL でIPアドレス 192.168.1.2 がリストされているかを調べるには、 2.1.168.192.dnsbl.example.com というホスト名の存在を確認すればよい。

なお、このホストに対応するIPアドレスはループバックアドレスである 127.0.0.1 が利用されることが多いが、各ビットの on/off によって意味を持たせているDNSBLも存在する。また、TXT RR には接続拒否時に出力するためのメッセージ (たとえば、"South Korea rejected" など) が設定されていることも多い。

これらのDNSBLをHTTPでも利用するための Apache 1.3 用モジュールが mod_access_rbl として存在したが、現在配布サイトが消滅しているため、入手不可となっている。(Apache 2.x 用は同様のものが複数存在するようだ。)

幸いにも 2.x 用のモジュールを 1.3 へ移植したものを発見したので、今回はこれを利用することにする: Peak Xoops - mod_access_rbl

# cd /usr/ports/www/apache13-modssl/work/apache_1.3.37/src/modules/standard
# patch < /path/to/mod_access.patch
# make mod_access.so
# cp mod_access.so /usr/local/libexec/apache/
# /usr/local/etc/rc.d/apache.sh restart

まだ試してはいないが、httpd.conf に以下の設定をすればこれを活用することが出来るはず。(dnsbl.example.com は実在しないので適当なものに置き換える必要がある。)

<Files *.cgi>
  <Limit POST>
    Order allow,deny
    Allow from all
    Deny via dnsbl.example.com
  </Limit>
</Files>
© 2007 HIRATA Yasuyuki <yasu@asuka.net>, all rights reserved