LoginSignup
4
3

More than 5 years have passed since last update.

昨日はWebシステムの入力について触れましたが、今日は出力部分について触れます。

出力の形態

Webアプリを作るに当たって、外部に出力するものもいろいろとあります。

  • DBへの問い合わせ
  • OSコマンドの呼び出し
  • メール送信
  • 外部APIの呼び出し
  • HTMLなどの生成

システム内部にある間には、データとコマンドの区別は基本的にはっきりしていますが(例外は後述)、これらのように他のシステムへデータを持ち出すと、単なるデータがコマンドに誤認されるというリスクが生じるため、他のシステムに渡す出力についてはきちんと管理する必要があります。

出力形態ごとの分析

SQLの場合

RDBMSはSQLというプログラミング言語で操作しますので、プログラムからSQLを生成する必要が生じてきます。その過程で、うっかりデータを混ぜ込めばSQLインジェクションとなってしまいます。

純粋な値のデータ→バインド機構が使える

元来、プリペアドステートメントは「あらかじめSQL文の枠組みだけ送ってサーバサイドで準備しておくことで、本体のデータ処理を効率化すること」が役割なのですが、副産物として「値は値として送信されるので、値とSQL構文を混同してしまうことがない」というメリットもあって、セキュリティ的な意味合いでも使われています(サーバが対応しないエミュレーションでは、後者の効果のみとなります)。

それ以外→エスケープ、あるいはホワイトリストでの検証

ただし、「SQL文の枠組み」を送るという性質上、あとから供給できるものは値だけで、列名などのキーワードはバインドの対象とできません。また、値の中でも、LIKEで使う検索用の値や正規表現など、値自身が機能性を持つ場合も、そちらのエスケープが必要となります。

  • 列名やASC/DESCなど…テーブル構造は決まっているはずなので、ホワイトリストと照らし合わせて検証
  • LIKEの引数→適切なエスケープ関数を使う

OSコマンドの場合

理想論をいえば、他の手段で可能なことは他の手段でしてしまったほうがいいでしょう。それでも使わざるを得ない場合には、

  • system系のシェルを介する関数ではなく、できるだけexecのような、実行ファイルを直接実行する方法を使う
  • 処理に使うファイルの名前は、可能な限り「英数字+拡張子」ぐらいにして、余計な文字で変な挙動を起こさせないようにする
  • 一時ファイルは競合状態でも介入が不可能な、安全な手法で生成する

などの緩和策を取っておきましょう。

メール送信の場合

メールを送信する場合、ヘッダの途中に改行コードを入れると、そこで別のヘッダだと認識されるメールヘッダ・インジェクションが発生します。

本文はともかく、メールヘッダとして入れる文字列として改行は不適切なので、きちんと弾いておきましょう。

HTML出力する場合

HTMLもタグを出力しないといけませんが、想定外のものをタグとして出力してしまうとXSSを起こします。もちろん「適宜エスケープする」という手段もありますが、確立したHTML手法があるのであれば、それに乗ってしまうのも1つの手法です(Railsでの例)。

なお、HTMLの中にJavaScriptやCSSなど別な言語で解釈されるコードが入る場合、その言語で見て安全性を確保しないといけませんので要注意です。

その他

言語内でも、正規表現などで「文字列で動作をコントロールする」場面があります。問題となった例としてRubyのKernel.#openがありまして、これは開く文字列の先頭が|だと、コマンドを実行してそのプロセスとのパイプを開くという仕様になっています。このような挙動が必要な場合は稀でしょうし、開くものの種類も通常は事前にわかるでしょうから、ファイルならFile.open、URLならOpenURI.open_uri、本当にプロセスとパイプしたい場合はIO.popenなど、機能特化したメソッドを使いましょう(参考Rubocopからの警告)。

4
3
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
4
3