ラボ演習 csp1

これはセキュアなソフトウェア開発に関するラボ演習です。 ラボの詳細については、概要をご覧ください。

タスク

下記のサーバーサイドのJavaScriptのWebアプリケーションに、コンテンツセキュリティポリシー(CSP)に関する設定を加えて、セキュリティを強化するヘッダが出力されるようにコードを変更してください。

背景

この演習では、サーバーサイドのWebアプリケーションに対して、セキュリティヘッダを追加します。 このサーバーサイドプログラムは、Expressフレームワーク(バージョン4)を使用してJavaScriptで書かれています。 ここでは、Expressアプリケーションにハードニングヘッダを追加するhelmetライブラリを使います。

タスクの詳細

まず最初にhelmetライブラリをロードしなければなりません。 JavaScriptではいくつもの方法があります。 今回は、requireステートメントを用いて、ライブラリをロードします。 下記のコードで、Expressをrequireしている行を参考にして、それと同じようにhelmetをrequireする行を作成してください。

次にhelmetを使ってハードニングするヘッダを挿入するコードを書く必要があります。 Expessでは、app.use(...)を呼び出すことによって、全てのリクエストに対して何かを行わせることができます。 下記のように、helmetの単純な呼び出しによって、多くのハードニングヘッダをセットアップすることも可能です。

app.use(helmet());

しかし、一般的には、アプリケーションに合わせた特別な設定を行う必要があります。 helmet()には、設定を表すオブジェクトをオプショナルな引数として与えることができます。 JavaScriptにおいて、オブジェクトは{ ... }という形で表現し、 中にキーと値のペアをコンマで区切って与えます。 キーと値のペアは、フィールドの名前、コロン(:)、その値という形になります。

今回は、コンテンツセキュリティポリシー(CSP)の設定を変更します。 これは、contentSecurityPolicyという名前のフィールドに値を設定することで指定できます。 その値はさらに別のオブジェクトとなっています。 まとめると、下記のような形になるでしょう。

app.use(helmet({
  contentSecurityPolicy: {
  }
}));

contentSecurityPolicyに対する値のオブジェクトも、directivesのようないろいろなフィールドを持つことができます。 このdirectives(ディレクティブ)フィールドは、さらにJavaScriptオブジェクトを値として持ちます。

directivesフィールドの値となるオブジェクトは、一つ以上のキーをとります。 今回は、次の二つのキーを設定します。

JavaScriptの文法のクセとして、上記のようなハイフン("-")を含むキーを設定する場合には、ダブルクォーテーションで囲んで文字列として書く必要があります。

"script-src"に対しては、今回は["'self'", "https://example.com"]という配列を設定します。 これは、JavaScriptがこのサーバーもしくはhttps://example.comというWebサイトからのみ実行可能で、それ以外からは実行できない、ということを意味します。 'self'は、これ自体がシングルクォーテーションで囲まれていることに注意してください。 なお、インラインのJavaScriptの利用を許可する"unsafe-inline"を加えることもできます。 しかし、今回の例では追加しません。というのは、"unsafe-inline"を加えないほうがはるかに安全であるからです。 CSPの"script-src"に値が設定されていて"unsafe-inline"が含まれていない場合には、HTMLのどこかに埋め込まれたJavaScriptは実行されないということになります。 これは、セキュリティとして大変すばらしいことです。攻撃者はサーバーに細工をして、生成されるHTMLに何かを紛れ込ませるということを良く行いますが、この設定であれば、それがスクリプトなら実行されることがないということになります。

"style-src"については、["'self'"]を設定します。これは、スタイルシートがこのサイトからのみロードできる(それ以外からはロードされない)ということを表します。 こちらも、"unsafe-include"を加えませんでした。これによって、HTMLに埋め込まれたCSSは無視されることになります。 これはセキュリティとして良いことで、攻撃者がサーバーに細工をしてCSSコマンドを埋め込んだとしても、それらのコマンドは無視されることになります。

必要に応じて、「ヒント」ボタンと「諦める」ボタンを使用してください。

演習()

const express = require("express");


const app = express();

// Helmetを使って、ハードニングヘッダを挿入する


app.get("/", (req, res) => {
  res.send("Hello world!");
});

app.listen(3000);


このラボは、Linux FoundationのDavid A. Wheelerによって開発されました。