はじめに
花粉にうんざりをしているキティちゃんです。おはこんばんにちは。今回はファイルアップロードとセキュリティについてお話をしていこうと思います。
きっかけ
ファイルをアップロードする機能を見かけたからです。見つけちゃうとテーマとして面白そうだなと思ってつい書いちゃいます。
ファイルアップロードとは
画像であったり、PDFなどをフォルダから選択してアップロードをするなんて経験をしたことがある方もいらっしゃるかと思いますが、まさにこのアップロードする行為、機能がファイルアップロードです。最近だとライブチケットの顔写真登録でこの機能を見かけました。自分の顔写真を撮って、アップロードして登録するものです。よく、入力した内容に誤りがないか、個人情報に偽りがないかを確認する目的でアップロードさせたりしますね。
どんなセキュリティの問題があるのか
以下のことが挙げられます。
1.アップロード機能に対するDoS攻撃
2.アップロードしたファイルをサーバー上のスクリプトとして実行する攻撃
3.仕掛けを含むファイルを利用者にダウンロードさせる攻撃
4.閲覧権限のないファイルのダウンロード
アップロード機能に対するDoS攻撃
この内容を触れるにあたって、DoS攻撃についても説明します。DoS攻撃とは、大量なリクエストを送るとことで、サーバーに負荷をかけ、レスポンスを低速にしたり、サービスを落としたりする攻撃のことです。この攻撃をファイルアップロード時に利用します。アップロードをする際に、大量のデータを送信、データ容量の大きいものを送信し、Webアプリケーションに対して、大きな負荷を与えます。
【対策】例えば、Apacheの設定ではリクエストボディサイズを絞ることができます。それ以外の設定方法は各言語のマニュアルだったりを参照してください。
Apacheでは、[LimitRequestBody]が該当する設定となります。
アップロードしたファイルをサーバー上のスクリプトとして実行する攻撃
アップロードしたファイルがWebサーバーの公開ディレクトリに保存される場合、アップロードしたスクリプトファイルがWebサーバー上で実行できてしまう可能性があります。例えば、PHPなどのスクリプト言語がアップロードでき、外部からスクリプトを実行されてしまうと、他サーバーへの攻撃をしたり、ファイルの改ざん、情報漏洩に繋がります。
【対策】1つは、利用者にアップロードされたファイルは公開ディレクトリに置かず、アプリケーション経由で閲覧させることで、直接ユーザーがアクセスしてファイルが実行することを防げます。2つ目はファイルの拡張子を制限することです。よくある実装としては、クライアント側でJavaScriptで拡張子チェックがありますが、これだけでは、すり抜ける方法がいくつかありますので、サーバーサイド側で拡張子をチェックする仕組みを実装する必要があります。
仕掛けを含むファイルを利用者にダウンロードさせる攻撃
文字通り、仕掛けをしたファイルのアップロードができてしまう場合に起きうる攻撃です。利用者などがアップロードされたファイルを閲覧したり、ダウンロードして実行してしまったりすることで不正なJavaScriptが実行されてしまったり、マルウェアに感染してしまう恐れがあります。
【対策】JavaScritpが実行できるということは、XSS攻撃が成立します。ファイルのダウンロードによるXSS攻撃の対策としては、以下が挙げられます。特にContent-Typeは正しい設定がされていない場合、古いブラウザなどは異なる解釈をしてしまうことがあります。少し話がずれてしますが、例えば、「Content-Type: text/html; charset=UTF-8」が正しい設定だとした場合、「Content-Type: text/html」とcharsetの文字コードが設定されていないと、古いブラウザではUTF-7と解釈してしまい、XSSの攻撃に繋がるといった話もあります。
1.ファイルContent-Typeを正しく設定する
2.レスポンスヘッダのX-Content-Type-Options: nosniffを指定する
3.ダウンロードを想定したファイルには、レスポンスヘッダとしてContent-Disposition: attachmentを指定する
4.PDFを扱う場合はPDFファイルはブラウザ内で開かず、ダウンロードすることを強制する
5.PDFをobject要素やembed要素では開けない仕組みを実装する
マルウェアなどの実行ファイルがアップロードされないようにするためには、拡張子のチェックをクライアント/サーバーサイドにて実施するのは勿論ですが、マジックナンバーと言われるファイルの種類を識別する数値をチェックすることも有効な方法です。
閲覧権限のないファイルのダウンロード
アップロードしたファイルをダウンロードする際の問題として、限られた権限者のみがダウンロードできるはずにも関わらず、権限のない者がダウンロードできてしまう場合があります。これは、アクセス制御の実装がされていないために、起きてしまいます。
【対策】機能を実行してよいユーザであるのか、リソースに対する操作の権限があるのかをチェックする必要があります。よくあるのは、セッション変数に格納したユーザIDを基準に権限をチェックするといった実装があります。
終わりに
特にどのように実装をするのかといった話には触れていませんが、今回の内容を書く上で、徳丸浩さんの本などを参考にさせていただきました。『体系的に学ぶ安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践』では実装についてのお話もあるため、興味を持った方は是非読んでみてください。また、この話はWebアプリの診断でも役立つとは思うので少しでもお役に立てればなと思います。
参考
『体系的に学ぶ安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践』著 徳丸浩様
『Apache コア機能 LimitRequestBody ディレクティブ』APACHE
・https://httpd.apache.org/docs/2.4/ja/mod/core.html#limitrequestbody
『Webサービスにおけるファイルアップロード機能の仕様パターンとセキュリティ観点』株式会社Flatt Security様
・https://blog.flatt.tech/entry/file_upload_security
『マジックナンバー (フォーマット識別子)』Wikipedia
・https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC_(%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E8%AD%98%E5%88%A5%E5%AD%90)