Salesforceの内部からREST APIをコールする場合の検討


APIファーストの設計というのをSalesforceでも行おうとすると、Apexクラスから同じ組織にあるREST APIをコールする必要があります。コールする側と、コールを返す側が同じIPアドレスでも問題はないとは思うけど、何か他に制限はあるのでしょうか？　まぁ、APIのコール数の上限とかかな...

気になった質問があったので、自動翻訳してみます。

+ [Calling Salesforce REST API From Apex Class](https://www.reddit.com/r/SalesforceDeveloper/comments/ydetdd/calling_salesforce_rest_api_from_apex_class/)
+ [Call Salesforce API from Apex and not fail Security Review](https://salesforce.stackexchange.com/questions/389121/call-salesforce-api-from-apex-and-not-fail-security-review)

私は何年もの間、Apex 内から Salesforce API を使用してきました。主に、セットアップの自動化を使用してアプリを強化するためです。そこで、次のようなToolingand Metadata APIfrom のコード スニペットを使用しました。UserInfo.getSessionId()

```
private HTTPResponse createSObject(String fragment) {
    HttpRequest request = new HttpRequest();

    request.setEndpoint(URL.getOrgDomainUrl().toExternalForm() + '/services/Soap/u/53.0');
    request.setMethod('POST');
    request.setHeader('Content-Type', 'text/xml; charset=UTF-8');
    request.setHeader('SOAPAction', 'ignored');
    request.setBody('<?xml version="1.0" encoding="UTF-8"?>.... 
                     <sessionId>' + UserInfo.getSessionId() + '</sessionId>');

    return new Http().send(request);
}
```

同様のコードでセキュリティ レビューに失敗しました。

:::note alert
Unauthorized use of SessionID

Please use OAuth, (try JWT flows and look into admin pre-authorization). Do not touch user credentials in a managed package.

SessionIDの不正使用

OAuth を使用してください (JWT フローを試し、管理者の事前承認を調べてください)。管理パッケージ内のユーザー資格情報には触れないでください。
:::

6 このことは、数か月前にパートナー フォーラムで明らかになりました。JWT フロー OAuth はConnected Appsで利用できます。接続アプリは PBO 上に作成することで処理します。接続アプリをパッケージ化すると、すべてのインストールに一意の値が発生し、JWT フローの呼び出しに必要なパラメーターを使用できるようにするためのインストール後の手動アクティビティが必要になるため、接続アプリをパッケージ化しないことをお勧めします。

8 (そして、はい、これはクレイジーなポリシーだと思います。Salesforce セキュリティはやりすぎです。) そもそもプラットフォームが Apex 呼び出し可能な API を提供していれば、半分の確率で、このような厄介なループバックを使用する必要はありません。Salesforce API 環境は、広範かつ重要であるにもかかわらず、あまりにもサイロ化され、断片化されすぎています。私の意見では、実際のループバックを必要とせずに、Apex プロキシを介してすべての API を呼び出すことができるはずです。

1 Apex プロキシについては同意しますが、「外部」API に関するポリシーについては同意しません。セッション ID の使用は、最新のセキュリティのベスト プラクティスからすると完全に時代遅れです。はい、SF には「使いやすさ」の基準に関して多くのギャップがありますが、セキュリティを犠牲にすることは解決策ではありません。

7 ここでの問題点は次のとおりです。 1. ドキュメントでは依然としてこのアプローチを推奨しています。2. Salesforce Security は、レビュー中にセッション ID がどのように使用されているかを確認できるため、このような無害な使用を簡単に許可できます。重要なのは、セッション ID が組織の外部に公開されていないということです。これは、 REST 呼び出しに頼らずに使用できるはずの API へのループバックに使用されているだけです。

1 重要な考慮事項の 1 つは、Apex コードが Lightning コンポーネントから実行される場合、セッション ID は API 対応にならないということです。

1 Salesforce がこれよりも優れたドキュメントを提供してくれることを願っています。OAuth 接続を構成するためにこれらの不透明な文字列に何を入力する必要があるかについては、ここでは詳しく説明しません。ExternalCredential がまだ必要であると推測できます。利用可能なプロバイダーがなかったため、スクラッチ組織でプロバイダーを作成できませんでした。そのため、ここではサポートされていない従来の認証情報を使用したと思います

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_connectapi_input_credential.htm

ソリューションは Connected App ですが、これは正確には何を意味するのでしょうか?

接続アプリケーションを使用すると、外部アプリケーションから Salesforce 組織リソースへの接続を制御できます。スコープ、OAuth ポリシー、IP 範囲、その他のパラメーターを使用して、不要なトラフィックと操作を制限します。管理者はいつでもアクセス権を確認し、付与/取り消し/監視できます。


**これらの緩和策は本質的に破壊的すぎるものです。**

Salesforce は、過去数年間で REST API の使用法を大幅に進歩させてきました (REST API の 1 日あたりの制限の調整、UI API、複合 API、複合グラフ API、GraphQL サポートなど)。当社はこれらの新機能を採用し、それによって顧客に価値を提供してきました。これにより、Salesforce との相互成長が可能になりました。私の観点からすると、この新しい施行は敷物を下から引きずり出しているように感じられ、同等の代替手段はなく、ユーザーエクスペリエンスへの影響は過小評価されています。

短期的には、これは強制措置として再検討されるべきだと思いますが、長期的には、そのような技術的なリフトなしで何らかの代替策が必要です。

多くの素晴らしい新機能は、最初に REST API 経由でアクセスできます。インスタンス内で既に実行されているコードのこれらのリソースにアクセスするには、最初にセッション ID を利用する必要があるという大きなギャップのように感じます。

Salesforce 内 (Apex または LWC 内) から呼び出すためにこれらすべてのリソースをどのように公開できるかについて、Salesforce が解決策の優先順位を付けることができれば素晴らしいと思います。そこでは、認証が私たちの手を離れます (認証がどのように機能するかと同様です)。 Salesforce の機能)。

UserInfo.getSessionId を使用できるように、パッケージにアーキテクチャの複雑さを追加したくありません。それをまったく使用する必要がないようにしたいのですが...


# 接続アプリをパッケージ化しないことをお勧めします

+ [SessionID access vulnerability found when using Metadata API](https://salesforce.stackexchange.com/questions/346926/sessionid-access-vulnerability-found-when-using-metadata-api)

:::note
API Sid の使用は、管理パッケージでは決して許可されていません。これらは、パッケージ化されていないコードでのみ許可されます。唯一の問題は、これを一貫して強制する自動化ツールが存在しなかったことです。これらの自動化ツールが展開されると、セッション ID の盗難により多くのアプリが審査に落ち始め、既存のアプリにフラグが立てられ始めます。

ユーザーの SID を取得して別の API にログインすることが、管理パッケージでは行われたくない理由を理解するには、次の点を考慮してください

1. 偽装: ログには、それらの呼び出しがアプリによって行われたときにユーザーによって行われたものとして記録されます。OAuth を使用する場合、アプリに関連付けられた資格情報を使用してログインすることになり、何が起こっているかがログに正しく追跡されます。

2. 承認の欠如: ユーザーに代わって別のサービスにログインする場合は、ユーザーの同意なしにこれを実行するのではなく、その実行を許可する必要があります。Salesforce では、管理者はユーザーを事前承認して、別のユーザーに代わって同意を与えることができますが、アプリケーション自体を承認することはできません。OAuth には認証ステップがあり、ユーザーの承認なしに資格情報を黙って盗んだりアクションを実行したりすることがなくなります。

3. スコープの欠如: 最小限の特権の原則に従い、許可される操作を可能な限り必要なものに近づけたいと考えています。OAuth ではスコープを選択したり定義したりできますが、API Sid にはこれを行う機能がありません。

4. 名前空間エスケープ: 管理パッケージ内で実行されるすべてのコードは、名前空間にスコープされる必要があります。その名前空間を突破して別のスコープで実行しようとする試みは、セキュリティ レビューで脆弱性とみなされます。これには、Web リンク経由で Salesforce オリジンのセッション ID を取得しようとする試みや、名前空間のない API SID を取得しようとする試みが含まれます。管理者がアプリを使用している場合は、その管理者の SID を取得して、別の名前空間にあるパッケージをアンインストールするか、パッケージ化されていない名前空間に apex クラスをインストールすることができます。これは明らかに自分自身の名前空間からの脱出です。

上記のリスクのため、API 対応 SID は安全でないと考えられており、製品から SID を削除する継続的な取り組みと、管理パッケージでの使用にフラグを立てる自動および手動の取り組みの両方が行われています。時間の経過とともに、これらの取り組みはますます厳格になるため、今すぐ避けてください。アプリがこれらを使用している場合は、代わりに OAuth を使用するようにアプリのリファクタリングを開始してください。

これは基本的に、ホームページ コンポーネントの問題の継続であり、管理パッケージに属さない資格情報の使用を防ぐためのプラットフォームの継続的なロックダウンです。

+ [Apex ラッパー Salesforce メタデータ API での名前付き認証情報の使用](https://gscloudsolutions.com/tips-tricks/using-named-credentials-with-the-apex-wrapper-salesforce-metadata-api/)
:::

# OAuth認証の問題点 ：これでは使えないなぁ

OAuth 許可は問題ありませんでしたが、(要求どおりに) ログイン ページにリダイレクトされ、再度ログインするように求められます。ユーザー名とパスワード (oAuth フローの一部としては醜いものです) を入力すると、コード パラメーターを使用して VF ページにリダイレクトされます。

2 回目の oAuth 付与は自動的に行われ、ログイン ページが直接表示されました。したがって、**アプリが許可された場合でも、ユーザーはトークンが要求されるたびにログインする必要があります。**


# さらに検討してくれている？

これを初めて見て以来、私はこの問題を解決するために使用できるアプローチを開発してきました。そのようなプロセスとしては、JWT と Web フローの 2 つがあります。

Salesforce は、開発者のパッケージ化組織に保存されている単一のマスターキーを使用する JWT ベースのソリューションを提案しました。私がこれを避けてきたのは、社内のセキュリティがどれほど優れていても、パッケージ化組織にアクセスできるユーザーをどれほど制限していても、単一のマスター キーでインターネット上のどこからでもすべての顧客組織にアクセスでき、それらの組織の管理者として行動していたというのは、あまりにも恐ろしすぎて考えられません。

私の JWT ソリューションは、管理者によってインストールおよび制御されているローカル キーを使用します。これにより、キーが制御不能になるため、キー使用の否認防止の側面がなくなりますが、接続されたアプリケーションを使用する要件を満たしながら認証へのアクセスを継続する簡単な実装手段が提供されます。これにより、インストール後の追加の管理タスクのコストが発生します。これが「最小限のコード変更で迅速に導入する必要がある」に対する解決策です。

もう 1 つの解決策は、Web フローを使用することです。私の Web フローは、外部のどこかにある非常に単純なサーバーを使用しています。私のサンプル コード (以下にリンク) は Express サーバーですが、実稼働システムでは、当然、より実稼働対応のソリューションが検討されます。サンプルは、簡単に展開して探索できるように設計されています。

Web フローには、はるかに使いやすく、Salesforce 管理者が望む制御を提供できるという利点があります。

https://github.com/financialforcedev/mdapi-oauth-demo

# さて、どのように構築していくか

REST APIの中に実際の処理をするApexを書いて、内部から使う時は直接このメソッドを呼び出す。外部からはREST APIを呼び出すように２段階の構成にするとこの問題は回避できるかな？

ロジックと画面を疎結合にしたいことと、APIをPostmanを使ってテストの自動化を行いたかったのですが、あんまりいいやり方ではないかな。