進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

Lightning JavaScript コードの保護

学習の目的

この単元を完了すると、次のことができるようになります。

  • Lightning コンポーネント内の危険な JavaScript と安全な JavaScript を識別する。
  • JavaScript エンコード関数を使用してスクリプトインジェクションに対する保護を行う。

JavaScript に注意すべき理由

多彩な対話型インターフェースを実現できるように、Lightning では、JavaScript を使用してボタンの押下や、ユーザおよび他のコンポーネントからの入力に応答できます。JavaScript は実に強力ですが、前の単元で確認したように、強力なツールはアプリケーションのセキュリティに影響を与えます。つまり、強力なほど、責任も大きくなります。使用方法に注意しないと、JavaScript によってセキュリティホールが生じます。 

クロスサイトスクリプティングについてはすでに説明しました。他にもいくつかの攻撃があり、その影響はそれぞれ異なります。コンポーネントを完全に停止させるものさえあります。 

JavaScript には注意が必要です。たとえば、JavaScript コードがイベントに応答するとき、それはイベントハンドラが登録されたときと同じコンテキストであるとは限りません。他のコンポーネントの DOM または属性がイベントと応答の間に変化する場合もあります。 

JavaScript を使用するときは注意を払い、変化するコンテキストと外部の状況をコードが処理できるようにします。適切に行えば、より安定してセキュアなコンポーネントを作成できます。

非同期 JavaScript

今、非同期 JavaScript は大流行しています。遅延を隠すのにこれ以上の方法はなく、多くのフレームワークがサポートしています。Lightning で非同期 JavaScript を使用できますが、注意が必要です。不適切に使用すると、アプリケーションによってコンポーネントだけでなく、Salesforce ページ全体にクラッシュまたは安定性の問題が発生することがあります。

たとえば、関数 setTimeout および setInterval を使用すると DOM にアクセスできますが、これらの関数を使用して DOM にアクセスするとコンテキストが Lightning フレームワーク外になります。親コンポーネントの状態について保証はありません。関数に親コンポーネントがまったくない場合もあります。状態が変化すると、コールバック関数は所有していないデータに対して操作を実行できます。または、決して出現しないデータを待機します。この状況が発生すると、アプリケーションはエラーメッセージを表示し、Salesforce ページ全体を停止し、コンポーネントは応答を停止します。

関数で Lightning コンポーネントのデータにアクセスする場合、$A.getCallback() クロージャを使用して常にフレームワークにアクセスできます。コンポーネントがまだ存在しているかどうかを確認するには、クロージャ内部で cmp.isValid() を使用します。

次に例を示します。

waitAndChange: function(cmp,evt,hlp){ 
  setTimeout(function(){ 
    $A.getCallback(function(){ // access the framework in a closure 
      if(cmp.isValid()){ // does the component exist in this context? 
        cmp.set("v.resultAttr","new value");
      } 
    }); 
  },2000); 
}

この関数は、その親コンポーネントがまだ存在するかどうかを確認してから、そのデータを変更します。確認しないと、目障りなエラーメッセージによってユーザはページを操作できなくなります。

サードパーティ JavaScript ライブラリ

Lightning プラットフォーム上に製品を構築する場合は、Lightning プラットフォーム上で機能するサードパーティライブラリのみを使用します。Lightning 用に構築されていない JavaScript ライブラリを使用するのは問題を招いているようなもので、コードの信頼性や安定性が損なわれる場合があります。 

Lightning ではまったく機能しないライブラリもあります。CKEditor は、JavaScript で記述された一般的なリッチテキストエディタパッケージです。eval 関数を内部的に使用します。最初の単元で、LockerService が Lightning での eval へのコールを禁止することでいかに安定性とセキュリティを改善するかを説明しました。つまり、CKEditor は Lightning では機能しません。 

サードパーティライブラリを購入する場合は、Lightning、特に LockerService で機能するものを探してください。サポートされるライブラリについての詳細は、開発者ブログ記事を参照してください。

イベント処理

イベント駆動型プログラミングは、非同期プログラミングに似ていますが、Lightning ではイベント応答の処理方法が少し異なります。標準的な Web 開発では、次のような一般的な JavaScript 関数を使用してイベントハンドラを登録します。 

<a href="#" onclick="javascript:myFunction()">Click me</a>

LockerService ではインライン JavaScript が無効化されるため、Lightning コントローラを使用してイベントを処理しなければなりません。具体的には、コントローラ上でメソッドを定義し、そのメソッドを Lightning 式で渡してイベントハンドラを登録します。

<a href="#" onclick="{!c.myFunction}">Click Me</a>

Controller.js

myFunction: function(cmp, evt, hlp){ 
  alert('button clicked');
}

JavaScript を使用したセキュアなデータの処理

アプリケーションを開発するとき、多くの場合はシステムのデータについて想定を行います。たとえば、電話番号は数値で、句読点と名前はアルファベットと想定します。コードでこれらの想定を適用すると、データが正しく使用されていることを確認できます。 

それ以外の場合は、データを使用する前に、特定の方法で処理する必要があります。たとえば、HTML マークアップと CSS スタイル設定はどちらもコードで特殊な処理が必要です。このために、エンコードを使用します。

