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

コンポーネント通信の保護

学習の目的

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

  • Lightning コンポーネント間の適切な通信チャネルを挙げる。
  • 自動起動イベントでデータベースを変更しないことで、クロスサイトリクエストフォージェリ (CSRF) を防止する。
  • @AuraEnabled Apex メソッドでデータ漏洩を防止する。

コンポーネントの状態

ここまでセキュアなコンポーネントの作成方法と、これらのコンポーネントがユーザ入力に応じてどのように変更されるかを説明してきました。しかし、まだ取り上げていない重要なトピックが 1 つあります。コンポーネントの状態です。コンポーネントの状態によって、コンポーネントの動作およびコンポーネントが Lightning や他のコンポーネントとやりとりする方法が決まります。 

状態は、ある時点におけるコンポーネントのデータのスナップショットだと考えてください。状態には、次のような情報が含まれます。

  • コンポーネントの Aura 属性の値
  • コンポーネントが表示されたかどうかに関する情報
  • コンポーネントの DOM
  • その他多数

コンポーネントをセキュアにするには、その状態について、誰が変更するのか、記述したコードにどのような影響を与えるかなどを理解する必要があります。

Aura 属性

Aura 属性には、コンポーネントの状態を説明する値が保存されます。アドレス帳の連絡先を表すコンポーネントがある場合、その連絡先の名前とアドレスを属性にすることができます。

属性は、コンポーネントのメソッドで使用できます。たとえば、連絡先の名前とアドレスを使用して手紙を送信できます。コンポーネントの属性は、公開インターフェースの一部として他のコンポーネントが使用できます。 

属性へのアクセス方法は、どこから (コンポーネント内か、別のコンテキストか) アクセスするかによって異なります。コンポーネント内では、簡単にcomponent.get および component.set アクセスを使用するか、コンポーネントの状態を変更します。

たとえば、次のコードはコンポーネントの numberAttribute 属性の値を取得します。

var numAttr = cmp.get("v.numberAttribute");

次のコードはコンポーネントの numberAttribute 属性の値を設定します。

cmp.set("v.numberAttribute",numAttr+1);

データを他のコンポーネントに渡すには、コンポーネントのマークアップを使用します。次のマークアップは、コンポーネントの numberAttribute 属性を値 1 に設定します。

<c:MyComponent numberAttribute="1" />

Aura 属性を使用すると、誰がその値を変更できるかを指定できます。このアクセス制御機能は、公開および使用可能にしてはならない項目が悪意のあるコンポーネントによって改ざんされるのを防止するため、セキュリティの観点から重要です。3 つのアクセスレベルがあります。

  • global: すべてのコンポーネントがこの属性の値にアクセスできます。
  • public: 同じ名前空間内のコンポーネントのみがこの属性の値を設定できます。
  • private: このコンポーネントのみがこの属性の値を設定できます。

アクセスレベルは慎重に割り当てます。データを変更できるコンポーネントが少ないほど、このコンポーネントを分析しやすくなります。 

簡単な銀行アプリケーションで属性とアクセス制御について調べましょう。

  1. Kingdom Management 開発者組織のナビゲーションバーの左側で [アプリケーションランチャー] をクリックし、Secure Lightning アプリケーションを選択します。
    アプリケーションランチャーのスクリーンショット
  2. [Access Control Demo (アクセス制御のデモ)] タブに移動します。
    • Castle Bank へようこそ。ここでは、市民プログラム用の現金を引き出すことができます。銀行の残高を参照し、一度に 5,000 ドゥカートずつ引き出せます。無制限の資金引き出しを許可するオプションもあります
  3. [Spend Unlimited (無制限の資金引き出し)] をクリックします。

これで銀行が指定した制限を超えて資金を引き出すことができます。人生は素晴らしい!

好きなだけ引き出せるのでしょうか? 銀行の所有者はそうは考えていません。あなたは、アプリケーションを修正して市民が無制限に資金を引き出せないようにするよう要請されました。そしてその方がよい気がしたので、引き受けました。

では、コードを見て何が起きているかを確認しましょう。

  1. クイックアクセスメニュー (設定のスクリーンショット) で開発者コンソールを開きます。
  2. [File (ファイル)] | [Open Lightning Resources (Lightning リソースを開く)] を選択します。
  3. LTNG_Access_Control_Demo を選択して、[Open Selected (選択したリソースを開く)] をクリックします。
  4. [Component (コンポーネント)] をクリックしてコンポーネントのマークアップを表示します。

「loanLimit」が global 属性になっています。 

  <aura:attribute name="loanLimit" access="global" type="Boolean" default="false" />

この属性を private に変えれば、この属性は他のコンポーネントからアクセスできなくなり、銀行の顧客があっという間に資金を枯渇させることはなくなります。

  <aura:attribute name="loanLimit" access="private" type="Boolean" default="false" />

変更を保存し、アプリケーションをもう一度開きます。親コンポーネントが「loanLimit」属性を変更できないことを示すエラーが表示される可能性があります。または、コンポーネントが表示されないか、ページが更新され続けることもあります。この修正は簡単です。ラッパーコンポーネント (LTNG_Access_Control_Demo_Wrapper) を開き、<c:LTNG_Access_Control_Demo> タグの属性を削除します。

おめでとうございます。顧客が銀行から無制限に資金を引き出すという問題を修正できました。次は、親コンポーネントから「loanLimit」への参照を削除しましょう。終わったら、好きなだけお金が手に入るチャンスをなぜ放棄したのか考えてみましょう。

