常識?非常識?プログラムは1文字でも間違えると正しく動作しない

(Last Updated On: 2021年6月10日)

プログラムのコードを書く場合1文字でも間違えると致命的な問題になる事がよくあります。=< であるべき所を < で条件分岐すると困った事になります。何を当たり前の事を言っているのだ?と思うでしょう。プログラマには常識です。プログラマーは1文字も間違いがないコードを書くために懸命にコードを書いています。

しかし、プログラムでデータを処理する場合1文字でも正しく取り扱うことができないモノが含まれると正しく動作できない、これは常識でしょうか?それとも非常識でしょうか?プログラマは自分が書いたコードに正しく処理可能なデータであることを保証するコードに(データを検証するコードを記述)しているでしょうか?入力データの検証はアプリケーションでは必須ですが検証できているでしょうか?

データもコードも1文字でも間違っていると正しく動作しない

当然ですが数値に数字以外の文字が含まれると整数として正しく処理できないです。

文字データも1文字でも不正なデータが入っているとデータとして正しく処理できないです。正しく処理できないだけでなく「出力のフェイルセーフ対策」がない場合、インジェクション攻撃で不正な操作さえ可能になります。代表的な例を紹介します。

  • ヌル文字インジェクション – ヌル文字がC言語の文字列終端文字として意味がある文字であることを利用したインジェクション攻撃。不正なパスへのアクセス、セキュリティチェック機能のバイパス、などに利用される。
  • 改行文字インジェクション − HTTPやSMTPなどのヘッダー部分と文字列部分が改行でフォーマットされているデータ形式へのインジェクション攻撃。不正なJavaScriptの実行から、HTTPキャシュ汚染、スパムメールの送信などに利用される。
  • 壊れた文字エンコーディング攻撃 – 壊れた文字エンコーディングへの対応はライブラリなどによって異なる。不正だと思われる部分を削除するサニタイズ処理を行うモノもあれば、不正だと思われる部分も特定の文字で置き換えるモノ、不正な文字エンコーディングでデータが全く無かったとして扱うモノ、不正な文字エンコーディングで致命的エラーを発生させるモノ、不正な文字エンコーディングでも何ごとも無かったようにそのまま処理してしまうモノ、と様々です。この処理の違いを利用したコードインジェクション攻撃やサービス不能攻撃(DoS攻撃)が可能になります。
  • その他もろもろのインジェクション攻撃 – 攻撃者は開発者の「ついうっかり無害化せずに出力しまった」を狙ってきます。英数字のシリアルナンバーにJavaScriptやSQLのコードを送りつけます。JavaScriptやSQLコードは明らかに英数字のシリアルナンバーとして不正な文字ですが、無視すると攻撃を許す事になります。

文字データも1文字でも不正なデータが入っているとデータとして正しく処理できないだけでなく、インジェクション攻撃を許してしまう事例は多数あります。

インジェクション攻撃ができない様にフェイルセーフ対策(HTMLテンプレートシステムエスケープ処理やSQLのプリペアード文など)が働いても問題です。出鱈目な入力データが出力されるのはまだ良い方ですが、出鱈目な入力データが保存されてしまうのは大きな問題になります。

このため、CWE/SANS TOP 25:2011 (=MITRE)では

Improper input validation is the number one killer of healthy software, so you’re just asking for trouble if you don’t ensure that your input conforms to expectations.

訳:不適切な入力バリデーションは安全なソフトウェアの1番の殺し屋であり、もし開発者が入力が期待に沿う入力であるか確認していないなら開発者が問題を起こしてくれと頼んでいる事になる。

https://cwe.mitre.org/top25/archive/2011/2011_mitigations.html#Mit-M1

CERT Top 10 Secure Coding Practicesでは

1. Validate input. Validate input from all untrusted data sources. Proper input validation can eliminate the vast majority of software vulnerabilities. Be suspicious of most external data sources, including command line arguments, network interfaces, environmental variables, and user controlled files.

訳: 1. 入力を検証する。信頼できないすべてのデータソースからの入力を検証する。入力を適切に検証することで、ソフトウェアの脆弱性の大部分を取り除くことができます。コマンドライン引数、ネットワーク・インターフェース、環境変数、ユーザーが管理するファイルなど、ほとんどの外部データ・ソースを疑ってください。

https://wiki.sei.cmu.edu/confluence/display/seccode/Top+10+Secure+Coding+Practices

