web-dev-qa-db-ja.com

ユーザー入力を検証する方法

開発者として、ユーザーが送信したデータを検証できる場所を理解するのに多くの問題を抱えています。簡単な例として、3つのフィールドを含む単純なフォームがあるWebページがあるとします。

Name -> text field
email -> text field
Lunch Choice -> Dropdown field
  values:
    Burger
    Hotdog
    Pizza

ユーザーがフォームを送信すると、名前と注文が保存され、翌日のランチを受け取ることができます。

私が悪意のあるユーザーであり、このサイトにアクセスしてhtmlを編集して、ピザの値が実際にサラダであり、オプションの値が他の値であると言った場合。

フォームが送信されて保存されると、いくつかの不正なデータがデータベースに入ります。

これはどこで止められますか?

私が最初に考えたのは、javascriptの検証を行うこと、サーバーにajax呼び出しを行って、要求された値が有効であることを確認することです。これは素晴らしいアイデアのように聞こえますが、javascriptはサーバーではなくクライアントで実行されるため、攻撃の影響も受けやすくなります。

ユーザーにフォームの送信を許可し、サーバーで送信を処理してそこでチェックを行うと、ユーザーは既にフォームを送信しているため、フォームにリダイレクトする必要がありますか?

私は入力証券について質問する最初の開発者ではないと確信しており、この種の問題を処理するためのベストプラクティスがあるかどうか疑問に思っていました。

前もって感謝します!

6
jacksonecac

基本的な質問です。サーバー側ですべてを検証する必要があります。バックエンドは、検証を行うための適切な場所です。もちろん、JavaScriptの検証は標準ユーザーを適切な値に導くのにも役立ちますが、ハッカー(または上級ユーザー)は簡単に騙すことができます。

バックエンドにデータベースがあり、各ユーザーに割り当てられる食品の種類を知っていると考えられます。受信した値が有効なレコードセットに存在するかどうかを確認する必要があります。問題がなければ、ワークフローを続行できます。そうでない場合は、エラーを表示してプロセスを停止できます。

直面するもう1つの重要な問題は、論理的なバイパスだけではありません。特殊文字に注意し、一重引用符、二重引用符、ダッシュ、セミコロンなどのすべての危険をフィルター処理します。そうしないと、SQLインジェクションやXSS(クロスサイトスクリプティング)攻撃に直面することになります。それもまた別の話ですが、非常に重要であることからも触れておきます。

8
OscarAkaElvis

オスカーはすでにすばらしい回答を投稿しましたが、いくつかの質問への回答として:

私が最初に考えたのは、javascriptの検証を行うこと、サーバーにajax呼び出しをして、要求された値が有効であることを確認することです。これは素晴らしいアイデアのように聞こえますが、javascriptはサーバーではなくクライアント上で実行されるため、攻撃の影響も受けやすくなります。

それは複雑すぎることです。あなたが言ったように、これは攻撃の影響を受けやすく、さらにブラウザでJavaScriptが無効になっていると完全に無効化されます。

ユーザーにフォームの送信を許可し、サーバーで送信を処理し、そこでチェックを行うと、ユーザーはすでにフォームを送信しているため、フォームにリダイレクトする必要がありますか?

うん。

従来、JS検証を使用したい場合は、フロントエンドで修正を提案するためにそれを行います。 「メールアドレスに@はありません。有効なメールアドレスを入力してください。」これにより、上記の往復を節約できます。 JavaScriptはセキュリティを強化するためのものではなく、より良いユーザーエクスペリエンスを強化するためのものです。

その後、有効なメールアドレスを入力してコンテンツを送信すると、メカニズムをバイパスする方法がなくなります。ボールはあなたのコートにあります。サーバーで、オスカーが言及している厄介なことをチェックし、すべての文字列をサニタイズし、何かが間違っていることを検出した場合は、ユーザーを入力ページに戻します(そして、ニースになりたい場合は、フォームフィールドを再入力しますサニタイズされた値を使用)。

したがって、この時点で、JSが無効になっていても、ユーザーは有効なメールアドレスを入力する必要があることを説明するHTMLメッセージを受け取ります。はい、これはエラーメッセージの2つの異なるセットを作成することを意味します-1つはJS用で、もう1つはHTMLで作成します(そのため、私は個人的にJS検証に悩むことはありません)。

提供されたコンテンツの再表示に注意してください。悪意のあるコードを文字列に埋め込んだ場合、最初にサニタイズせずに結果のページに表示すると、異常終了する可能性があります。

4
Ivan

入力検証の実行とは、入力をチェックして、処理できることを確認することを意味します。トリッキーな部分は、それを検証することにより、すでにいくつかのマイナーな処理を行っていることであり、それが隠れた脆弱性を作り出す可能性があります。