コンポーネントの通信

イベントのスコープ設定

Lightning コンポーネントは、3 つのメカニズム (属性、イベント、メソッド) を使用して互いに通信します。属性がほとんどの通信を処理します。コンポーネントは、そこに含まれるコンポーネントの属性値を設定できます。

このパターンの通信は重要であるため、理解しやすいように用語を説明しましょう。1 つのコンポーネント A があり、その中にコンポーネント B、C、D が含まれているとします。B、C、D は A の子で、A は B、C、D の親です。 

この表現を使用すると、属性を使用して親から子へと「コンポーネントチェーンの下位へ」通信するのが簡単であることがわかります。ただし、属性を使用して子からその親へと「コンポーネントチェーンの上位へ」通信することはできません。その方法がないのです。

Lightning では、チェーンの上位への通信のためにイベントという別のメカニズムが用意されています。これらは、以前の単元で処理方法を学習したものと同じイベントです。イベントは作成または「起動」され、そのイベントを受信したコンポーネントが処理方法を決定します。

Lightning には次の 2 種類のイベントがあります。 

  • コンポーネントイベント。イベントを起動したコンポーネントの親にアラート通知します。イベントは処理されるまで親のチェーンを上に移動します。
  • アプリケーションイベント。アプリケーションによって起動され、すべてのコンポーネントに送信されます。そのイベントをリスンしているすべてのコンポーネントが受信します。

可能な場合は常にアプリケーションイベントではなくコンポーネントイベントを使用してください。これは、コンポーネントイベントの方が通信相手のコンポーネントが少ないためです。アプリケーションイベントは大きな影響を与え、他のコンポーネントがどう反応するかを把握するのは困難です。

イベントの起動

コンポーネントはイベントを使用して互いに通信します。たとえば、コンポーネントがイベントを起動していずれかの子のデータを更新する場合があります。フレームワークは、イベントが処理された後、そのイベントを起動したコンポーネントを再表示することで、更新に応答します。 

これは妥当なのですが、問題につながることがあります。カスタム再表示関数内でイベントを起動すると、別の表示ループが発生し、これにより別のイベントが起動され、さらに別のループが発生、と続きます。想像が付くでしょう。このため、可能な場合はレンダラでイベントを起動することは避けてください。どうしても必要な場合は、一時点のイベント数を制限するロジックを追加します。

次の例は、コンポーネントレンダラのコードです。このレンダラはアラートイベントを起動し、notifiedOnRender 属性を設定してそのことを示します。レンダラへの後続のコールでは、この属性をチェックしてそれ以上イベントを起動しません。

例:
componentRenderer.js

rerender: function(cmp,hlp){ 
  this.superRerenderer(); 
  if(cmp.get('v.notifiedOnRender') == false) { 
    alert('hello world'); 
    var alertedEvent = cmp.getEvent('alertedEvent'); 
    alertedEvent.fire(); 
    cmp.set('v.notifiedOnRender',true); // sets a flag to indicate an alert 
  } 
  else { 
    // do nothing, we already sent the alert 
  } 
  }

@AuraEnabled Apex メソッドを使用した CRUD/FLS

最初の単元で、CRUD/FLS アクセス制御について少し説明しましたね。Lightning は CRUD/FLS 制限を適用しません。言い換えると、サーバ側の @AuraEnabled Apex メソッドは、同じ名前空間内のコンポーネントだけでなく、どこのどのコンポーネントからもコールできません。 

サーバ側 @AuraEnabled Apex メソッドはページを読み込まずにコールできるため、いつコンポーネントがサーバからのデータを要求しているかを見分けるのは困難です。そのため、これらのメソッドへのアクセスを制限することが重要です。悪意のあるコンポーネントによる API の不正使用を防ぐには、開発者が CRUD/FLS を適用する必要があります。

次のコードでは、いずれかのクリーチャーの名前を取得します。コメントの後のコード行は、コール側にクリーチャーのデータへのアクセス権限があるかどうかを確認しています。

@AuraEnabled public static List<Creature__c> 
getCreatureName(Id creatureId) { 
  List<Creature__c> creatureDetails = new List<Creature__c>(); // Check to see whether the caller has access to this information. 
  if (!Creature__c.SObjectType.getDescribe().isAccessible()) { 
    return null; 
  } 
  if(creatureId != null || creatureId != 'undefined') { 
    creatureDetails = [select Name from Creature__c where Id =:creatureId]; return creatureDetails; 
  } 
  else { 
    creatureDetails = null; 
    return creatureDetails; 
  } 
}

@AuraEnabled Apex メソッドに CRUD/FLS 権限を適用するのは簡単なうえ、セキュリティが強化されるので行う価値があります。

コードをセキュアにする

ここまで、Lightning コンポーネントフレームワークがどのように Apex および JavaScript と連動し、セキュアでメンテナンスしやすいコンポーネントを記述するのに役立つかを見てきました。適切に行えば、開発した製品で応答性や優れた設計を犠牲にせずに最高レベルのセキュリティを実現でき、お客様を維持できます。

次は、Kingdom Management 開発者組織で学んだことをそれぞれの製品に適用してください。少しの軽微な調整によって得られる違いに驚くことでしょう。

リソース

イベントとの通信

コンポーネントのコンポジション 

コンポーネントのファセット

コンポーネントの初期化時のアクションの呼び出し

Lightning のアクセス制御

メモ

メモ

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

retargeting