と解説しています。1 IPAのセキュリティガイドラインの多くがセキュアコーディングの基本を無視した問題があるガイドラインですが、現在のIPAのセキュアプログラミング講座はCERT Top 10 Secure Coding Praticesを原則として定義している。

整数が整数であることを検証すればSQLインジェクション、JavaScriptインジェクション、LDAPインジェクション、正規表現インジェクション、改行インジェクション、ヌル文字インジェクション、XPathインジェクション、CSSインジェクション、JSONPathインジェクション、PATHインジェクション、とあらゆるインジェクション攻撃を排除・緩和できます。

不適切な入力バリデーションだと、手遅れな時点でエラーになったり、出鱈目なデータが表示・保存されり、最悪不正な操作まで許す原因になります。問題となるデータは出来る限り早い段階で取り除く(処理を拒否する、処理しない)のがプログラミングとソフトウェアセキュリティ、コンピューターサイエンス、システムエンジニアリングの原則中の原則です。

一文字でも間違った(≒不正な)データが出力されたり、保存されたりするアプリケーションは正しく動作しているとは言えません。入力バリデーションの不備があり、不正なデータを出力しているが正しい動作である、といった状態は論理的に起こりえないです。(≒フェイルセーフ対策が機能している状態、例えばSQLのプリペアードクエリで出鱈目なデータが渡されSQLエラーになった状態、は正しい処理とは言えない。そもそも出鱈目なデータが渡されるコードであることが間違い)

ライブラリやフレームワークの責任”ではない”

入力バリデーションはライブラリやフレームワークの責任だと勘違いしている開発者も居ます。しかし、ライブラリやフレームワークは「全ての外部からの入力データを適切にバリデーションする責任」を持っていませんし、実際に”アプリケーション向けに適切なバリデーション”を提供している汎用ライブラリやフレームワークは皆無です。

「全ての外部からの入力データを適切にバリデーションする責任」には「適切な入力を定義するアプリケーションの責任」です。汎用ライブラリや汎用フレームワークではクエリ文字列やPOST、COOKIEやHTTPヘッダーのパラメーター数や長さ、範囲、形式を適切にバリデーション(=厳格にバリデーション)できる仕様を定義できるのはアプリケーションです。ライブラリやフレームワークには定義できません。2 汎用ライブラリや汎用フレームワークは入力データバリデーションの補助はできても特定のアプリケーション向けに完全な入力データバリデーションを提供できない。一般に汎用であるためアプリケーション仕様より遥かに幅広いデータ、不正なデータを含めたデータ、を受け入れる仕様になっている。ライブラリは妥当なデータのみを渡すことを呼び出し側(≒アプリ開発者)の責任(仕様)にもできる。

入力バリデーションが甘いアプリケーションでWebセキュリティ業界が儲かる

入力データバリデーションが甘いアプリケーションだとセキュリティ業者は簡単に儲かります。

開発者が問題を起こしてくれと頼んでいる

CWE/SANS TOP 25:2011

入力を適切に検証することで、ソフトウェアの脆弱性の大部分を取り除くことができます

CERT Top 10 Secure Coding Practices

MITREがいう所の問題を起こしてくれと頼むコード、CERTがいう所の早期にソフトウェアの脆弱性の大部分を取り除くコードがないアプリケーションなら、非常に脆弱なデータバリデーションの仕組みであるWebアプリケーションファイアーウォールを売るのは容易です。

Webアプリ攻撃用のツールを使った、アプリケーションとその奥深くのフレームワークやライブラリの「フェイルセーフ対策の不備」を見つけるのも容易になります。

非開発者の方でも「データに1文字でもおかしなモノがあれば正しく動作しない事があるのは常識でしょ?プログラムってそういうモノでは?」と思うかも知れませんが、残念ながらソフトウェア開発の慣習と誤ったセキュリティ概念の固定化によりWebセキュリティ業界が儲って当然と言えるようなソフトウェア開発が一般的なのが現状です。

その一翼を担っているのが日本の情報セキュリティ推進する立場にはあるIPAだったりするので、日本での問題は根深いです。(少なくとも海外で公的機関が出鱈目なセキュリティ概念・ガイドラインを公開している例は知らないです)

