Universal Signature Code Analyzerのテンプレート言語

プロジェクトPT Application Inspectorでのコードの署名分析のプロセスは、次の段階に分かれています。


  1. 言語依存表現(抽象構文ツリー、AST)への解析。
  2. ASTを言語に依存しない統一された形式に変換します
  3. DSLで説明されているテンプレートへの直接マッピング。

最初の2つの段階については、以前の記事「 ANTLRとRoslynを使用したソース解析の理論と実践 」および「 ツリー構造と統一されたASTの処理 」で説明されています。 この記事は第3段階、つまり、テンプレートを記述するためのさまざまな方法、それらの記述のための特殊言語(DSL)の開発、およびこの言語のテンプレートの例に専念します。



内容




パターンを記述する方法




ハードコーディング


テンプレートは、コード内で直接手動で作成できます。 これには、パーサーの開発は必要ありません。 この方法は、開発者以外には適していませんが、単体テストの作成に使用できます。 また、新しいテンプレートをコンパイルするには、プログラム全体の再コンパイルが必要です。



JSON、XML、または別のマークアップ言語


マッピングされたASTの一部は、JSONまたは他の形式から直接保存およびロードできます。 このアプローチでは、テンプレートを外部からロードできますが、構文は面倒で、ユーザーによる編集には適していません。 ただし、この方法を使用してツリー構造をシリアル化できます。 (.NETでツリー構造をシリアル化する方法と、それらをバイパスする方法については、次の記事で説明します。)



ネイティブテンプレート記述言語、DSL


3番目のアプローチは、簡単に編集できる特別なサブジェクト指向言語を開発することです。これは簡潔ですが、同時に既存および将来のテ​​ンプレートを記述するのに十分な表現力を備えていました。 このアプローチの欠点は、構文とパーサーを開発する必要があることです。



便宜


最初の記事で述べたように、正規表現を使用してすべてのパターンを簡単かつ便利に説明できるわけではありません。 DSLは、正規表現と一般的なプログラミング言語の一般的に使用される構造の混合物です。 さらに、この言語は特定の主題分野を対象としており、標準として使用されることを意図していません。



構文


サイクルの2番目の記事では、命令型プログラミング言語の基本構成はプリミティブ型(リテラル)、式(式)、および命令(文)であると述べました。 DSLを開発するとき、同じことをしました。 式の例:



命令は、式の最後にセミコロンを追加することにより作成されます。


リテラルは、次のようなプリミティブ型です。



これらのリテラルを使用すると、単純な構造を記述できますが、たとえば、数値の範囲、正規表現を記述するために使用することはできません。 このようなより複雑なケースをサポートするために、高度な構造(PatternStatement、PatternExpression、PatternLiteral)が導入されました。 このような構造は、特殊なブラケット<[および]>区切られています。 同様の構文がNemerleから借用されました(そのようなブラケットは準引用に使用されます。つまり、その中のコードをAST Nemerleに変換するために使用されます)。


サポートされている高度な設計の例を以下に示します。 一部の構造では、構文糖も提供され、レコードを削減できます。




サンプルテンプレート



ハードコードされたパスワード(すべての言語)


(#.)?<[(?i)password(?-i)]> = <["\w*"]>




弱い乱数ジェネレーター(C#、Java)


new Random(...)


この脆弱性は、安全でない乱数生成アルゴリズムの使用です。 これまでのところ、そのようなケースは標準のRandomクラスのコンストラクターを検索することで追跡されてきました。



デバッグ情報リーク(PHP)


Configure.<[(?i)^write$]>("debug", <[1..9]>)




安全でないSSL接続(Java)


new AllowAllHostnameVerifier(...) <[||]> SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER


構文構造全体に「論理OR」を使用します。



コメント内のパスワード(すべての言語)


Comment: <[ "(?i)password(?-i)\s*\=" ]>


ソースコードでコメントを検索します。 さらに、C#、Java、PHPでは、ご存じのように、単一行コメントは二重スラッシュ//で始まり、SQLライクな言語では-二重ハイフンで--



SQLインジェクション(C#、Java、PHP)


<["(?i)select\s\w*"]> + <[~"\w*"]>


単純なSQLインジェクション:右側の文字列式ではなく、selectで始まる文字列の連結。



セキュリティ属性のないクッキー(PHP)


session_set_cookie_params(#,#,#)


4番目の引数で設定されているセキュリティフラグなしでCookieを設定します。



空の例外処理ブロック(すべての言語)


try {...} catch { }


空の例外処理ブロック。 C#では、モジュールは次のコードを見つけます。


 try { } catch { } 

T-SQLでは、これは次のとおりです。


 BEGIN TRY SELECT 1/0 AS DivideByZero END TRY BEGIN CATCH END CATCH 

そして、PL / SQLではこれは次のとおりです。


 PROCEDURE empty_default_exception_handler IS BEGIN INSERT INTO table1 VALUES(1, 2, 3, 4); COMMIT; EXCEPTION WHEN OTHERS THEN NULL; END; 


安全でないクッキー(Java)


 Cookie <[@cookie]> = new Cookie(...); ... ~<[@cookie]>.setSecure(true); ... response.addCookie(<[@cookie]>); 


セキュリティフラグを設定せずにCookieを追加します。 このテンプレートは汚染分析でより正確に実装されているという事実にもかかわらず、より原始的なマッチングアルゴリズムを使用して実装することもできました。 添付変数@cookie 、式の否定、および任意の数のステートメントを使用します。



カーソルを閉じる(PL / SQL、T-SQL)


PL / SQL

 <[@cursor]> = DBMS_SQL.OPEN_CURSOR; ... <[~]>DBMS_SQL.CLOSE_CURSOR(<[@cursor]>); 

T-SQL

 declare_cursor(<[@cursor]>); ... <[~]>deallocate(<[@cursor]>); 

開いているカーソルは、権限の低いユーザーによって悪用される可能性があります。


次のコードはT-SQLにあります。


 DECLARE Employee_Cursor CURSOR FOR SELECT EmployeeID, Title FROM AdventureWorks2012.HumanResources.Employee; OPEN Employee_Cursor; FETCH NEXT FROM Employee_Cursor; WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM Employee_Cursor; END; --DEALLOCATE Employee_Cursor; is missing GO 


過度に拡張された特権(PL / SQL、T-SQL)


grant_all(...)


この欠点には、ユーザーに必要以上の特権が付与される可能性があるという事実が伴います。


コードは次のとおりです。
GRANT ALL ON employees TO john_doe;



おわりに


モジュールの動作を示すために、製品PT Application Inspectorでさまざまなプログラミング言語(C#、Java、PHP)のコードで特定のパターンを検索するプロセスを示すビデオを用意しました。 連載の最初の記事で触れた構文エラーの正しい処理についても説明します。




次の記事で教えてくれます:


Source: https://habr.com/ru/post/J300946/


All Articles