AppScan でカスタム スクリプトを統合して DAST スキャンを強化

AppScan を使用してカスタム・スクリプトを DAST スキャンに統合し、HTTP 要求と応答を動的に操作して、セキュリティー・テストの柔軟性と有効性を強化します。

AppScan でカスタム・スクリプトをアクティブ化

AppScan のカスタム・スクリプトは、デフォルトではアクティブ化されています (「CustomScripts.Enable」の設定が 「True」 に設定されています)。
Note: 一旦アクティブ化されると、これらのスクリプトは、記録やスキャンなどの操作中に、AppScan Standard 内での HTTP 要求と応答ごとに実行されます。

カスタム・スクリプトを非アクティブ化するには:

  1. 「ツール」 > 「オプション」 > 「拡張」タブに移動します。
  2. CustomScripts.Enable 設定を「False」に設定します。

カスタム・スクリプトを実装し、管理して DAST スキャンを強化

次のように、カスタム JavaScript を DAST スキャンに追加します。
  1. 構成設定の「詳細」セクションの「カスタム・スクリプト」を選択します。
  2. 「+ 追加」ボタンをクリックします。
  3. 必要に応じて、事前入力された「名前」フィールドを編集します。
  4. スクリプトに適した「実行コンテキスト」を選択します。:
    1. 要求を送信する前にスクリプトを実行するための「事前要求」
    2. 応答を受信した後にスクリプトを実行するための「事後応答」
    3. 複数の手順やフォームへの入力を伴うタスクの「パラメーター」。このコンテキストを setResultValue メソッドと組み合わせて使用すると、スクリプトが AppScan に結果を返すことができます。
  5. JavaScript フィールド (コードエディター) に JavaScript を入力し、AppScan 環境内で自動補完候補を表示するには Ctrl+Space を使用します。

    AppScan でサポートされている JavaScript バージョンとの構文の正確性および互換性についてスクリプトを検証します。詳細なガイドラインについては、「JavaScript コード」を参照してください。

    Tip: 構文エラーはコード・エディター内で強調表示され、ツールチップで識別できますが、スクリプトの実行を妨げるものではありません。

    コード・エディターのツールチップを示すイメージ

    例 1: ログインの詳細を要求に自動的に追加します (ログイン管理構成を使用しない)。

    // Before each request
    if(request.method == "POST") {
        request.body = JSON.stringify({
            "username": "jsmith",
            "password": "demo1234"
        })
    }

    例 2: 応答からの API キーをグローバル変数に保存します。

    // After each response
    try {
            var result = JSON.parse(response.body)
            log(`parsing: ${JSON.parse(response.body).Authorization}`)
            if(result.Authorization) {
                environment.globalVariables.addOrUpdate("Authorization", result.Authorization)
                log(`key = ${result.Authorization}`)
            }
    }
    catch (error) {
            log(error)
    }

    例 3: 許可 API キーが存在する場合は、許可 API キーをヘッダーに付加します。

    // Before each request
    var authorization = environment.globalVariables.get("Authorization")
        if(authorization) {
            request.headers.set("Authorization", authorization)
            log(`authorization is ${authorization}`)
        }    
    例4: 異なる値で別のヘッダーを追加します。
    //各リクエスト関数の前に 
    function addUniqueHeader(headerName, value) {
        if(!(request.headers[headerName] != null && request.headers[headerName].includes(value))) {
            request.headers.add(headerName, value)
            }
    }
    addUniqueHeader(“headerName”,”Value”) 
  6. 「追加」をクリックしてスクリプトを保存します。スクリプトがリストに追加され、デフォルトで有効になります。
    Note: これらのスクリプトは、DAST スキャン中に HTTP 要求や応答ごとに実行されます。
    この機能を適切に使用して、スキャンの効率および有効性を高めてください。ライブ・デプロイメントの前に、制御された環境でスクリプトをテストして、スクリプトが期待どおりに機能することを確認します。
  7. 「有効」チェックボックスを使用して、カスタム・スクリプトのリストからスクリプトを有効または無効にすることができます。
  8. 「有効」チェックボックスを使用するか、スクリプト・リストでスクリプトを編集、削除、または並べ替えて、スクリプトを管理します。 オプション・メニュー
  9. 「フル・スキャンの開始」をクリックして、スキャンを実行します。
  10. 結果: 有効なスクリプトが、要求または応答ごとに実行されます。「データ」 > 「要求」タブ > 「要求/応答」から、スクリプトの詳細を表示できます。
    Note: カスタム・スクリプトは、テンプレートにエクスポートするときにデフォルトで暗号化されます。暗号化を無効にするには、「一般:」を調整します。スキャン構成で、「機密データを暗号化」設定を「False」に設定します。

