Webサーバで読み込んだファイルをダウンロードさせる

Webサーバ側で読み込んだファイルをダウンロードさせるにはResponse.WriteFile([FilePath]) を使用します。その際Response.Buffer を Trueに設定する事でクライアントへの応答をバッファリングしてくれます。(ダウンロードさせるファイルの種類にもよりますが部分的にクライアントに送信しても意味がない場合はバッファリングしておいた方がよいと思います。)

Default.aspx


<%

Response.Buffer = True

Response.ContentType = "application/octet-stream"

Response.WriteFile("C:\test.pdf")
Response.Flush()

%>

これだけなら非常に簡単ですが、実用レベルに持っていくためには、いくつかの課題をクリアする必要があります。


まずはファイル名が問題になります。上記の処理はWebサーバ側で読み込んだデータを応答にそのまま書きだすのでファイル名が無い状態になります。その結果、ブラウザ側で勝手にファイル名が付けられます。(例:IE:default.pdf,firefox:default.aspx)


Response.HeaderEncoding = System.Text.Encoding.GetEncoding("SHIFT-JIS")
Response.AddHeader("content-disposition", "attachment; filename=日本語表.pdf")

この問題を解決するためには content-disposition ヘッダを使用してファイル名を指定します。content-disposition ヘッダは使用に当たっていくつかの注意点があり、それらの内容を把握した上で利用する必要があります。

■Content-Dispositionはセキュリティ上の懸念がある(RFC2616による指摘)

RFC2616(HTTP/1.1) section 15.5
http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.5


15.5 Content-Disposition Issues

RFC 1806 [35], from which the often implemented Content-Disposition (see section 19.5.1) header in HTTP is derived, has a number of very serious security considerations. Content-Disposition is not part of the HTTP standard, but since it is widely implemented, we are documenting its use and risks for implementors. See RFC 2183 [49] (which updates RFC 1806) for details.

Content-Dispostionにはセキュリティ上の懸念がある。詳細は RFC2183を参照。
(See RFC 2183 [49] (which updates RFC 1806) for details. )

http://www.ietf.org/rfc/rfc2183.txt


RFC2183を参照すると・・



5. Security Considerations

There are security issues involved any time users exchange data.
While these are not to be minimized, neither does this memo change
the status quo in that regard, except in one instance.

Since this memo provides a way for the sender to suggest a filename,
a receiving MUA must take care that the sender's suggested filename
does not represent a hazard. Using UNIX as an example, some hazards
would be:

+ Creating startup files (e.g., ".login").

+ Creating or overwriting system files (e.g., "/etc/passwd").

+ Overwriting any existing file.

+ Placing executable files into any command search path
(e.g., "~/bin/more").

+ Sending the file to a pipe (e.g., "| sh").

In general, the receiving MUA should not name or place the file such
that it will get interpreted or executed without the user explicitly
initiating the action.

It is very important to note that this is not an exhaustive list; it
is intended as a small set of examples only. Implementors must be
alert to the potential hazards on their target systems.


Webサーバ側の脆弱性ではなく脆弱なブラウザを使用するクライアント側の問題のようです、セキュリティ上の懸念事項としては悪意あるWebサーバ側クライアントの任意のファイルを置き換える事ができるというもの。恐らくかなり古い過去のブラウザだけが該当する問題のようです。


もしかしたら神経質なファイアウォールがContent-Dispositionヘッダを削除する可能性もありますが、その場合はヘッダが無い場合の動作になるだけで、あまり気にしなくても良いように思います。


■ファイル名が文字化けする。


ファイルをダウンロードする ASP.NET Web ページで日本語ファイル名が文字化けする

http://support.microsoft.com/kb/436616/


日本語ロケールieは、content-dispositionヘッダがSHIFT-JISで指定されることを期待するので、ASP.NETの既定エンコードであるUTF-8で指定されると文字化けします。


content-disposition ヘッダは、本来ならRFC2231でエンコードするべきヘッダなのですがie 自体が対応していないのでRFCに乗っ取って適切にエンコーディングしても問題解決にならないようです。


RFC2231
http://www.emaillab.org/emailref/RFC/rfc2231.txt


そのため、この問題に対応するためResponse.HeaderEncodingを使用して応答ヘッダのエンコーディングをSHIFT-JISに変換します。



Response.HeaderEncoding = System.Text.Encoding.GetEncoding("SHIFT-JIS")
Response.AddHeader("content-disposition", "attachment; filename=日本語表.pdf")


■ファイルが消える


Content-Disposition: attachemnt と Cache-Control: no-cache によるダウンロードの問題

http://support.microsoft.com/kb/436605/ja


Content-Disposition: attachemnt と Cache-Control: no-cache を同時に指定するとダウンロードしたファイルが消えるという問題があります。この2つのHTTPヘッダを同時に指定しないようにする必要があります。


■まとめ
コードは短いけど、整理することが結構多いので注意です。


参考資料:
[HOWTO] 既知の MIME タイプに対し [ファイルのダウンロード] ダイアログ ボックスを開く
http://support.microsoft.com/kb/260519/ja