エンコード

潜在的に危険性のあるコンテキストにデータを置かなくてはならない場合もあります。この場合、データをエンコードして、そのコンテキストで確実に安全なものにします。 

エンコードスキームとエンコードコンテキストについての詳細は、「インジェクションの脆弱性防止」モジュールを参照してください。

例を見てみましょう。

<aura:unescapedHTML value="{! '<b>'+v.userInput+'</b>'}"/>

ここでは、ユーザ入力を未加工の HTML として表示します。このシナリオでは、独自のマークアップをユーザデータに追加したため、未加工の HTML を使用する必要があります。すでに説明したように、このタグによりアプリケーションは攻撃に対して脆弱なままになります。たとえばユーザが「<plaintext>」と入力すると、それ以降のすべての文字列が、既存の HTML コードも含め、テキスト文字として表示されます。

Salesforce では、secure-filters というパッケージを提供しています。これには、データを変換して、コンテキストに関係なく常にデータがテキストとして表示されるようにする一連のフィルタが含まれています。secure-filters は HTML では危険な文字を自動的にエンコードします。このように変換されると、危険なタグ区切り文字「<」と「>」が無害なリテラル「&lt;」と「&gt;」になり、HTML パーサーによってテキストとして表示されます。これは、不適切な HTML コードを無力化するよい方法です。

メモ

メモ

secure-filters パッケージでは入力を検証しません。出力をサニタイズするだけです。

次は、これらのフィルタをプロジェクトに埋め込む方法を学習し、その使用方法を確認しましょう。このステップは、Kingdom Management 開発者組織の「SecureFilters Demo」(SecureFilters デモ) ではすでに完了しています。

  1. secure-filters のエンコード関数の効果を得られる Lightning コンポーネントを特定します。
  2. 開発者組織で、開発者コンソールを開き、securefilters という名前で MIME タイプが text/javascript の静的リソースを新規作成します。
  3. [Submit (送信)] をクリックします。
  4. 新しいブラウザタブで、GitHub の secure-filters ファイル /lib/secure-filters.js を開きます。
  5. 未加工のコードを表示してコピーまたはダウンロードしてから、コードを「securefilters」静的リソースに貼り付けます。
  6. ステップ 1 で特定した Lightning コンポーネントで、このフィルタを使用する任意の場所に次のマークアップを追加します。
<ltng:require scripts="{!$Resource.securefilters}" />

フィルタを使用するには、コンポーネントのコントローラやヘルパーなどの JavaScript コード内で secureFilters.FILTERNAME(UNTRUSTED_DATA) をコールします。たとえば、動的 CSS オブジェクト (unsafeCss) をテキスト (safeCss) として表示する場合、次のように行います。

safeCss = secureFilters.css(unsafeCss); // Use safeCss.

フィルタが実際に動作する様子を見てみましょう。前の単元の神話上のクリーチャーに再びアクセスします。

  1. Kingdom Management 開発者組織のナビゲーションバーの左側で [アプリケーションランチャー] をクリックし、Secure Lightning アプリケーションを選択します。
    アプリケーションランチャーのスクリーンショット
  2. [SecureFilters Demo (SecureFilters デモ)] タブに移動します。
  3. 神話の獣がリストされたページが表示されます。「wyvern」を検索します。
    • 結果は、最初に unescapedHTML の例で表示されたものと同じです。次は、私たちの友人「Balrog」をもう一度検索します。
  4. 「Balrog」を検索します。
    • すると、Balrog がときの声を上げ、Balrog の説明のテキストが画面内を回ります。次は、Balrog の説明をプレーンテキストに変換して、Balrog を無力化します。
  5. エディタでコードを開きます。
    1. クイックアクセスメニュー (設定のスクリーンショット) で開発者コンソールを開きます。
    2. [File (ファイル)] | [Open Lightning Resources (Lightning リソースを開く)] を選択します。
    3. LTNG_SecureFilters_Demo を選択して、[Open Selected (選択したリソースを開く)] をクリックします。 

開発者コンソールのメニューから LTNG_SecureFilters_Demo.cmp をクリックして、このクリーチャーの説明のコンポーネントマークアップを確認します。DemoSecureFilters および secureFilters.html はすでにインポートして、レコード名をセキュア HTML としてエンコードしてあります。説明を HTML としてエンコードすると、Balrog のときの声はテキストを回せなくなり、ページは安全になります。これは、次のように簡単な修正です。

outputT += "Description: " + secureFilters.html(results[i].Description__c) + "<br />";

HTML、CSS、JavaScript を始め、さまざまな種別のデータのセキュアフィルタがあります。詳細は、「リソース」セクションを参照してください。

各コンポーネントのコードをセキュアにする方法について説明したので、次は Lightning でその状態がどのように維持されるかを見てみましょう。Lightning プラットフォーム上でコンポーネントがセキュアにやりとりできる方法についても説明します。

リソース

フレームワークのライフサイクル外のコンポーネントの変更

セキュアフィルタライブラリ

DOM へのクライアント側表示

メモ

メモ

このモジュールは Lightning Experience 向けです。ハンズオン組織を起動するときには、Lightning Experience に切り替えてこの Challenge を実行してください。