AppScan のカスタム・スクリプトの例

AppScan のカスタム・スクリプトの例は、GitHub リポジトリにアップロードされています。

AppScan で効果的な JavaScript コードを記述するためのガイドライン

コンテキスト

要求: 要求データをサーバーに送信する前に変更します。各要求オブジェクトには、ヘッダー、本文、パス、メソッドなどのプロパティが含まれており、これらを操作して DAST スキャンをカスタマイズできます。
  1. ヘッダー: すべての要求ヘッダーを含んでいます。デフォルト・ヘッダー以外の任意のヘッダーを追加、削除または変更できます。
    //存在しない場合は新しいヘッダーを追加し、存在する場合は上書きします 
    request.headers.set(key, value)
    // ヘッダーを追加します 
    request.headers.add(key, value)
    CAUTION: リクエストごとにスクリプトが複数回実行される可能性があるため、新しいヘッダーを追加するには、既存のヘッダーを置き換え、重複を防ぐためにsetmethodを使用することをお勧めします。同じ名前で異なる値を持つ複数のヘッダーが必要な場合にのみ、add メソッドを使用してください。add メソッドは、同じ名前と値を持つヘッダーが既に存在する場合、ヘッダーを追加しません。ヘッダーの重複を避けるように注意してください。これはエラーを引き起こす可能性があります。
    // Remove header
    request.headers.remove(key)
    // Modify header
    request.headers[key]
    // Examples
    request.headers.add("Authorization", "MyCoolApiKey")
    request.headers.set("Authorization", "SecondApiKey")
    request.headers.remove("Authorization")
    request.headers['Authorization'] = "myapikey3"
    デフォルト・ヘッダー (大文字と小文字は区別されません): デフォルト・ヘッダーは読み取り専用であり、変更できません。
    • ホスト: 要求の送信先ホストを識別します。
    • コンテンツ長: 要求のサイズを計算し、この情報をサーバーに送信します。
  2. 本文: 要求の本文に関する情報を含んでいます。本文のタイプは「ストリング」です。
    // Access body
    request.body
    // Example
    request.body = "{ "username":"user" }"
  3. パス: 要求が意図されたエンドポイントに関する情報を保持します。エンドポイント形式では、base-url (例: /api/v1/test) は除外されます。このプロパティーは読み取り専用であり、スクリプトを実行する前に変更しようとした場合でも、最初に設定されたときと同じままです。
    // Access url path
    request.path
    // Example
    if (request.path.startsWith("api/v1/test"))
  4. 照会: 現在の要求の照会ストリングおよびパラメーター (存在する場合) を保持します。このオブジェクトから照会パラメーターを追加または削除できます。各値は、「キー = 値」のように単一オブジェクトとして扱われます。「getQueryString」を使用すると、「&」記号で連結されたすべての項目を持つストリングが提供されます。このストリングは項目のコピーであるため、ストリングを変更すると、照会のコピーのみを変更することになります。
    Note: クエリー・パラメーターが空の場合、AppScan は、クエリー区切り文字 (「?」) を無視します。
    // Retrieve the current query string
    request.query.getQueryString()
    
    // Example
    // Add new value (or update existing one)
    request.query.addOrUpdate("appscan","appscanvalue")
    // Check if value exist
    request.query.contains("appscan") // for key only check
    request.query.contains("appscan=appscanvalue") // for key and value check
    // Remove an item
    request.query.remove("appscan") // for key only check
    request.query.remove("appscan=appscanvalue") // for key and value check
    request.query.clear() // remove all values
  5. メソッド: 要求のメソッド (例: GET/POST/etc)。このプロパティーは読み取り専用であり、スクリプトを実行する前に変更しようとした場合でも、最初に設定されたときと同じままです。
    // Access to the method
    request.method
    // Example
    if (request.method == "GET")
