
昨年、攻撃者はロシアの銀行に対して1年前よりも30%多くの攻撃を行いました。 彼らは約60億ルーブルを撤回しようとしました。 多くの場合、金融アプリケーションのセキュリティが不十分なため、攻撃が可能になります。
統計によると、リモートバンキングシステムの半分以上(54%)には、MitM攻撃を許可し、インターネットバンキングへのアクセスを傍受するXSS脆弱性が含まれていました。 モバイルバンキングアプリケーションの状況は良くありません。2014年のAndroidの「ウォレット」の70%とiOSの50%には、アカウントにアクセスするのに十分な脆弱性が含まれていました。
脆弱性を早い段階で特定することは、その後に悪用の結果を分解するよりもはるかに安価です。 10月中旬、Positive Technologiesの専門家であるTimur YunusovとVladimir Kochetkovは、銀行業務アプリケーションの安全な開発に関する2日間のマスタークラスを開催しました。 今日は簡単な改めて説明します。
セキュリティ問題とその可能な解決策の議論は、銀行業務アプリケーションの典型的なセキュリティ問題から始めるべきです。
アクセス制御の問題
このような問題は、主に次のアクセス制御メカニズムを実装するときに発生します。
セキュリティ監査は、不十分なアクセス制御、さまざまなバックエンドおよび管理者システムへのアクセス権などのエラーを常に検出します。 これらの脆弱性の中で最も一般的なものは、ほぼすべての銀行および銀行のアプリケーションに見られます。
多くの場合、問題の根本は、暗号プロトコルの誤用と暗号プリミティブの実装(標準の.NET、Javaライブラリなどに組み込まれた暗号化ツール)にあります。 ここで重要なことは、低レベルの暗号プリミティブを使用することは原則として望ましくないことです。これは、設定を間違えて、単一のアプリケーションに暗号を実装するすべての努力を無効にするのは非常に簡単だからです。
このようなエラーの最も顕著な結果の1つは、弱い暗号ブロックモードの使用時に発生するパディングOracle攻撃の脆弱性です。 低レベルのツールを使用する代わりに、KeyCzar、libsodiumなどの高レベルのライブラリを使用するよう常に努力する必要があります。
問題の別の層は、不明瞭なアプローチによるセキュリティに関連しています。 各銀行は暗号化(SSL、TLSなど)を使用し、多くの場合、アプリケーションレベル(L7)でデータを暗号化します。 これは金融機関にセキュリティの幻想を与えます。サーバー側には何も保護するものはないという考え方です。すべてが暗号で「ラップ」されており、攻撃者はサーバーに悪意を持って送信することはできません。
もちろん、これはそうではありません。 暗号化はリバースエンジニアリングの影響を受けやすく、銀行アプリケーションがインストールされているデバイスに攻撃者が物理的にアクセスできる場合、モバイルアプリケーションのチェックはバイパスされます。 つまり、SSLトラフィックに対してMitM攻撃をいつでも実行できます。 さらに、たとえばサイトのフォームなどから、暗号化の「上」でも脆弱性が悪用される場合があります。
ワークフロー管理の問題
最も一般的で危険なワークフロー制御エラー-およびそれらに基づく攻撃の可能性-では、以下を区別できます。
- 不十分なプロセスチェック。
- 競合状態および原子性に対する他の攻撃。
- その他のビジネスロジックの脆弱性
- CSRF攻撃。
このタイプの問題は、銀行アプリケーションで2番目に多い検出です。 それらの発生の可能性を最小限に抑え、ビジネスロジックを保護するには、各ビジネスプロセスを明確に形式化する必要があります。 一般に、ビジネスロジックは、「機能ドメインのロジック」の概念の流行語の同義語です。 サブジェクト領域は、エンティティ、それらの不変式、および相互作用のルールのセットです。
一部の抽象的なサブジェクト領域の脆弱性を回避するには、次のもので十分です。a)エンティティの不変式とそれらの相互作用の規則について、形式化され一貫した説明があれば十分です。 b)エンティティを信頼の境界を越えて渡すときに、すべての不変条件とドメインルールの遵守を厳密に(強制的に、既定値を許容せずに)制御します。
多くの場合、ドメインロジックは、特定のワークフロー(ワークフローまたはステートマシン)の形式で表現できます。その状態は、ドメインのエンティティの許容される不変式のセットであり、状態間の遷移が相互作用する唯一の方法です。 この場合、サブジェクト領域の実装のセキュリティを確保するために、いくつかの特定のルールを定式化できます。
- ワークフロー内の再帰的なパスとループの出現を避けます。
- 異なるストリームで共有されるデータの整合性の違反の可能性を考慮する必要があります。
- ストリームの現在の状態は、信頼境界の前ではなく、その背後ではなく保存される必要があります(「2層」に関連して-クライアントではなくサーバーで)。
- ワークフロー状態間の遷移の開始者の信頼性の厳密な制御を実装する必要があります(非効率的な制御は、たとえばWebの場合、CSRF攻撃に対する脆弱性につながります)。
- データを共有する複数のワークフローが同時に機能できる場合、そのようなすべてのフローからそのようなすべてのデータへのきめ細かいアクセスを提供する必要があります。
データフロー管理の問題
データフロー制御の編成に誤りがあると、次の深刻な問題が発生する可能性があります。
- インジェクション(SQL、XSS、XML、XXE、XPath、XQuery、Linqなど)、
- サーバー側での任意のコードの実装と実行。
3番目に一般的なタイプの銀行業務アプリケーションの問題検出ですが、最も広範なものです。 ここでの主な欠点は、非効率的なデータ前処理です。 銀行のアプリケーションですべての保護メカニズム(ワンタイムパスワードなど)を無効にできるXSSから、金融アプリケーションでの存在により重要な情報への絶対アクセスを可能にするSQLインジェクションに至るまで、多数の攻撃と脆弱性につながります。 -アカウント、パスワード(1回限りを含む)-資金の盗難を実行します。
データの前処理を整理するには、次の3つのアプローチがあります。
- 型付け —文字列データをOOPの用語で特定の型にキャストし、コードでこれらの型を使用します(たとえば、SQLクエリのパラメータ化は、SQLリテラルの型付けの暗黙的な実装です)。
- 衛生 -入力文字列データを出力として使用するのに安全な形式に変換します(例はすべての種類のHtmlEncode、UrlEncode、addslashesなどです)。
- 検証 -任意の基準に対するデータの検証。 2つのタイプの検証が可能です:構文(たとえば、正規表現への準拠のチェック)およびセマンティック(たとえば、特定の範囲内の数値のチェック)。
これらのアプローチの優先順位は、まさにこれです。 つまり、類型化が不可能な場合は衛生を考慮すべきであり、衛生が不可能な場合は検証を導入する必要があります。 これは、コードのセマンティクスの変更からの距離を最大化するために必要です。 さらに、可能な場合は常にルールを遵守する必要があります:「入力でのタイピング/検証(コード実行フローの開始にできるだけ近い)、衛生-出力に(データが出力されるコード内の場所にできるだけ近い)」
上記のアプローチの適用例をいくつか考えてみましょう。
タイピング
次のコードがあるとします:
var parm = Request.Params["parm1"]; if (Request.Params["cond1"] == "true") { return; } if (Request.Params["cond2"] == "true") { parm = Request.Params["parm2"]; } else { parm = "<div>Harmless value</div>"; } Response.Write("<a href=\"" + parm + "\">");
ここでは、危険な値が
parm
に書き込まれます。これは、XSSクラスの攻撃に対する脆弱性につながりますが、その使用のコンテキストでは入力が許可されます。
var typedParm = new Uri(Request.Params["parm2"]); var parm = Request.Params["parm1"]; if (Request.Params["cond1"] == "true") { return; } if (Request.Params["cond2"] == "true") { parm = typedParm.GetComponents( UriComponents.HttpRequestUrl, UriFormat.UriEscaped); } else { parm = "<div>Harmless value</div>"; } Response.Write("<a href=\"" + parm + "\">");

