JavaScript でセキュアなコーディングをするために気をつけること

著者名: 天野 祐介 (External link) (サイボウズ株式会社)

目次

はじめに

kintone は JavaScript を使って自由にカスタマイズできます。
カスタマイズにより独自のリッチな UI を構築したり、新しい機能を追加したりできますが、セキュアなコーディングをしないと クロスサイトスクリプティング(以下、XSS)などの脆弱性を作り込んでしまう危険性があります。

この記事では、JavaScript でセキュアなコーディングをするための基本的なポイントを解説します。

脆弱性を生む主な原因

脆弱性を作り込む主な原因になるコードは、要素の動的な生成です。
特に、レコード情報などのユーザーが入力した値を使って要素を生成するときに脆弱性が発生しやすくなります。

対策

document.write()element.innerHTML を使って要素を生成するときは、コンテンツとなる文字列を必ず HTML エスケープするようにしましょう。
以下は、HTML エスケープの実装のサンプルです。

1
2
3
4
5
6
7
8
function escapeHtml(str) {
  str = str.replace(/&/g, '&');
  str = str.replace(/</g, '&lt;');
  str = str.replace(/>/g, '&gt;');
  str = str.replace(/"/g, '&quot;');
  str = str.replace(/'/g, '&#39;');
  return str;
}

使用例は以下になります。

1
2
3
4
// 悪い例
element.innerHTML = '<span class="foo">' + value + '</span>';
// 良い例
element.innerHTML = '<span class="foo">' + escapeHtml(value) + '</span>';

適切な HTML エスケープを行というのは大原則ですが、それに加えて気を付けるべき点を以下にまとめます。

気を付けるべき点

信頼できない外部サイトからデータを取得しない

JSONP や kintone.proxy() を利用して外部サイトからデータを取得するときは、データの提供元が信頼できることを確認します。
また、以下のような場合も、必ず提供元を確認します。

  • img タグや script タグの src 属性を設定するとき
  • 外部サイトが提供する JavaScript や CSS を利用するとき

JavaScript コードを動的に生成しない

eval("...")<span onclick="..."> のように、文字列として JavaScript コードを記述するのは避けます。
可読性の著しい低下やスコープの破壊、適切にエスケープできなくなるなどのリスクがあります。

JSON のパースには JSON.parse() を使う

kintone.api() などで取得した JSON オブジェクトのパースには、JSON.parse() を使います。
JSON は JavaScript のオブジェクトとしても評価可能なため eval()new Function() を使うこともできますが、エスケープの不備や XSS の恐れがあるため利用しないようにします。

URL のエンコードには encodeURIComponent() を使う

a タグの href 属性(リンク先)をセットする場合や location.href を書き換える場合は、必ず encodeURIComponent() でエンコードします。

1
2
3
4
// 悪い例
location.href = '/k/1234/show?param=' + param;
// 良い例
location.href = '/k/1234/show?param=' + encodeURIComponent(param);

ユーザーに関係する情報を cookie や localStorage に保存しない

ユーザーの個人情報や入力したデータは、クライアントサイドストレージに保存するのは避けます。
意図せずブラウザー上にデータが残り続け、第三者に漏洩するのを防ぐためです。
たとえば、次のようなデータが該当します。

  • ログイン ID, プロフィール
  • レコード情報
  • アクセス権

サードパーティライブラリは常に最新版を利用する

ライブラリによっては特定のバージョンに脆弱性があり、読み込んでいるだけで攻撃可能になることがあります。
ライブラリのバージョンに起因する脆弱性を防ぐため、常に最新版を利用するようにしましょう。

脆弱性の高いデータソース

基本的にどんな要素を生成するときもエスケープ処理は必須ですが、以下のデータは特に脆弱性の原因になりやすく、注意が必要なものです。

  • レコード情報(ユーザーの入力値)
  • 外部から取得したデータ(第三者からのデータ)
  • URL パラメーター(ユーザーの入力値)

location.hreflocation.hash で取得できる URL 情報から特定のパラメーターを抽出するといった処理はよくあります。
その際、URL はユーザーが任意の値を入力できるため、レコード情報などのユーザー入力値と同じように扱う必要があります。

脆弱性の高い JavaScript のコード例

脆弱性を特に引き起こしやすい JavaScript のコード例を挙げます。
これらを使うときは適切なエスケープが必須になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 要素の生成
document.write('...');
element.innerHTML = '...';

// 属性の設定
element.setAttribute(name, value);
element.someAttribute = '...'; // someAttributeはhref,onclick,style,srcなど

// URL操作
location.href = '...';

また、URL 操作時はエンコードに加えて遷移先が信頼できるサイトだと保証しなければなりません。

その他気を付ける点

同期 XMLHttpRequest はなるべく使わない

同期 XMLHttpRequest はなるべく使わないようにします。
通信中にブラウザーが固まってしまうパフォーマンスの問題や、Firefox では非推奨になっているためです。
詳細は、 同期と非同期のリクエスト (External link) (外部サイト)を確認してください。

サードパーティライブラリ使用時の注意点

jQuery に代表される DOM 操作を行ライブラリは、内部で操作している DOM API がユーザーから見えないため、知らないうちに前述の危険な操作を呼び出していることがあります。
たとえば、jQuery の html() メソッドは内部的には innerHTML と同じなので、渡された文字列をそのまま HTML として展開してしまいます。
そのため、コンテンツ部分は text() を使ってエスケープするなどの対策が必要です。

1
2
3
4
// 悪い例
$(el).html($('<span class="foo">' + value + '</span>'));
// 良い例
$(el).html($('<span class="foo">').text(value));

ライブラリを利用する際も、普段と同じようにエスケープに気を配ることが大事です。

おわりに

JavaScript でセキュアなコーディングをするために気を付けることを解説しました。
安心して利用できる JavaScript カスタマイズを作成する参考になれば幸いです。
こちらと合わせて、 kintone セキュアコーディングガイドライン も確認してください。