プロジェクトPT Application Inspectorでのコードの署名分析のプロセスは、次の段階に分かれています。
- 言語依存表現(抽象構文ツリー、AST)への解析。
- ASTを言語に依存しない統一された形式に変換します
- DSLで説明されているテンプレートへの直接マッピング。
最初の2つの段階については、以前の記事「 ANTLRとRoslynを使用したソース解析の理論と実践 」および「 ツリー構造と統一されたASTの処理 」で説明されています。 この記事は第3段階、つまり、テンプレートを記述するためのさまざまな方法、それらの記述のための特殊言語(DSL)の開発、およびこの言語のテンプレートの例に専念します。
内容
パターンを記述する方法
- コードで定義されたテンプレート(ハードコード);
- JSON、XML、または別のマークアップ言語。
- DSL、サブジェクト指向言語。
ハードコーディング
テンプレートは、コード内で直接手動で作成できます。 これには、パーサーの開発は必要ありません。 この方法は、開発者以外には適していませんが、単体テストの作成に使用できます。 また、新しいテンプレートをコンパイルするには、プログラム全体の再コンパイルが必要です。
JSON、XML、または別のマークアップ言語
マッピングされたASTの一部は、JSONまたは他の形式から直接保存およびロードできます。 このアプローチでは、テンプレートを外部からロードできますが、構文は面倒で、ユーザーによる編集には適していません。 ただし、この方法を使用してツリー構造をシリアル化できます。 (.NETでツリー構造をシリアル化する方法と、それらをバイパスする方法については、次の記事で説明します。)
ネイティブテンプレート記述言語、DSL
3番目のアプローチは、簡単に編集できる特別なサブジェクト指向言語を開発することです。これは簡潔ですが、同時に既存および将来のテンプレートを記述するのに十分な表現力を備えていました。 このアプローチの欠点は、構文とパーサーを開発する必要があることです。
便宜
最初の記事で述べたように、正規表現を使用してすべてのパターンを簡単かつ便利に説明できるわけではありません。 DSLは、正規表現と一般的なプログラミング言語の一般的に使用される構造の混合物です。 さらに、この言語は特定の主題分野を対象としており、標準として使用されることを意図していません。
構文
サイクルの2番目の記事では、命令型プログラミング言語の基本構成はプリミティブ型(リテラル)、式(式)、および命令(文)であると述べました。 DSLを開発するとき、同じことをしました。 式の例:
expr(args);
メソッド呼び出し;-
Id expr = expr
; 変数の初期化; -
expr + expr
; 連結 -
new Id(args)
; オブジェクト作成; -
expr[expr]
; インデックスまたはキーによるアクセス。
命令は、式の最後にセミコロンを追加することにより作成されます。
リテラルは、次のようなプリミティブ型です。
- Id; 識別子;
- ひも 二重引用符で区切られた文字列。
- Int; 整数
- ブール; ブール値。
これらのリテラルを使用すると、単純な構造を記述できますが、たとえば、数値の範囲、正規表現を記述するために使用することはできません。 このようなより複雑なケースをサポートするために、高度な構造(PatternStatement、PatternExpression、PatternLiteral)が導入されました。 このような構造は、特殊なブラケット<[
および]>
区切られています。 同様の構文がNemerleから借用されました(そのようなブラケットは準引用に使用されます。つまり、その中のコードをAST Nemerleに変換するために使用されます)。
サポートされている高度な設計の例を以下に示します。 一部の構造では、構文糖も提供され、レコードを削減できます。
-
<[]>
; 拡張式演算子(たとえば、<[md5 | sha1]>または<[0..2048]>); -
#
または<[expr]> `; 任意の式; -
...
または<[args]>
; 任意の数の引数。 -
(expr.)?expr
;expr.expr
または単にexpr
と同等です。 -
<[~]>expr
条件の否定。 -
expr (<[||]> expr)*
-いくつかの条件の結合(OR); -
Comment: "regex"
-コメントで検索します。
サンプルテンプレート
ハードコードされたパスワード(すべての言語)
(#.)?<[(?i)password(?-i)]> = <["\w*"]>
-
#
; 式が欠落している可能性があります。 -
<[(?i)password(?-i)]>
; タイプIdの正規表現は、どのような場合でも記述できます。 -
<["\w*"]>
; タイプStringの正規表現。
弱い乱数ジェネレーター(C#、Java)
new Random(...)
この脆弱性は、安全でない乱数生成アルゴリズムの使用です。 これまでのところ、そのようなケースは標準のRandom
クラスのコンストラクターを検索することで追跡されてきました。
デバッグ情報リーク(PHP)
Configure.<[(?i)^write$]>("debug", <[1..9]>)
-
<[(?i)^write$]>
; タイプIDの正規表現は大文字と小文字を区別せず、正確な出現のみを定義します。 -
("debug", <[1..9]>)
; 関数の引数 -
<[1..9]>
; 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)のコードで特定のパターンを検索するプロセスを示すビデオを用意しました。 連載の最初の記事で触れた構文エラーの正しい処理についても説明します。
次の記事で教えてくれます:
- .NETでのツリー構造の比較、シリアル化、およびトラバース
- CFG、DFGおよび汚染分析。