データ入力の検証は、常に私にとって非常に内部の苦労でした。
実際のセキュリティフレームワークとコードをレガシーアプリケーションの書き換えプロジェクトに追加する寸前(これまでのところ、カード城の強力なレガシーセキュリティコードとデータの検証はほぼ維持されています)で、どれだけの検証が必要かについてもう一度考えています。どこなど.
プロとして5年間Java=開発者として、データ入力の検証とセキュリティ対策のための個人ルールを作成および改善しました。メソッドを改善したいので、いくつかのアイデアを聞いてください。一般的なルールと手順は問題なく、Java固有のものも同様です。
要約すると、これらは私のガイドライン(3層のWebアプリケーションスタイルで公開)であり、簡単な説明があります。
第1層のクライアント側(ブラウザ):最小限の検証、不変のルールのみ(必須のメールフィールド、1つのアイテムを選択する必要など)。 「6〜20文字」などの追加の検証の使用頻度が少なくなり、変更に対するメンテナンス作業が増える(ビジネスコードが安定したら追加される場合がある)。
第1層のサーバー側(Web通信処理、「コントローラー」):このルールはありませんが、ここではデータ操作とアセンブリ/解析エラーのみを処理する必要があると考えています(誕生日フィールドは有効な日付ではありません)。ここにさらに検証を追加すると、簡単に退屈なプロセスになります。
第2層(ビジネスレイヤー):確かな検証。入力データ形式、範囲、値、メソッドをいつでも呼び出すことができないかどうかの内部状態チェック、ユーザーの役割/権限など。ユーザー入力データをできるだけ少なくし、必要に応じてデータベースから再度取得します。取得したデータベースデータも入力として考慮する場合は、特定のデータがDBで信頼性が低いか、十分に破損していることがわかっている場合にのみ検証します。ここでは、強い型付けがほとんどの仕事をしています。
3層(データレイヤー/ DAL/DAO):ビジネスレイヤーのみがデータにアクセスすることになっているため、ここでは多くの検証が必要であるとは考えていません(「param1がtrueの場合、param2がnullであってはならない」などの場合に検証します);ただし、「ここ」とは、「データベースにアクセスするコード」または「SQL実行メソッド」を意味する場合、データベース自体はまったく逆です。
データベース(データモデル):適切な主キー、外部キー、制約、データタイプ/長さ/サイズを使用して、DB上のデータが不正で破損しないように、十分に考え、強力で自己実施する必要があります。 /精度など-独自のプライベートディスカッションがあるため、トリガーはこれから除外します。
初期のデータ検証は優れたパフォーマンスですが、繰り返しのデータ検証は退屈なプロセスであり、データ検証自体が非常に煩わしいことは認めます。これが、非常に多くのコーダーがスキップするか、途中で行う理由です。また、すべての重複した検証は、常に同期されていない場合、バグの可能性があります。これらは、時間、帯域幅、CPU、ケースバイケースで処理される例外を犠牲にして、ほとんどの検証をビジネスレイヤーまで許可することを私が今日好んでいる主な理由です。
それで、これについてどう思いますか?反対意見?他の手順はありますか?そのようなトピックへの参照?寄付は有効です。
注:Javaのやり方を考えている場合、私たちのアプリはSpring MVCとMyBatis(パフォーマンスと不良データベースモデルがORMソリューションを除外する)をベースにしたSpringです。SpringSecurityを追加する予定です。セキュリティプロバイダーとJSR 303(Hibernate Validator?)
ありがとう!
編集:第3層に関する追加の説明。
検証は一貫している必要があります。したがって、ユーザーが有効であると判断されたWebフォームにデータを入力した場合、クライアント側で実装していない基準があるため、データベースレイヤーによって拒否されるべきではありません。
ユーザーにとって、1ページ分のデータを正しく入力することは、データベースへの大幅なラウンドトリップの後に何か問題があったことを通知するためだけに明らかに煩わしいことはありません。これは、プロセスでクライアント検証を実行した場合に特に当てはまります。
これらを公開しているため、さまざまなレベルで検証を行う必要があり、誰が呼び出しているかを制御できない可能性があります。したがって、検証が1か所で定義され、必要な場所から呼び出されるように(可能な限り)調整する必要があります。これがどのように配置されるかは、言語とフレームワークによって異なります。 Silverlight(たとえば)では、サーバー側で定義でき、適切な属性を使用してクライアント側にコピーされ、そこで使用できます。
リレーショナルシステムでは、これを3層のアプローチと見なします。各レイヤーは、以下のレイヤーによって制約されます。
これに対するideal答えは、1つの場所で3つすべてのレイヤーで制約を定義できるシステムです。これには、SQLのコード生成と、少なくともクライアントとサーバーのデータ駆動型検証が含まれます。
ここに特効薬があるかどうかはわかりませんが、JVMを使用しているので、少なくともクライアントとサーバー間でJavaScript検証コードを共有するためにRhinoを確認することをお勧めします。入力検証を2回記述しないでください。
•第3層(データレイヤー/ DAL/DAO):ビジネスレイヤーのみがデータにアクセスすることになっているため、ここでは多くの検証が必要であるとは考えていません(「param1がtrueの場合、param2がnullであってはならない」などの場合に検証します)。 。
これは間違っています。検証を行うための最も重要な場所は、データベース自体です。ほとんどの場合、データはアプリケーション以上の影響を受けます(影響がないと思われる場合でも)。データベースに適切な制御を行わないことは、せいぜい無責任です。これを行わないという決定により、他の要因よりもデータの整合性が失われます。データの整合性は、データベースを長期間使用するために重要です。優れたデータを含むデータベースレベルで整合性ルールを適用できなかったデータベースを見たことがありません(データを文字どおり数千のデータベースで見たことがあります)。
彼は私よりも良いと言っています: http://softarch.97things.oreilly.com/wiki/index.php/Database_as_a_Fortress
上記のすべては、開発者と保守者が完璧であり、常に完全に実行される完璧なコードを書くことを前提としています。将来のソフトウェアリリースは、あなたが作成した文書化されていないすべての仮定、およびあなたが想像もしなかった方法でシステムにデータを入力したユーザーとハッカーについて知っています。
確かに、検証が多すぎることは悪いことですが、プログラム、ネットワーク、OSが完璧だとすると、ハッカーはファイアウォールを通過できず、DBAは手動でデータベースを「調整」しないため、おそらくもっと悪いことになります。
周囲に境界の円を描き、それが保護している障害モードを特定し、その境界をチェックする適切なレベルの実装を行います。たとえば、データベースで無効なデータが表示されることはありませんが、どうすれば発生し、発生した場合はどうなりますか?あなたのユーザーは誰ですか、失敗のコストはどうですか?
物理的な世界のセキュリティモデルを研究します。セキュリティは、玉ねぎのように層状にすべきです。 1つの厚い壁はセキュリティが不十分と見なされます。データの検証も同じ方法で検討する必要があります。
検証に関する2つの短い一般的な規則:
呼び出し側に渡すことができる方法で無効な入力について通知する何か(エラー、例外)を返すことを保証しないものを呼び出す場合は、それを検証します。
データを使用して何か他のことを行う(決定を行う、計算を行う、保存するなど)場合は、データを検証します。