例: 合成メソッドの作成

この例では、合成メソッドの作成方法を示します。この合成メソッドでは、まずクラス・フィールドを汚染します。次に、ユーザーのコード内のメソッドに呼び出しを追加し、最後にこのメソッド呼び出しの結果をシンクに渡します。

アプリケーション・シナリオ

この例では、createUser は JAX-RS フレームワークに実装された REST API です。ユーザーは、http://host:port/users/createUser などの URL を使用してこの API を呼び出すことができます。パスが一致すると、フレームワーク・ランタイムは、UserRestService.createUser() に対するこの呼び出しを代行します。さらに、フレームワーク・ランタイムは、createUser() を呼び出す前に、クライアント・データの urlInfo クラス変数を初期化します。最後に、createUser() によって返されたデータが、ランタイムによってクライアントに送り返されます。

合成メソッドでモデル化される対象

合成メソッドを使用して アプリケーション・シナリオ をキャプチャーするための要素には、以下のものがあります。

  • UserRestServiceurlInfo クラス変数の汚染。
  • UserRestService.createUser() への呼び出し。
  • クライアントへの戻りデータ。

以下は、createUser() メソッドのコードです。

import java.io.BufferedWriter;

@Path("users")
public class UserRestService {
  @Context
  UriInfo urlInfo;

  @Path("/createUser")
  public User createUser(){
    MultivaluedMap<String, String> queryParams = 
      urlInfo.getQueryParameters();
    String name = queryParams.getFirst("name");
    User user = new User(name);
    return user;
  }
}

ステップ 1: 空の合成メソッドの作成

22    public class JAXRSHandler extends F4FHandler{
23    @Override
        public void handleApp(F4FApp app, F4FActions actions) {
24    HighLevelSyntheticMethod synthMethod = HighLevelSyntheticMethod.make();           
  • 合成メソッド・オブジェクトは、行 24 で初期化されます。

ステップ 2: クラス・フィールドの汚染のモデル化

以下のコード・スニペットは、特定のクラス・フィールドを汚染する方法を示しています。この例では、@Context アノテーションで注釈が付けられたクラス・フィールドを汚染しようとしています。

27    // create a local variable of the appropriate type 
28    Local userRestServiceClazzInstance = 
        synthMethod.newLocal("com.ibm.appscan.UserRestService");
29
30    // get all the class fields
31    for(IField field: app.getIClass
        ("com.ibm.appscan.UserRestService").getDeclaredInstanceFields()){
32
33      //get all the annotations associated with the field   
34      Collection<Annotation> fieldAnnotations = app.getFieldAnnotations(field);
35
36      //for each annotation of the field check if it is an @Context annotation 
37      for (Annotation annotation : fieldAnnotations) {
38
39        if (annotation.getType().getName().toString().equals
            ("Ljavax/ws/rs/core/Context")) {
40
41          // call the F4F API to assign taint to the field
43          synthMethod.addInstanceVariableWrite(
                 userRestServiceClazzInstance /*Variable representing 
                 class instance*/,
44               field /*field to taint  */, 
                 Taint.taint() /* taint */, 
                 null);
45        }
46      }
47    }

Framework for Frameworks API addInstanceVariableWrite は、4 つの引数を使用します。

  1. 最初の引数は、汚染するフィールドがあるクラス参照です。以下の例では、ローカル変数 userRestServiceClazzInstance がこの引数を参照します。
  2. 2 番目の引数は、汚染するクラス・フィールドです。
  3. 3 番目の引数は、クラス変数フィールドに割り当てられる新しい値です。この例では、Taint.taint() が受け渡されるようにこの変数を汚染しようとしています。
  4. 最後の引数は FilePositionInfo です。この例では null となります。

ステップ 3:createUser() メソッドの呼び出しのモデル化

このステップでは、合成メソッドでの呼び出しをシミュレートします。

50    // call createUser() and store the returned value to a local variable
51    Local returnObj = synthMethod.addCall(
52      "com.ibm.appscan.UserRestService.createUser():com.ibm.appscan.User"
          /* signature of the method to be called */,
          null, /* FilePositionInfo */
53        userRestServiceClazzInstance /* Object on which the method 
            will be called */);

addCall 高位 API は 3 つの引数を使用します。

  • 最初の引数は、呼び出すメソッドのシグニチャーです。このケースでは、User.createUser() を呼び出すので、そのシグニチャーを使用します。
  • 2 番目の引数は FilePositionInfo です。これは、この例では必要がないので null として渡されます。
  • 最後の引数は、createUser() メソッドの呼び出しに必要なパラメーターのリストを表します。

createUser() では引数を使用しないため、この呼び出しに受け渡される引数は、this オブジェクト (タイプ UserLocal 変数 (userRestServiceClazzInstance)) のみです。メソッド createUser() は、新規に作成された User を返します。これは、returnedObj という名前の新しい Local 変数に保管されます (行 51 に表示)。

ステップ 4: クライアントへのデータの戻りのモデル化

この最終ステップでは、クライアントに返されるデータの戻りをモデル化するためのシンクを作成します。

58    // create a PrintWriter object
59    Local printWriterObj = synthMethod.newLocal("java.io.PrintWriter");
60
61    // we want to call the print API on the PrintWriter object. 
      // The print API takes a single argument of Object type returns void
62
63    // we create a param list of size 2. The first item in this list is always the 
      //  'this' object and rest are actual method arguments. 
64    Param[] printWriterObjParam =  new Param[2];
65    printWriterObjParam[0] = printWriterObj;  // The "this" object
      // the value returned by the call to the createUser method
66    printWriterObjParam[1] = returnObj;
67
68    // Now add a call to the print method
69    synthMethod.addCall("java.io.PrintWriter.print(java.lang.Object):void", 
        null, printWriterObjParam);                      
70  }
  • 行 59 では、合成メソッドに PrintWriter クラスの Local オブジェクトを作成します。
  • 行 64 から 66 では、PrintWriter クラス・インスタンス (printWriterObj) に print メソッドを呼び出すために必要なパラメーター・リストを準備しています。
    • 最初のパラメーターは、オブジェクト参照 (printWriterObj) それ自体です。
    • 2 番目のパラメーターは、print メソッドに対する引数です。returnObj ローカル変数に保管されている戻り値を受け渡します。
  • 行 69 では、呼び出しを PrintWriter.print メソッドに追加し、クライアントに返されるデータの戻りをモデル化しています。