EN JP CN

チュートリアル - Java Path チェッカーの作成

チュートリアル - Java Path チェッカーの作成

チュートリアル - Java Path チェッカーの作成

チュートリアル - Java Path チェッカーの作成

前提条件: Ant がインストールされている必要があります。

このチュートリアルでは、JNDI.PRINT という名前のセキュリティ脆弱性 (SV) チェッカーを作成します。作成できる Java Path チェッカーのタイプの詳細については、Java Path チェッカーのタイプを参照してください。Java path チェッカーを作成するプロセスは、SV チェッカー、RLK チェッカー、共通チェッカーのいずれを作成する場合も同じです。

検出したい指摘を含む抜粋は、Sample1.java にあります。

import javax.naming.*;

public class Sample1 {

   public void test(final Context context) throws Exception {
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");
      System.out.println(enumeration );
   }
}

kwcreatechecker を実行する

チェッカーファイルを作成するディレクトリから次のオプションを指定して kwcreatechecker を実行します。

kwcreatechecker --language java --type sv --code JNDI.PRINT
注: --code オプションでは、特殊 (およびマルチバイト) 文字はサポートされていません。

結果

ディレクトリは--code で指定した名前で作成されます。このディレクトリには、チェッカースタブファイルが含まれます。上述の例では、ディレクトリの名前は JNDI.PRINT です。

@Source と@Sink を knowledge base (ナレッジベース) に追加する

エンジンが指摘を検知するためには、少なくとも 1 つの source と1 つの sink を定義する必要があります。指摘が発生するのは、ソースで作成されたデータがシンクで使用されている場合のみです。

kwcreatechecker によって生成された .jkb ファイルには、source、sink、check、および prop の例が含まれます。

  1. JNDI.PRINT\kb\jndi.print.jkb を開きます。
  2. ソースを追加します。上記のサンプルに基づくと、この指摘のソースは Context クラスの list メソッドの呼び出しです。 この呼び出しは、表示するべきではない、危険性のあるデータを返します。
    package javax.naming; 
    
    import java.util.Hashtable; 
    
    public interface Context { 
        @Source("return") public NamingEnumeration list(String name) throws NamingException; 
    }
    
  3. シンクを追加します。この場合、シンクは println メソッドの呼び出しです。
    package java.io;
    
    import java.util.Formatter; 
    import java.util.Locale; 
    
    public class PrintStream {    
        public void println(@Sink Object o); 
    }
    
  4. 保存し、ファイルを閉じます。

チェッカーのタイトルとメッセージを指定する

  1. 好みのエディターで JNDI.PRINT\checkers.xml を開きます。
  2. "Your message goes here" を以下によって置換します。
    JNDI data {0} leak
    
  3. "Your title goes here" を以下によって置換します。
    JNDI information leak
    
  4. ファイルを保存します。

チェッカーのコンテキスト依存ヘルプを作成する

  1. 好みのエディターで JNDI.PRINT\help.xml を開きます。
  2. 必須: 次の指摘の説明を追加します。
    Sensitive JNDI information leak
    
  3. オプション: 必要に応じて、ファイルの残りで以下の情報を指定することができます。
  4. ファイルを保存します。

JNDI.PRINT help.xml

<?xml version="1.0"?>
<help language="java">
    
    <defect id="JNDI.PRINT">        
        <description>            
            Sensitive JNDI information leak            
        </description>
        <risks>            
            Revealing details about an JNDI storage is a security issue because it provides attackers with information they can use to further their attacks.
        </risks>
        <prevention>            
            Filter all the data coming from the JNDI in order to prevent sensitive information leaks.
        </prevention>
        
        <examples>            
            <example line="1">                
                
                
import javax.naming.*;

public class Sample1 {

    public void test(final Context context) throws Exception {
    
        final NamingEnumeration<NameClassPair> enumeration = context.list("*");
        System.out.println(enumeration );
        
    }
    
}

            
            
                <description>                    
                    JNDI.PRINT is reported on line 7.                    
                </description>                
            </example>            
        </examples>        
    </defect>    
</help>

Buildfile:build.xml

チェッカーファイルを JAR ファイルにパックするには、チェッカーディレクトリに移動して Ant を実行します。たとえば、次のようになります。

cd \home\jsmith\testproject\JNDI.PRINT

ant

結果:

Buildfile: build.xml

jar:

[jar] Building jar: \home\jsmith\testproject\JNDI.PRINTJNDI.PRINT.jar

install: BUILD SUCCESSFUL Total time: 7 seconds

チェッカーをテストする

チェッカー JAR を plugins フォルダーに配置する

チェッカーをテストするには、前のステップで作成した JAR ファイルをローカルに展開する必要があります。

次の場所に plugins ディレクトリがない場合は、手動で作成する必要があります。場所は、お使いのオペレーティングシステムによって異なります。

  • Unix: ~<username>/.klocwork/plugins
  • Windows 7 および Vista: C:\users\<username>\.klocwork\plugins
  • Windows XP: C:\Documents and Settings\<username>\.klocwork\plugins

JAR ファイルを plugins フォルダーに配置します。

kwjava を実行する

kwjava を実行して 1 つまたは複数のサンプルファイルに対してチェッカーをテストします。出力サイズを縮小するには、チェッカーのテストに単純なソースファイルを使用することがベストプラクティスです。

kwjava --license-host kw-test --license-port 27000 Sample1.java --xml problem.xml

problem.xml の出力:

<problem>
    <file>Sample1.java</file>
    <method>test</method>
    <line>7</line>
    <column>17</column>
    <message>
        JNDI data Parameter enumeration of call to println(...) is printed out at enumeration
    </message>
    JNDI.PRINT
    
    <params>
        <param>Parameter enumeration of call to println(...)</param>
        <param>Value returned by list(...)</param>
        <param>enumeration</param>
        <param>enumeration</param>
    </params>
    <trace> 
        <traceBlock file="Sample1.java" class="Sample1" method="test" id="1">
            <traceLine line="6" text="Value returned by list(...)"/>
            <traceLine line="7" text="Parameter enumeration of call to println(...)"/>
        </traceBlock> 
    </trace>
</problem>

予想した指摘をチェッカーが検出しない場合は、knowledge base (ナレッジベース) ファイルを再度調べて、問題をトラブルシューティングします。

knowledge base (ナレッジベース) ファイルで問題を特定できない場合は、チェッカーのログを有効にしてチェッカーが解析したコードのほか、適用されたソースとシンクについての情報を取得することができます。オプション: 高度なトラブルシューティングオプション: 高度なトラブルシューティングを参照してください。

オプション: 高度なトラブルシューティング

-l オプションを設定して kwjava を実行します。ログにはチェッカーが解析したコードのほか、適用されたソースとシンクに関する情報が含まれます。この出力を使用して、チェッカーおよび knowledge base (ナレッジベース) をデバッグおよび改善することができます。

kwjava --license-host kw-test --license-port 27000 Sample1.java -xml problem.xml -l <checker_dir>\logger.xml>

フィールド <checker_dir> は、kwcreatechecker によって生成されたチェッカーディレクトリです。

チェッカーのロガーファイルを有効にすると、チェッカーによるデータの収集と追跡の方法を確認できます。

knowledge base (ナレッジベース) に @Prop を追加する

新しい抜粋リファレンスは Sample2.java です。

import javax.naming.*;

public class Sample2 {

   public void test(final Context context) throws Exception {    
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");    
      final Object o = enumeration.next();  
      System.out.println(o); 
   }
}

@Prop で knowledge base (ナレッジベース) を拡張する

上のサンプルでは、汚染データが final NamingEnumeration<NameClassPair> enumeration = context.list("*"); で作成されますが、シンクでは使用されません。シンクで使用されるのは、汚染データの一要素です。汚染データのこの要素は、final Object o = enumeration.next(); で抽出されます。

このような状況をサポートするためには、チェッカー knowledge base (ナレッジベース) を prop エントリで拡張し、列挙が汚染されている場合は次のメソッドが汚染データを返すことを指定する必要があります。

  1. JNDI.PRINT\kb\jndi.print.jkb を開きます。
  2. 次のようにして prop を追加します。
package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
 
   @Prop(in="this", out="return") T next() throws NamingException;
}

knowledge base (ナレッジベース) に @Check を追加する

チェックエントリの作成に必要な情報を取得するには、Sample3.java を使用します。

import javax.naming.*;

public class Sample3 {

   public void test(final Context context) throws Exception {
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");
      final Object o = enumeration.next();
      verify(o);
      System.out.println(o);
   }

   public void verify(final Object o) throws Exception {
      if (o.toString().indexOf("password") >= 0) {
         throw new Exception("Private data is accessed");
      }
   }
}

上の抜粋で、データのチェックには verify メソッドで十分です。

  1. JNDI.PRINT\kb\jndi.print.jkb を開きます。
  2. 次のようにしてチェックを追加します。
public class Sample3 { 
   public void verify(@Check final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
 
   @Prop(in="this", out="return") T next() throws NamingException;
}  

この knowledge-base (ナレッジベース) エントリでは、JNDI.PRINT は Sample3 に対して報告されません。

次へ移動しますチェッカーをテストします。チェッカーを再度テストしたら、check-true を knowledge base (ナレッジベース) に追加します。

knowledge base (ナレッジベース) に @CheckTrue を追加する

チェックの verify メソッドがブール値 true (データは表示可能) および false (表示不可) を返した場合、データは正のブランチで汚染されていません。

public class Sample3 {  
public boolean verify(@CheckTrue final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
  
   @Prop(in="this", out="return") T next() throws NamingException;
}

その場合、次のコードでは指摘は報告されません。

   final NamingEnumeration<NameClassPair> enumeration = context.list("*");   
   final Object o = enumeration.next();  
   if (verify(o)) {     
      System.out.println(o);   
   }

次のコードの場合は、チェックが正しく実行されなかったため、指摘が報告されます。

   final NamingEnumeration<NameClassPair> enumeration = context.list("*");   
   final Object o = enumeration.next();
   if (!verify(o)) {   
      System.out.println(o);   
   }

次へ移動しますチェッカーをテストします。チェッカーを再度テストしたら、check-false を knowledge base (ナレッジベース) に追加します。

knowledge base (ナレッジベース) に @CheckFalse を追加する

verify が、表示可能のデータに対して false を返す場合 (逆チェック)、@CheckFalse 注釈を使用する必要があります。

public class Sample3 { 
public boolean verify(@CheckFalse final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
  
   @Prop(in="this", out="return") T next() throws NamingException;
}

次のステップ:チェッカーをテストします。チェッカーの再テスト後、解析結果に満足できた場合は、チェッカーは展開準備が完了しました。カスタムチェッカーの展開 を参照してください。