mcpField
F
fix-csp-compliance

fix-csp-compliance

github.com/ui5セキュリティ44143 回インストール1 週間前に更新
リポジトリ

fix-csp-compliance について

UI5 開発者向けのスキルです。インライン JavaScript を外部ファイルへ移し、動作を保ったまま `csp-unsafe-inline-script` 警告に対処します。

主な機能

  1. 01インライン JavaScript の外部化
  2. 02スクリプト内容の保持
  3. 03UI5 初期化への対応
  4. 04インラインイベント処理の置換
  5. 05テスト・動的スクリプトへの対応

活用シーン

  1. 01CSP リンター警告への対処
  2. 02UI5 起動コードの HTML 外部化
  3. 03HTML イベント属性の置換
  4. 04インラインテスト起動コードの再構成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ui5/plugins-coding-agents --skill fix-csp-compliance

インストール後、Claude Code で/fix-csp-complianceを入力して読み込まれたか確認します。

詳細

CSP 準拠の修正 - 安全でないインラインスクリプト

重要なルール

  1. インラインスクリプトの内容は絶対に削除しないでください。 必ず内容を外部の .js ファイルに移し、インラインの <script>...</script> を <script src="filename.js"></script> に置き換えてください。簡単な設定オブジェクト、デバッグフラグ、使われていないように見えるコードも、すべて外部ファイルに移す必要があります。削除すると機能の退行につながります。
  2. ファイル名には、内容の目的に合った分かりやすい名前を使用してください(例:設定には appConfig.js、初期化には init.js)。

このスキルは、UI5 リンターが検出するものの、コードを外部ファイルに再構成する必要があるため自動修正できない、コンテンツセキュリティポリシー(CSP)準拠の問題を修正します。

対応するリンタールール

ルール IDメッセージパターン重大度このスキルの対応
csp-unsafe-inline-script安全でないインラインスクリプトの使用警告外部 JS ファイルに移動

使用する場面

次のようなリンター出力が表示された場合に、このスキルを適用してください:

index.html:15:5 warning Use of unsafe inline script  csp-unsafe-inline-script
test.html:20:5 warning Use of unsafe inline script  csp-unsafe-inline-script

背景:CSP が重要な理由

コンテンツセキュリティポリシー(CSP)は、次の攻撃の防止に役立つセキュリティ機能です:

  • クロスサイトスクリプティング(XSS)攻撃
  • データインジェクション攻撃
  • 不正なスクリプト実行

攻撃者が HTML の挿入に成功すると、悪意のある JavaScript も挿入できるため、インラインスクリプトは安全でないと見なされます。CSP に準拠したアプリでは script-src 'self' を使用し、インラインスクリプトをブロックします。

ドキュメント:コンテンツセキュリティポリシー

検出

リンターは、次の条件を満たす <script> タグにフラグを付けます:

  • src 属性がない
  • インラインの JavaScript コンテンツがある

フラグが付く例:

<script>
    console.log("Inline code");  
</script>

<script type="text/javascript">
    doSomething();  
</script>

<script type="module">
    import { foo } from './foo.js';  
</script>

フラグが付かない例:

<script src="app.js"></script>  

<script src="app.js">
    // This content is ignored by browser anyway
</script>

<script type="text/xmldata">
    
    <data>...</data>
</script>

修正方針

すべてのインラインスクリプトに対する修正方法は同じです。外部ファイルに移し、元の場所に <script src="..."> タグを追加します。 インラインスクリプトの内容は保持され、HTML 内ではなく別の .js ファイルに配置されます。インラインスクリプトの内容は絶対に削除せず、必ず外部ファイルに移してください。


1. 基本的なインラインスクリプト → 外部ファイル

問題:HTML 内のインライン JavaScript です。


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>My App</title>
    <script>
        window.myConfig = {
            apiUrl: "/api/v1",
            debug: true
        };
    </script>
    <script
        id="sap-ui-bootstrap"
        src="resources/sap-ui-core.js"
        data-sap-ui-async="true">
    </script>
    <script>
        sap.ui.require(["my/app/init"], function(init) {
            init.start();
        });
    </script>
</head>
<body class="sapUiBody" id="content">
</body>
</html>

修正方針:インラインスクリプトを外部ファイルに移します。


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>My App</title>
    <script src="config.js"></script>
    <script
        id="sap-ui-bootstrap"
        src="resources/sap-ui-core.js"
        data-sap-ui-async="true"
        data-sap-ui-on-init="module:my/app/init">
    </script>
</head>
<body class="sapUiBody" id="content">
</body>
</html>
// config.js
window.myConfig = {
    apiUrl: "/api/v1",
    debug: true
};
// my/app/init.js
sap.ui.define([], function() {
    "use strict";

    return {
        start: function() {
            // Initialization code
        }
    };
});
2. インライン初期化を含む UI5 ブートストラップ → data-sap-ui-on-init

問題:UI5 ブートストラップ後のインラインスクリプトです。


<script
    id="sap-ui-bootstrap"
    src="resources/sap-ui-core.js"
    data-sap-ui-async="true"
    data-sap-ui-resource-roots='{"my.app": "./"}'
    data-sap-ui-compat-version="edge">
</script>
<script>
    sap.ui.getCore().attachInit(function() {
        sap.ui.require([
            "sap/m/Shell",
            "sap/ui/core/ComponentContainer"
        ], function(Shell, ComponentContainer) {
            new Shell({
                app: new ComponentContainer({
                    name: "my.app",
                    async: true
                })
            }).placeAt("content");
        });
    });
