Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

8 power night2014_nakamura

910 views

Published on

  • Be the first to comment

8 power night2014_nakamura

  1. 1. Visualforceで セキュアコーディング 初級編 2014/11/05 中村
  2. 2. ねらい •Dreamforceセッション 「Secure Coding: Field-level Security, CRUD, and Sharing」 より、 今回は、画面開発に絞って、CRUDとFLSを 遵守する術を再度確認します。 2
  3. 3. 3 #1 SF設定において データアクセスを、どう 権限管理するの~
  4. 4. データに対するセキュリティ設定 4 1.オブジェクトレベルのアクセス権限 2.項目レベルのセキュリティ 3.Force.comでの共有設定 を適切に設定する。
  5. 5. データに対するセキュリティ設定 CRUD 5 1.オブジェクトレベルのアクセス権限 2.項目レベルのセキュリティ 3.Force.comでの共有設定 を適切に設定する。 FLS Sharing
  6. 6. データに対するセキュリティ設定 6 CRUD •Read •Create •Edit •Delete 1.オブジェクトレベルのアクセス権限 プロファイルごとに設定・管理する。
  7. 7. データに対するセキュリティ設定 2.項目レベルのセキュリティ 7 プロファイルごとに設定・管理する。 •Required •Editable •Read-Only FLS
  8. 8. データに対するセキュリティ設定 3.Force.comでの共有設定 8 今日は割愛します。ごめんなさい。 Sharing
  9. 9. データに対するセキュリティ設定 CRUD 9 1.オブジェクトレベルのアクセス権限 2.項目レベルのセキュリティ 3.Force.comでの共有設定 を適切に設定する。 FLS Sharing
  10. 10. 10 #2 ページ開発時に、何を 気をつければいいの~
  11. 11. まず、大前提として・・・ Apex: Apex Classes do not enforce CRUD Why? System Context Visualforce: Visualforce Pages do enforce CRUD Why?User Context 11
  12. 12. まず、大前提として・・・ Apex: Apex は、CRUDもFLSも遵守しません。 システムコンテクストだから。 Visualforce: Visualforce は、CRUDもFLSも遵守します。 ユーザコンテクストだから。 12
  13. 13. 考えるべきポイントは2つ 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 13
  14. 14. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 14 更に、ここもポイントは2つ。 ①Visualforce層を介する場合 ②Visualforce層を介さない場合
  15. 15. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 15 更に、ここもポイントは2つ。 ①Visualforce層を介するとは? 差込項目が、Sobjectや項目を直接参照 しているケース。
  16. 16. Visualforce Page 01 <apex:page standardController="Account"> 02 <apex:pageBlock title="Contacts"> 03 <apex:dataTable value="{!account.Contacts}" var="contact" cellPadding="4" border="1"> 04 <apex:column> 05 <apex:facet name="header">Name</apex:facet> 06 {!contact.Name} 07 </apex:column> 08 <apex:column> 09 <apex:facet name="header">Phone</apex:facet> 10 {!contact.Phone} 11 </apex:column> 12 </apex:dataTable> 13 </apex:pageBlock> 14 </apex:page> 16
  17. 17. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 17 更に、ここもポイントは2つ。 ①Visualforce層を介する場合 ②Visualforce層を介さないとは? 文字列、整数、Apex クラスなどのオブ ジェクトを介して SObject データを参照 している場合
  18. 18. Visualforce Page 01 <apex:page controller="MyLanguageController" showheader="false" applyBodyTag="true" sidebar="false"> 02 <apex:pageMessages /> 03 04 <apex:form > 05 <apex:selectList value="{!selectedLanguage}" multiselect="False" size="1" style="width:115px;"> 06 <apex:selectOptions value="{!languageOptions}"/> 07 </apex:selectList> 08 <apex:commandButton value="change!" action="{!save}" /> 09 </apex:form> 10 11 </apex:page> 18
  19. 19. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 19 ①Visualforce層を介する場合 ⇒CRUD、FLSが自動チェックされる。 ②Visualforce層を介さない場合 ⇒CRUD、FLSの自動チェックはない。 よって、自前でチェックする必要 がある!
  20. 20. 考えるべきポイントは2つ 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 20
  21. 21. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 21 ここも同様のポイントが2つ。 ①Visualforce層を介する場合 ②Visualforce層を介さない場合
  22. 22. 考えるべきポイントは2×2 2.データに対する変更(作成、更新、削除) 22 ①Visualforce層を介する場合 ⇒CRUD、FLSが自動チェックされる。 ②Visualforce層を介さない場合 ⇒CRUD、FLSの自動チェックはない。 よって、自前でチェックする必要 がある!
  23. 23. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 23 いずれのパターンにおいても、 Visualforce層を介するレンダリングが推 奨される。
  24. 24. 考えるべきポイントは2×2 1.ユーザに対して表示するデータ 2.データに対する変更(作成、更新、削除) 24 では、Visualforce層を介さない場合、 どうチェックするのか?
  25. 25. 25 #3 どうやって チェックするの~
  26. 26. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 26
  27. 27. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 27
  28. 28. Visualforce Page 01 <apex:page controller="RandomContactController"> 02 <apex:outputText value="{!getRandomName}" /> 03 </apex:page> 28 Apex Controller 01 public with sharing class RandomContactController { 02 public String getGetRandomName() { 03 04 Contact [] myList = [SELECT Name FROM Contact LIMIT 1000]; 05 // Pick a list entry at random 06 Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size()); 07 Contact selected = myList.get(index); 08 return selected.Name; 09 } 10 }
  29. 29. Visualforce Page 01 <apex:page controller="RandomContactController"> 02 <apex:outputText value="{!getRandomName}" /> 03 </apex:page> 29 Apex Controller 01 public with sharing class RandomContactController { 02 public String getGetRandomName() { 03 04 // Check if the user has read access on the Contact.Name field 05 if (!Schema.sObjectType.Contact.fields.Name.isAccessible()) { 06 return ''; 07 } 08 09 Contact [] myList = [SELECT Name FROM Contact LIMIT 1000]; 10 // Pick a list entry at random 11 Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size()); 12 Contact selected = myList.get(index); 13 return selected.Name; 14 } 15 }
  30. 30. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 30
  31. 31. Visualforce Page 01 <apex:page standardcontroller="Lead" extensions="LeadConverterExtension"> 02 <apex:pageMessages /> 03 <apex:pageBlock title="Lead"> 04 <apex:outputField value="{!Lead.Name}" /><br /> 05 <apex:outputField value="{!Lead.Company}" /><br /> 06 <apex:outputField value="{!Lead.Phone}" /><br /> 07 <apex:form> 08 <apex:commandButton action="{!convertLead}" value="Convert To Contact" /> 09 </apex:form> 10 </apex:pageBlock> 11 </apex:page> 31
  32. 32. 32 Apex Controller 01 public with sharing class LeadConverterExtension { 02 private Lead l; 03 public LeadConverterExtension(ApexPages.StandardController ctr) { 04 l = [SELECT FirstName,LastName,Phone,Company FROM Lead WHERE Id=:ctr.getRecord().05 } 06 07 public PageReference convertLead() { 08 Contact c = new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone); 09 insert c; 10 return null; 11 } 12 }
  33. 33. 33 Apex Controller 01 public with sharing class LeadConverterExtension { 02 private Lead l; 03 public LeadConverterExtension(ApexPages.StandardController ctr) { 04 l = [SELECT FirstName,LastName,Phone FROM Lead WHERE Id=:ctr.getRecord().Id]; 05 } 06 07 public PageReference convertLead() { 08 String [] contactUpdateFields = new String [] {'FirstName', 'LastName', 'Phone'}; 09 10 Map<String,Schema.SObjectField> m = Schema.SObjectType.Contact.fields.getMap(); 11 for (String fieldToCheck : contactUpdateFields) { 12 if (!m.get(fieldToCheck).getDescribe().isCreateable()) { 13 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 14 return null; 15 } 16 } 17 18 Contact c = new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone); 19 insert c; 20 return null; 21 } 22 }
  34. 34. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 34
  35. 35. 35 Apex Controller 01 public with sharing class LeadConverterExtension { 02 private Lead l; 03 public LeadConverterExtension(ApexPages.StandardController ctr) { 04 l = [SELECT FirstName,LastName,Phone FROM Lead WHERE Id=:ctr.getRecord().Id]; 05 } 06 07 public PageReference convertLead() { 08 String [] contactUpdateFields = new String [] {'FirstName', 'LastName', 'Phone'}; 09 10 Map<String,Schema.SObjectField> m = Schema.SObjectType.Contact.fields.getMap(); 11 for (String fieldToCheck : contactUpdateFields) { 12 if (!m.get(fieldToCheck).getDescribe().isCreateable()) { 13 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 14 return null; 15 } 16 } 17 18 Contact c = new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone); 19 insert c; 20 return null; 21 } 22 } isCreateable() を isUpdateable() に してチェック!
  36. 36. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 36
  37. 37. Visualforce Page 01 <apex:page standardcontroller="Lead" extensions="LeadDeleteExtension"> 02 <apex:pageMessages /> 03 <apex:pageBlock title="Lead"> 04 <apex:outputField value="{!Lead.Name}" /><br /> 05 <apex:outputField value="{!Lead.Company}" /><br /> 06 <apex:outputField value="{!Lead.Phone}" /><br /> 07 <apex:form> 08 <apex:commandButton action="{!deleteLead}" value=“Delete" /> 09 </apex:form> 10 </apex:pageBlock> 11 </apex:page> 37
  38. 38. 38 Apex Controller 01 public with sharing class LeadDeleteExtension { 02 private Lead l; 03 public LeadDeleteExtension(ApexPages.StandardController ctr) { 04 l = [SELECT Id FROM Lead WHERE Id=:ctr.getRecord().Id]; 05 } 06 07 public PageReference deleteLead() { 09 delete l; 10 return null; 11 } 12 }
  39. 39. 39 Apex Controller 01 public with sharing class LeadDeleteExtension { 02 private Lead l; 03 public LeadDeleteExtension(ApexPages.StandardController ctr) { 04 l = [SELECT Id FROM Lead WHERE Id=:ctr.getRecord().Id]; 05 } 06 07 public PageReference deleteLead() { 08 if (!Lead.sObjectType.getDescribe().isDeletable()) { 09 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 10 return null; 11 } 12 } 13 14 delete c; 15 return null; 16 } 17 } isDeletable() は オブジェクトレベルで チェック!
  40. 40. パターンは4+α 1.データ表示(R) 2.データ作成(C) 3.データ編集(U) 4.データ削除(D) 5.Apexコントローラではなく、 Visualforceページでチェック! 40
  41. 41. Visualforce Page <!– 表示権限チェック --> 01 <apex:outputText value="{!contactName}" 02 rendered="{!$ObjectType.Contact.fields.Name.Accessible}" /> <!– 作成権限チェック --> 01 <apex:inputText value="{!stringToBecomeNewContactEmail}" 02 rendered="{!$ObjectType.Contact.fields.Email.Createable}" /> <!– 更新権限チェック --> 01 <apex:inputText value="{!contactEmail}" 02 rendered="{!$ObjectType.Contact.fields.Email.Updateable}" /> <!– 削除権限チェック --> 01 <apex:commandButton action="{!CustomDelete}“ 02 rendered="{!$ObjectType.Contact.Deletable}" /> 41
  42. 42. 42 Enjoy Salesforce Developer Thank You!

×