衛生
次のコードがあります。
var parm = Request.Params["parm1"]; if (Request.Params["cond1"] == "true") { return; } if (Request.Params["cond2"] == "true") { parm = Request.Params["parm2"]; } else { parm = "<div>Harmless value</div>"; } Response.Write("Selected parameter: " + parm);
ここで
parm
が危険な値を書き込むことも簡単にわかります。 この場合、タイピングは不可能ですが、危険な操作のコンテキストでは衛生が可能です。
var parm = Request.Params["parm1"]; if (Request.Params["cond1"] == "true") { return; } if (Request.Params["cond2"] == "true") { parm = HttpUtility.HtmlEncode(Request.Params["parm2"]); } else { parm = "<div>Harmless value</div>"; } Response.Write("Selected parameter: " + parm);

検証
次の例(バッファオーバーフロー攻撃の脆弱性)では、入力とサニタイズは不可能です。つまり、検証を適用する必要があります。
const int BufferSize = 16; public unsafe struct Buffer { public fixed char Items [BufferSize]; } static void Main(string[] args) { var buffer = new Buffer(); var argument = args[0].ToCharArray(); if (argument.Length < BufferSize) { return; } for (var i = 0; i < argument.Length; i++) { unsafe { buffer.Items[i] = argument[i]; } } }
検証されたコードは次のようになります。
const int BufferSize = 16; public unsafe struct Buffer { public fixed char Items [BufferSize]; } static void Main(string[] args) { Func<int, int> __ai_bkfoepld_validator = index => { if (index >= BufferSize) { throw new IndexOutOfRangeException(); } return index; }; var buffer = new Buffer(); var argument = args[0].ToCharArray(); if (argument.Length < BufferSize) { return; } for (var i = 0; i < argument.Length; i++) { unsafe { buffer.Items[__ai_bkfoepld_validator(i)] = argument[i]; } } }

