Ramazeさんで"HTTP Cache Poisoning via Host Header Injection"をやってみました
15KB Of Fame: HTTP Cache Poisoning via Host Header Injection という記事を読みました。これは、HTTP GET を発行する時に HOST を好きに指定することで、サーバ側のレンダリング結果のキャッシュを汚染しちゃって色々できちゃわない?というものです。HTTP_HOST に変なのが入ってるとはあんまり考えないだろうという油断を突いたもの、ということでしょうか。
元記事のヤツだと具体的にどういう事か分かりづらいかと思いますので、これをRamazeさんを使って再現してみることにします。
require "rubygems" require "ramaze" class MyController < Ramaze::Controller map :/ engine :None helper :cache # 次の指定により http://localhost:7000/ のレンダリング結果は # キャッシュされ再利用されます cache :index def index <<-__HTML__ <html><body> HOST: #{request.env["HTTP_HOST"]} </body></html> __HTML__ end end Ramaze.start
以上のような内容の Ramaze アプリ(test.rb)を起動します。
% ruby test.rb [2008-06-11 16:55:07] INFO Starting up Ramaze (Version 0.3.9.1) [2008-06-11 16:55:07] WARN Public root: 'public' doesn't exist [2008-06-11 16:55:07] WARN Template root: 'view' doesn't exist [2008-06-11 16:55:07] DEBUG mapped Controllers: {"/"=>MyController} [2008-06-11 16:55:07] INFO Ramaze is ready to run on: 0.0.0.0:7000 ...
というわけで、サーバは http://localhost:7000/ で待ち構えています。では準備が整いました。
まず悪い人が telnet かなにかを使ってサーバに接続します。
% telnet localhost 7000
ここで次のようなリクエストを発行します。
GET / HTTP/1.1 Host: example.com
するとサーバは request.env["HTTP_HOST"] を鵜呑みにしてレンダリングしますので、次のような内容が返ってきます。
<html><body> HOST: example.com </body></html>
さて、このレンダリング結果はサーバ側にキャッシュされています。そこで、良い子の人が普通のブラウザで http://localhost:7000/ にアクセスしますと、キャッシュされたものがそのまま返ってきますので、やはり次のような内容が返ってきてしまいます。
<html><body> HOST: example.com </body></html>
すると、わー、localhost:7000 に接続したはずなのにびっくり!という事になってしまうわけです。
ということなのですが、これを完成させるためには、悪い人は非常にタイミング良くリクエストを投げてやる必要があると思います。正直結構難しいのではないでしょうか。あと、request.env["HTTP_HOST"] を直接レンダリングする場合って少ないと思うのですが、そうでもないのでしょうか。
脆弱性って言う程でもない気がするのですが、気をつけておいた方が無難だろう、とは思いました。