応答: 応答データと、関連する親要求を含んでいるオブジェクト。情報の取得、応答データの変更または保存を行うことができます。各応答は、応答オブジェクトによって表されます。応答オブジェクトは、次のプロパティーを持ちます。
  1. 本文: 応答からの応答本文を保持します。応答はストリング形式であるため、必要に応じて手動で (例: JSON に) 変換する必要があります。このプロパティーは読み取り専用であり、スクリプトを実行する前に変更を試みても変わりません。
    // Access body
    response.body
    // Example
    let json = JSON.parse(config.response)
  2. パス: 応答エンドポイントに関する情報を含んでいます。
    // Access to the relative url
    response.path
    // Example
    if (response.path.startsWith("api/v1/test"))
  3. ステータス: 応答ステータスに関する詳細を格納します。ステータスは、次のプロパティーを持つオブジェクトです。
    // Access status
    response.status.statusCode // A numeric representation of the status
    response.status.statusDescription // The description of the status code
    response.status.statusLine //the whole status line including the http version
    // Example
    if (response.status.statusCode == 200) // check only the number
    if (response.status.statusDescription == "OK") // Check only the description
    if (response.status.statusLine == "HTTP1.1 200 OK") // Full line
  4. ヘッダー: すべての応答ヘッダーを含んでいます。デフォルト・ヘッダー以外の任意のヘッダーを追加、削除または変更できます。
    // Add header
    response.headers.add(key, value)
    // Override header if exist
    response.headers.set(key, value)
    // Remove header
    response.headers.remove(key)
    // Modify header
    response.headers[key]
    // Examples
    response.headers.add("Authorization", "MyCoolApiKey")
    response.headers.set("Authorization", "SecondApiKey")
    response.headers.remove("Authorization")
    response.headers['Authorization'] = "myapikey3"
  5. 親要求: 応答の前に送信された要求を含んでいるオブジェクト。要求データは読み取り専用です。要求は、以前に定義された要求オブジェクトとしてすべてのプロパティーを持ちます。
    // Example
    response.request.path //- access to the path from the request

環境データ

短期データ・オブジェクトは、スキャンの一時停止、停止、または完了、ログイン、あるいは手動テストの実行など、タスクが終了するまで重要な情報を格納します。

  1. グローバル変数: グローバル変数データは、ユーザー固有のデータ・ペアを格納するために設計されたキー - 値データ構造です。キーは一意 (2 つの要素が同じキーを持つことはできませんが、複数の要素が同じ値を共有することはできます) であり、実行中のスクリプト間でデータを共有するのに便利です。

    このデータは、新しいスキャンまたは再スキャンが行われるたびに消去されます。

    // Add data to the globals or update existing one
    environment.globalVariables.addOrUpdate(key, value)
    // Remove key data from the globals
    environment.globalVariables.remove(key)
    // Read data - retrieves the value for the current key (without removing it)
    environment.globalVariables.get(key)
  2. スキャン状況: 現在のスキャンに関する情報を含んでいます。
    // determine if the current phase is explore phase
    environment.status.isInExplore()
    // determine if the current phase is test phase
    environment.status.isInTest()

ロギング

スクリプトのロギング機能を有効にして、デバッグおよび問題の特定に役立てます。コマンド「console.log」は、ここでは機能しません。代わりに、単語「log」を使用し、その後に、引用符で囲んだメッセージを続けます。また、エンジンの動作中に JavaScript の構文または使用方法に関係のないエラーが発生した場合、このエラーは、エンジン・トレース・ログに記録されます。

// Log message to file
log("my cool logging")

// Log message with custom source
log("message", "my-cool-source")

結果

カスタム・スクリプトの実行結果を設定し、「パラメーター」コンテキストと連動します。AppScan は、必要に応じてこの結果を使用します。

// Sets the script execution result
setResultValue("result")

制約

  1. スクリプトでは制限されたメソッドの使用を避け、実行の失敗やエラーを回避してください。
    1. eval
    2. 関数 (コンストラクター)
    3. setTimeout
    4. setInterval

      これらのメソッドを使用すると、スクリプトが失敗し、エラーになります。

  2. スクリプトの実行制限を守り、最適なパフォーマンスを得られるようにして、リソースの過剰使用を回避してください。
    1. 5 秒の実行時間 (最大)
    2. 64 MB のメモリー割り振り

      これらの制限を 1 つでも超えると、スクリプトは失敗します。

エラー処理

制限のある関数をスクリプトが使用しているときにエラーまたは例外が発生した場合、スクリプトは動作を停止します。このエラーが発生すると実行中のスキャンは一時停止します。エラーの詳細内容が「UserScript.log」ファイルに記録され、詳しい内容を確認できます。

スクリプトで構成されたテンプレートのロード

スクリプトを有効にして構成されたテンプレートをロードすることで、スキャンを開始できます。demo.testfire 実行記述ファイル用のスクリプトで事前構成されたサンプル・テンプレートが Program Files (x86)\HCL\AppScan Standard\Templates で入手可能です。

AppScan でサポートされている JavaScript バージョン

現在、ES6 (2015) から ES15 (2024) までの ECMAScript バージョンがサポートされています。ただし次の機能はサポートされません。
  • ES6 (2015)
    • ジェネレータ
    • 末尾呼び出し
  • ES8 (2017)
    • 共有メモリとアトミック機能
  • ES15 (2024)
    • Atomics.waitAsync
    • 正規表現 \v フラグ