インフラストラクチャの問題とその解決方法
銀行システムに対する攻撃の成功につながる可能性のあるインフラストラクチャの問題がいくつかあります。 それらの中には:
- アプリケーションDoS
- 環境問題
- サードパーティのソフトウェア、モジュール、プラグイン。
攻撃の成功は、より単純な非クローズFTP、またはIBM / Tomcat管理パネルなどの助けを借りても発生します。
そして、開発と展開の段階で銀行業務アプリケーションのセキュリティを高めるためにすべきことは次のとおりです。
- インフラストラクチャの各コンポーネントが侵害されていると見なす必要があります。
- インフラストラクチャ内であっても、TLS(SSLではない)をあらゆる場所に適用する必要があります。
- 各インフラストラクチャコンポーネントは、公式のセキュリティガイド(存在する場合)またはベストプラクティスに従って展開および構成する必要があります。
- セキュリティとコンプライアンスを分析するための特別なツール(たとえば、 MaxPatrol )を使用すると、セキュリティのレベルを大幅に高めることができます。
- インフラストラクチャが必要としない場合でも、すべてのコードに署名する必要があります。
- すべてのプラグインとサードパーティの信頼できないモジュールは、専用のサンドボックスで実行する必要があります。
銀行の適用分野
専門家はまた、RBSシステムのサーバー側に関係のないさまざまな銀行業務アプリケーション、およびそれらの潜在的な問題について聴衆に語りました。
- プラグインとクライアントアプリケーション-もともと銀行業務に関連していなかったさまざまなプラグインとクライアントアプリケーションのセキュリティエラーは、問題を引き起こす可能性があります。
- モバイルアプリケーションとその一般的なセキュリティの問題-原則として、モバイルアプリケーションはデスクトップのアプリケーションよりも保護されにくい。 一般的に、サーバー側はどのような種類のアプリケーションでも同じように統一する必要がありますが、そうではないことがよくあります。
- オペレータステーションとアプリケーション-多くの場合、ハッカーは内部ネットワークに侵入するために複雑なセキュリティシステムに侵入する必要さえありません。これらのシステムのオペレータである企業の従業員を欺くだけで十分です。
- クライアント攻撃の開発-クライアント自身に対する標的型攻撃の助けを借りて、銀行の顧客からお金を盗むことが可能です。
おわりに
銀行アプリケーションがサイバー犯罪者の関心をますます高めており、セキュリティの確保に多くの困難があるという事実にもかかわらず、問題は多くの場合、ソフトウェア製品の開発段階でも防止できます。
そして、安全なソフトウェアを開発するためのベストプラクティスに従うだけで、不必要な努力をせずにこれを行うことができます。