</script>

修正方針:data-sap-ui-on-init 属性を使用します。


<script
    id="sap-ui-bootstrap"
    src="resources/sap-ui-core.js"
    data-sap-ui-async="true"
    data-sap-ui-resource-roots='{"my.app": "./"}'
    data-sap-ui-compat-version="edge"
    data-sap-ui-on-init="module:my/app/init">
</script>
// webapp/init.js
sap.ui.define([
    "sap/m/Shell",
    "sap/ui/core/ComponentContainer"
], function(Shell, ComponentContainer) {
    "use strict";

    new Shell({
        app: new ComponentContainer({
            name: "my.app",
            async: true
        })
    }).placeAt("content");
});
3. 設定データ → JSON またはモジュール

問題:インラインの設定オブジェクトです。


<script>
    window.APP_CONFIG = {
        apiEndpoint: "https://api.example.com",
        features: {
            darkMode: true,
            analytics: false
        }
    };
</script>

修正方針 A:実行時に読み込む外部 JSON ファイルを使用します。


<script src="config.js"></script>
// config.js - loads JSON
(function() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "config.json", false);  // Sync for config
    xhr.send();
    window.APP_CONFIG = JSON.parse(xhr.responseText);
})();
// config.json
{
    "apiEndpoint": "https://api.example.com",
    "features": {
        "darkMode": true,
        "analytics": false
    }
}

修正方針 B:設定を含む UI5 モジュールを使用します。

// my/app/config.js
sap.ui.define([], function() {
    "use strict";

    return {
        apiEndpoint: "https://api.example.com",
        features: {
            darkMode: true,
            analytics: false
        }
    };
});

// Usage in other modules
sap.ui.define(["my/app/config"], function(config) {
    console.log(config.apiEndpoint);
});
4. インラインイベントハンドラー → 外部スクリプト

問題:HTML 属性内のインラインイベントハンドラーです。


<button onclick="handleClick()">Click me</button>
<img src="logo.png" onerror="handleError(this)">
<body onload="init()">

修正方針:イベントリスナーを含む外部スクリプトを使用します。


<button id="myButton">Click me</button>
<img id="logo" src="logo.png">
<body>
// app.js
document.addEventListener("DOMContentLoaded", function() {
    document.getElementById("myButton").addEventListener("click", handleClick);
    document.getElementById("logo").addEventListener("error", function() {
        handleError(this);
    });
    init();
});

function handleClick() {
    // Click handler
}

function handleError(element) {
    // Error handler
}

function init() {
    // Initialization
}
5. テスト用 HTML ファイル

問題:インラインスクリプトを含む QUnit テストファイルです。


<!DOCTYPE html>
<html>
<head>
    <script src="resources/sap-ui-core.js"
        data-sap-ui-async="true">
    </script>
    <script>
        sap.ui.getCore().attachInit(function() {
            sap.ui.require(["my/app/test/myTest"]);
        });
    </script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>

修正方針:Test Starter を使用します(prefer-test-starter も修正されます)。


<!DOCTYPE html>
<html>
<head>
    <script
        src="resources/sap/ui/test/starter/runTest.js"
        data-sap-ui-testsuite="test-resources/my/app/test/testsuite.qunit">
    </script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>
6. 動的なスクリプトコンテンツ

問題:スクリプトコンテンツが動的に生成されています。


<script>
    var userId = "<%= user.id %>";  // Server-side template
    var token = "<?php echo $token; ?>";
</script>

修正方針:データ属性または meta タグを使用します。


<meta name="user-id" content="<%= user.id %>">
<meta name="csrf-token" content="<?php echo $token; ?>">
<script src="app.js"></script>
// app.js
var userId = document.querySelector('meta[name="user-id"]').content;
var token = document.querySelector('meta[name="csrf-token"]').content;

実装手順

  1. リンターの出力からすべてのインラインスクリプトを特定します

  2. 各スクリプトを分類します:

    • UI5 の初期化 → data-sap-ui-on-init を使用
    • 設定 → 外部 JS ファイル
    • イベントハンドラー → addEventListener を使用する外部スクリプト
    • テストのボイラープレート → Test Starter を使用
  3. スクリプトの内容を保存する外部ファイルを作成します

  4. 外部ファイルを参照するようにHTML を更新します

  5. 機能が維持されていることを確認するため、アプリケーションをテストします

よくあるパターン

インラインパターンCSP 準拠の解決策
<script>code</script><script src="file.js">
インラインの data-sap-ui-on-initdata-sap-ui-on-init="module:path/to/init"
onclick="fn()"element.addEventListener("click", fn)
onerror="fn()"element.addEventListener("error", fn)
onload="fn()"DOMContentLoaded イベントリスナー
サーバーでレンダリングされた設定<meta> タグ + JS リーダー
QUnit のインラインブートストラップTest Starter の runTest.js

注意事項

  • CSP 準拠はエラーではなく警告です。一部の環境では必要ない場合があるためです
  • data-sap-ui-on-init 属性は、AMD モジュール向けに module:path/to/module 形式を受け付けます
  • サーバーでレンダリングされる動的な値には、<meta> タグまたは data-* 属性を使用してください
  • テストファイルでは、CSP 準拠とベストプラクティスの両方を満たすために Test Starter を使用してください
  • サードパーティライブラリによっては CSP の調整が必要な場合があります。ドキュメントを確認してください
  • CSP の設定によっては、JSONP コールバックに特別な処理が必要となる場合があります

コメント