CWE-20(やコンピューターサイエンス、システムエンジニアリング)の「入力バリデーション」は「データがアプリケーションが期待する形式と一致しているかチェックする」ことを意味します。エスケープしたりフィルタリングしたりする意味はありません。期待する形式(=アプリ仕様)でアプリケーションで正しく処理できる形式であることもチェックするので脆弱性を隠すという意味もありません。このような基礎的定義から勘違いしていると安全なソフトウェア作りから遠のくばかりです。訴訟になった場合などでは不利にしかなりません。

脆弱性を隠す、という意味では出力のフェイルセーフ対策(無条件のHTMLエスケープなどの出力の無害化など)が脆弱性を隠す対策です。出鱈目なデータ(≒攻撃用のデータ)でも可能な限り無害になるような形でデータを出力する、これはどう見ても脆弱性を隠す対策、誤魔化す対策です。

参考:

まとめ

コードに1バイトも間違いが無いよう注意する事と同じく、データにも1バイトも間違い無いように注意しないと正しく動作するアプリケーションは作れない。

ライブラリやフレームワークは「汎用」であるため、「アプリケーション用」のデータの妥当性検証の責任は持っていないし、必要であれば妥当性検証の責任を丸ごと放棄しても構わない。データの妥当性検証の実施責任はライブラリやフレームワークを利用したアプリケーションの責任だからです。3例: HTMLテンプレートシステムが ”年齢”の出力に”<script>XSS</script>”と表示してもHTMLテンプレートシステムには何の問題・責任もない。整数に123/n456のデータは何処からどう見ても不正で整数として処理しようすること自体が間違い。

コードに1バイトの間違いがないようにする事とデータに1バイトの間違いもないようにする事は等しく重要で、正しく(=安全に)動作するプログラムに欠かせません。このため、コンピューターサイエンティストが推奨するトップ10の安全なコーディング原則の1番目が入力バリデーションである。逆に一般的には半分以上がフェイルセーフ対策となる出力の無害化は7番目(CERT版。IPAは開発者が重要性を誤りかねない2番目に変更)であり重要度が低い。

当たり前過ぎて原則だと言われませんが、正しく処理できない入力データはできる限り早く拒否する、これはプログラミングの基本原則です。エラー/間違いを起こす入力データを放置してフェイルセーフ対策(=出力の無害化対策)で問題を誤魔化す/隠蔽するのは悪手である。4 出力のセキュリティ対策(≒フェイルセーフ対策)に任せるのが根本的な対策である、とするセキュリティ専門家も居ますがこれは完全な出鱈目。フェイルセーフ対策はあくまでフェイルセーフ(=本来別の場所で対処されるべき問題)です。問題はできる限り早い段階で排除するのはプログラミングの原則中の原則です。

参考: 具体的に何をすれば良いのか?はCWE/SANS TOP 25:2011で解説されています。

Webフォームのパラメーターだけバリデーションしても”標準入力バリデーション”にはなりません。HTTPヘッダー(もちろんクッキーも)、POST、GET、余計な入力も含めて全てバリデーションして標準入力バリデーションになります。OWASP TOP 10:2017 A10では更にこの入力バリデーションを行った上で、記録と対応を実施しないと脆弱なWebアプリケーションであるとしています。

参考:

  • 1
    IPAのセキュリティガイドラインの多くがセキュアコーディングの基本を無視した問題があるガイドラインですが、現在のIPAのセキュアプログラミング講座はCERT Top 10 Secure Coding Praticesを原則として定義している。
  • 2
    汎用ライブラリや汎用フレームワークは入力データバリデーションの補助はできても特定のアプリケーション向けに完全な入力データバリデーションを提供できない。一般に汎用であるためアプリケーション仕様より遥かに幅広いデータ、不正なデータを含めたデータ、を受け入れる仕様になっている。ライブラリは妥当なデータのみを渡すことを呼び出し側(≒アプリ開発者)の責任(仕様)にもできる。
  • 3
    例: HTMLテンプレートシステムが ”年齢”の出力に”<script>XSS</script>”と表示してもHTMLテンプレートシステムには何の問題・責任もない。整数に123/n456のデータは何処からどう見ても不正で整数として処理しようすること自体が間違い。
  • 4
    出力のセキュリティ対策(≒フェイルセーフ対策)に任せるのが根本的な対策である、とするセキュリティ専門家も居ますがこれは完全な出鱈目。フェイルセーフ対策はあくまでフェイルセーフ(=本来別の場所で対処されるべき問題)です。問題はできる限り早い段階で排除するのはプログラミングの原則中の原則です。

投稿者: yohgaki