最初のステップは、通常、入力の長さを検証することです。ほとんどの入力は一時的に有限のバッファに着陸します。バッファーにコピーする入力の量がバッファーの長さを超えないようにしてください。入力が多すぎてバッファーが足りない場合、これは古典的な「バッファーオーバーフロー」の問題を引き起こす可能性があります。これらを悪用することはハッカーの定番です。

次のステップは、データが予期した形式であることを確認することです。数値を想定している場合は、バイトに数字と、プラス、マイナス、セパレータ、小数点、通貨記号などの許可された数値記号のみが含まれていることを確認してください。これらはロケール固有であることに注意してください。米国では、100万ドル1,000,000.00と入力できますが、ドイツでは100万ユーロを1.000.000,00と入力できます。英数字と数字が必要な場合は、「ホワイトリスト」を使用して、必要な文字のみを受け入れます。悪い文字のブラックリストよりも良い文字のホワイトリストを信頼する方が安全です。ブラックリストにより、現在の構成で安全に保つことができますが、将来誰かがデータベースを別のデータベースに置き換えるとします。予期しない文字の1つがSQLインジェクションを許可している可能性があります。スクリプトとHTMLについても同様です。

これらのチェックを逆にして、入力の長さをチェックする前に特殊文字をテストすると、検証コードがバッファオーバーフローに対して脆弱になる可能性があることに注意してください。最も安全な順序でそれらを実行することが重要です。

したがって、次のステップは入力を適切にエンコードすることです。たとえば、<および>を受け入れて結果をWebページに配置する場合、シンボルがHTMLエンコードされていることを確認して、不注意で、攻撃者が出力ページに<script>attack!</script>を配置できる穴を作成します。

ここでSQLインジェクションから保護することをお勧めします(' OR 1=1;DROP TABLE STUDENTS--などの悪いものを入力する人を保護しますが、それは保護を完全に保証するものではないため、両刃の剣です。これを防ぐには、アポストロフィ文字の受け入れに対する検証チェック。次の防御線はSQLとインターフェースするコード内にある必要があり、そのコードはクエリを安全に実行する必要があります(パラメーター化されたSQLクエリ、ORM、または他の防御戦略を使用)。は、上記のSQLインジェクション攻撃に対して入力をペンテストできますが、1種類のインジェクション攻撃しか知らないため、欠陥は見つかりません。しかし、攻撃者が新しい攻撃の道を見つけ、HTMLエンコーディングを使用して回避しようとしているとします。あなたのチェック、そしてそれはあなたがそのタイプの入力に対してテストおよび/またはサニタイズすることを忘れたことが判明します。SQLコーディングに注意しない限りあなたはまだ脆弱である可能性があります。これはどのようにしてdepを防御するかの小さな例ですこの戦略はあなたを安全に保つのに役立ちます。

3
John Deters

予期しないデータがデータベースに書き込まれないようにするには、フォームが送信された直後に、それを受け取るスクリプト/プロセスによって、サーバー側でデータを検証します。 。

外部ソースから受信したデータはすべて悪意のあるものとして扱う必要があるため、データを受信するすべてのプロセスは、処理する前にデータをサニタイズする必要があります。

クライアント側の検証の目的は、ユーザーフレンドリーなインターフェースを提供することです。サーバー側の検証の目的は、ユーザーの入力が安全であることを確認することです。

OWASPの Input Validation Cheat Sheet および SQL Injection Prevention Cheat Sheet をお勧めします。

1
Krzysztof

すべてのユーザー入力を検証およびサニタイズします

基本的に2つのタイプの検証があり、1つは必須です(サーバー側)1つはUXに望ましい(クライアント側)

クライアント側の検証

データがサーバーに送信される前に、ブラウザーで発生するクライアント側の検証。これは即座に応答するため、サーバー側の検証よりもユーザーフレンドリーです。

その中には、ブラウザベースの検証とHTML5制約API/JSベースのアプローチが組み込まれています。

  • 組み込みのフォーム検証はHTML5フォーム検証機能で行われ、通常はJavaScriptを必要としません。これはパフォーマンスが向上しますが、カスタマイズはできません。

  • JavaScript検証はJavaScriptを使用してコーディングされています。完全にカスタマイズ可能ですが、完全に上書き可能でバイパス可能です

サーバー側の検証

サーバーサイドの検証は、データが送信された後にサーバーで行われる検証です。サーバーサイドのコードを使用して、データがデータベースに入力される前に検証され、間違っている場合はクライアントに応答が送信されます。何が問題かをユーザーに知らせるため。サーバー側の検証は、サーバーへのラウンドトリップを必要とするため、クライアント側の検証ほどユーザーフレンドリーではありませんが、不可欠です。これは、不良データに対するアプリケーションの最後の防衛線です。すべての一般的なサーバー側フレームワークには、データを検証およびサニタイズする(安全にする)機能があります。

上記のテキストのための素晴らしい mozilla プロジェクトの功績があり、確実に読むことを推奨します。

0
Luke