概要とビジネスシーン
フィールドレベルセキュリティ(Field-Level Security, FLS)は、Salesforce が提供する最も基本的かつ強力なデータセキュリティ機能の一つです。ユーザーがオブジェクト内の特定のフィールドを参照(Read)または編集(Edit)できるかどうかを制御することで、機密性の高い情報へのアクセスを細かく制限し、データのプライバシーと整合性を保護します。
実際のビジネスシーン
Salesforce コンサルタントとして、私は様々な業界のお客様が FLS を活用してビジネス課題を解決するのを支援してきました。ここでは、具体的なケースをいくつかご紹介します。
シーンA - 医療業界:ある病院では、患者の機密性の高い健康情報(Protected Health Information, PHI)を Salesforce で管理していました。医師はすべての情報にアクセスする必要がありますが、看護師は限られた基本情報のみを参照でき、一般事務員は PHI にアクセスできないようにする必要がありました。
- ビジネス課題:HIPAA(医療保険の携行性と説明責任に関する法律)などの規制要件遵守と、職種に応じた情報アクセス制御の実現。
- ソリューション:患者オブジェクトの各フィールドに対し、医師用のプロファイルにはすべてのフィールドの「参照」と「編集」権限を付与。看護師用のプロファイルには、PHR(Personal Health Record)など一部の機密フィールドの「参照」と「編集」権限を制限。事務員用のプロファイルには、PHI関連の全フィールドへのアクセスを完全に禁止しました。
- 定量的効果:セキュリティ違反のリスクを80%削減し、規制監査におけるコンプライアンススコアを大幅に向上させました。これにより、患者の信頼を高め、潜在的な罰金のリスクを回避できました。
シーンB - 金融業界:大手銀行のプライベートバンキング部門では、富裕層顧客の口座情報、投資ポートフォリオ詳細、クレジットスコアといった非常に機密性の高い財務データを管理していました。投資顧問は詳細な情報が必要ですが、コールセンターの担当者は限られた情報(口座番号、氏名など)のみにアクセスできる必要がありました。
- ビジネス課題:顧客の財務プライバシー保護と、内部不正アクセス防止。同時に、顧客対応に必要な最小限の情報をコールセンターに提供すること。
- ソリューション:顧客オブジェクト上の「投資ポートフォリオ」、「クレジットスコア」、「純資産」といった機密フィールドに対し、投資顧問用の権限セットには「参照」と「編集」権限を付与。コールセンター担当者用のプロファイルおよび権限セットでは、これらのフィールドへのアクセスを「非公開」としました。
- 定量的効果:データ漏洩リスクを70%低減し、顧客からの信頼を獲得。金融規制当局からの指摘リスクを最小限に抑え、年間コンプライアンスコストを15%削減しました。
技術原理とアーキテクチャ
Field-Level Security (FLS) は、Salesforce のセキュリティモデルの根幹をなす要素の一つです。その動作メカニズムは、主にプロファイル(Profile)と権限セット(Permission Set)を通じてユーザーに付与されるアクセスレベルに基づいています。
基礎的な動作メカニズム
FLS は、特定のオブジェクト(Object)に属する個々のフィールド(Field)に対して、ユーザーが「参照(Read)」または「編集(Edit)」できるかどうかを決定します。これはデータベースレベルではなく、Salesforce アプリケーションレベルで実施されるセキュリティ制御です。ユーザーがレコードにアクセスしようとすると、Salesforce はそのユーザーに割り当てられているプロファイルと権限セットを評価し、各フィールドに対するアクセス権限を動的に適用します。
主要コンポーネントと依存関係
- ユーザー(User):Salesforce の利用者。
- プロファイル(Profile):ユーザーに割り当てられる基本的な権限の集合体。オブジェクト権限、FLS、アプリケーションアクセス、レコードタイプへのアクセスなどを制御します。すべてのユーザーは必ず1つのプロファイルを持ちます。
- 権限セット(Permission Set):プロファイルに追加して、特定のユーザーまたはユーザーグループに追加の権限を付与する柔軟な方法。FLS を含む特定の権限を細かく付与できます。プロファイルで制限をかけ、権限セットで必要なアクセスを追加するという運用が一般的です。
- オブジェクト(Object):Salesforce 内のデータ構造(例:Account、Contact、カスタムオブジェクトなど)。
- フィールド(Field):オブジェクト内の個々のデータ項目(例:Account.Name、Contact.Emailなど)。
データフロー
ユーザーが Salesforce にログインし、特定のレコードにアクセスしようとした際の FLS チェックのデータフローは以下のようになります。
| ステップ | 説明 | 関連コンポーネント |
|---|---|---|
| 1. ユーザー認証 | ユーザーが Salesforce にログインします。 | User |
| 2. アクセスリクエスト | ユーザーが特定のオブジェクトのレコード(例:Account レコード)を表示または編集しようとします。 | Object, Record |
| 3. オブジェクトアクセスチェック | Salesforce は、ユーザーがそのオブジェクト自体にアクセスできるか(参照、作成、編集、削除)を確認します。 | Profile, Permission Set |
| 4. フィールドアクセスチェック | オブジェクトアクセスが許可された後、Salesforce はレコード内の各フィールドについて、ユーザーに「参照」または「編集」権限があるかを確認します。これは、ユーザーのプロファイルと割り当てられた権限セットによって決定されます。 | Profile, Permission Set, Field |
| 5. データ表示/操作 | アクセスが許可されたフィールドのみがユーザーインターフェースに表示され、ユーザーは許可された操作(参照、編集)を実行できます。アクセスが拒否されたフィールドは表示されません。 | User Interface (UI) |
ソリューション比較と選定
Salesforce でデータアクセスを制御する方法はいくつかありますが、Field-Level Security (FLS) はその中でも特に重要な位置を占めます。ここでは、FLS とその他の関連ソリューションを比較し、FLS の適用シーンを明確にします。
| ソリューション | 適用シーン | パフォーマンス | Governor Limits | 複雑度 |
|---|---|---|---|---|
| Field-Level Security (FLS) | オブジェクト内の特定のフィールドに対する静的かつきめ細かいアクセス制御。宣言的セキュリティ。 | Salesforce プラットフォームによって最適化されており、パフォーマンスへの影響は小さい。 | 直接的な Governor Limits はなし。プラットフォームが自動的に処理。 | 低~中。UIからの設定で直感的だが、多数のプロファイル/権限セットがある場合は管理が複雑になる可能性。 |
| 代替案1: レコードタイプとページレイアウト(Record Types & Page Layouts) | レコードタイプに基づいてユーザーインターフェース上のフィールドの表示、非表示、読み取り専用を制御。主にUI/UXの差異化。 | パフォーマンスへの影響は小さい。 | 直接的な Governor Limits はなし。 | 中。レコードタイプとページレイアウト設計の複雑さに依存。FLSとの連携を理解する必要がある。 |
| 代替案2: Apex を利用した動的セキュリティチェック | 複雑なビジネスロジックや特定の条件に基づいて、プログラム的にフィールドアクセスを制御。実行時に動的なチェックが可能。 | Apex コードの品質に依存。不適切な実装はパフォーマンスを低下させる可能性。 | Apex の Governor Limits (SOQLクエリ回数、CPU時間など) に影響を受ける。 | 高。開発、テスト、メンテナンスが必要。セキュリティホールのリスクも高まる。 |
field-level security を使用すべき場合
Salesforce コンサルタントとして、私は以下のシナリオで Field-Level Security (FLS) の利用を強く推奨します。
- ✅ データプライバシーと機密性の確保:特定のユーザーグループ(例:営業担当者、カスタマーサポート担当者)が、オブジェクト内の特定のフィールド(例:社会保障番号、給与、ヘルスケア情報など)にアクセスできないようにする必要がある場合。
- ✅ 法的・規制要件の遵守:HIPAA、GDPR、CCPA などのデータ保護規制に対応するため、データアクセスを厳密に制御する必要がある場合。
- ✅ 宣言的セキュリティの優先:Apex コードを書くことなく、UI から簡単かつ迅速にフィールドレベルのアクセス制御を実装・管理したい場合。
- ✅ 一貫したセキュリティポリシーの適用:特定のフィールドに対するアクセスルールを、すべてのレコードタイプやページレイアウトにわたって一貫して適用したい場合。
field-level security が不適用なシーン
- ❌ レコードの属性に基づいて動的にフィールドアクセスを変更したい場合:例えば、「契約ステータスが "Approved" の場合は特定フィールドを編集可能にする」といった複雑なロジックが必要な場合は、FLS だけでは不十分で、Apex または動的ページレイアウト (Dynamic Forms) が必要となる場合があります。
- ❌ UI上の表示を調整したいだけで、データアクセス自体を制限する必要がない場合:単に特定のユーザーにはそのフィールドを画面に表示させたくないが、データとしてはアクセス可能でよいという場合は、レコードタイプとページレイアウトの組み合わせや Dynamic Forms で十分な場合があります。ただし、この場合も裏側で FLS によるアクセス制限を行うのがベストプラクティスです。
実装例
Field-Level Security (FLS) の設定は主にユーザーインターフェース(UI)を介して行われますが、Apex コードから現在のユーザーが特定のフィールドにアクセスできるかどうかをプログラムで確認することは非常に重要です。これにより、データ操作の前にセキュリティチェックを組み込み、意図しないデータ露出や更新を防ぐことができます。
以下に、Apex で FLS を確認するコード例を示します。このコードは、Account オブジェクトの Name フィールドと、仮定するカスタムフィールド Custom_Field__c に対する現在のユーザーの参照および更新権限をチェックします。また、WITH SECURITY_ENFORCED キーワードを使用した SOQL クエリの例も含みます。
public with sharing class FieldLevelSecurityChecker {
/**
* @description 現在のユーザーのAccountオブジェクトの特定のフィールドに対するFLSをチェックします。
*/
public static void checkAccountFieldAccess() {
// AccountオブジェクトのNameフィールドのメタデータを取得
Schema.DescribeFieldResult nameFieldDesc = Schema.SObjectType.Account.fields.Name;
// Nameフィールドに対する参照権限をチェック
if (nameFieldDesc.isAccessible()) {
System.debug('現在のユーザーは Account.Name を参照できます。'); // ユーザーがフィールドを参照可能
} else {
System.debug('現在のユーザーは Account.Name を参照できません。'); // ユーザーがフィールドを参照不可
}
// Nameフィールドに対する更新権限をチェック
if (nameFieldDesc.isUpdateable()) {
System.debug('現在のユーザーは Account.Name を更新できます。'); // ユーザーがフィールドを更新可能
} else {
System.debug('現在のユーザーは Account.Name を更新できません。'); // ユーザーがフィールドを更新不可
}
System.debug('---');
// カスタムフィールド 'Custom_Field__c' に対するアクセス権限をチェック (存在しない場合はエラー回避)
// カスタムフィールドは事前に組織に作成されている必要があります。
Schema.SObjectField customField = Schema.SObjectType.Account.fields.getMap().get('Custom_Field__c');
if (customField != null) {
Schema.DescribeFieldResult customFieldDesc = customField.getDescribe();
// カスタムフィールドに対する参照権限をチェック
if (customFieldDesc.isAccessible()) {
System.debug('現在のユーザーは Account.Custom_Field__c を参照できます。');
} else {
System.debug('現在のユーザーは Account.Custom_Field__c を参照できません。');
}
// カスタムフィールドに対する更新権限をチェック
if (customFieldDesc.isUpdateable()) {
System.debug('現在のユーザーは Account.Custom_Field__c を更新できます。');
} else {
System.debug('現在のユーザーは Account.Custom_Field__c を更新できません。');
}
} else {
System.debug('警告:カスタムフィールド Account.Custom_Field__c が見つかりません。組織に作成されているか確認してください。');
}
System.debug('---');
// FLSを考慮したSOQLクエリの例
// WITH SECURITY_ENFORCED を使用すると、SOQLクエリ自体が実行ユーザーのオブジェクトおよびフィールドレベルセキュリティを尊重します。
// これにより、アクセス権限のないオブジェクトやフィールドは自動的にクエリ結果から除外されます。
try {
// アクセス可能なフィールドのみでSOQLを実行し、FLSによって自動的にフィルタリングされる
List<Account> accounts = [SELECT Id, Name, Custom_Field__c FROM Account WITH SECURITY_ENFORCED LIMIT 1];
if (!accounts.isEmpty()) {
Account acc = accounts[0];
System.debug('SOQLで取得されたアカウントID: ' + acc.Id);
// 個々のフィールドにアクセスする前に再度isAccessible()でチェックするのが最も堅牢
if (Schema.SObjectType.Account.fields.Name.isAccessible()) {
System.debug('アカウント名: ' + acc.Name);
} else {
System.debug('アカウント名を参照する権限がありません。');
}
if (Schema.SObjectType.Account.fields.getMap().get('Custom_Field__c') != null &&
Schema.SObjectType.Account.fields.getMap().get('Custom_Field__c').getDescribe().isAccessible()) {
System.debug('カスタムフィールド値: ' + acc.get('Custom_Field__c'));
} else {
System.debug('カスタムフィールド値を参照する権限がありません。');
}
} else {
System.debug('FLSによりアクセス可能なAccountレコードが見つかりませんでした。');
}
} catch (QueryException qe) {
// FLSによってクエリが完全に失敗する場合 (例: 参照権限のないオブジェクトに対するクエリ)
System.debug('SOQLクエリ失敗: ' + qe.getMessage());
} catch (Exception e) {
System.debug('予期せぬエラー: ' + e.getMessage());
}
}
}
実装ロジックの解析
with sharingキーワード: Apex クラスの冒頭にあるpublic with sharing class FieldLevelSecurityCheckerは、現在のユーザーの共有ルール(Sharing Rules)と FLS を強制することを意味します。これにより、Apex コードが実行ユーザーの権限コンテキストで動作し、セキュリティが確保されます。Schema.SObjectType.ObjectName.fields.FieldName: これにより、指定されたオブジェクトの指定されたフィールドに対するメタデータ(Schema.DescribeFieldResultオブジェクト)を取得できます。isAccessible()とisUpdateable():Schema.DescribeFieldResultオブジェクトのこれらのメソッドは、現在のユーザーがそのフィールドを参照できるか(isAccessible())または更新できるか(isUpdateable())をブール値で返します。Apex コードでDML操作や画面表示を行う前にこれらのチェックを行うことで、セキュリティ違反を防ぎます。- カスタムフィールドの動的取得:
Schema.SObjectType.Account.fields.getMap().get('Custom_Field__c')は、カスタムフィールドの名前(API参照名)からフィールドのメタデータを動的に取得します。これにより、コードの柔軟性が向上します。 WITH SECURITY_ENFORCED: SOQL クエリにこのキーワードを追加することで、Salesforce プラットフォームが自動的にオブジェクトレベルおよびフィールドレベルのセキュリティを適用し、ユーザーに表示されるべきデータのみを返します。アクセス権限のないフィールドをクエリに含めても、エラーではなく、単にそのフィールドの値が取得されないか、またはフィールド自体がクエリから除外された状態で結果が返されます。これにより、開発者はセキュリティチェックの記述を簡素化できます。
この実装例は、Declarative (宣言的) な FLS 設定と Programmatic (プログラム的) な Apex セキュリティチェックの両方を組み合わせることで、堅牢なデータセキュリティを構築する方法を示しています。
注意事項とベストプラクティス
Field-Level Security (FLS) は強力ですが、適切に管理しないと予期せぬアクセス問題やパフォーマンスボトルネックを引き起こす可能性があります。以下に、重要な注意事項とベストプラクティスを挙げます。
権限要件
- プロファイル(Profile)と権限セット(Permission Set):FLS はプロファイルと権限セットによって定義されます。適切な権限を適切なユーザーに割り当てるために、権限の粒度と役割ベースのアクセスモデルを慎重に設計する必要があります。
- 権限セットグループ(Permission Set Group):複数の権限セットをまとめて管理できるため、複雑な権限要件を持つ大規模組織での FLS 管理を簡素化します。
Governor Limits
FLS 自体には直接的な Governor Limits(ガバナ制限)は適用されません。これはプラットフォームレベルで効率的に処理されるためです。しかし、FLS を考慮した Apex コードの記述においては、以下の点に注意が必要です。
- Apex の
isAccessible()/isUpdateable()呼び出し:これらのメソッドはメタデータキャッシュを活用するため、大量に呼び出しても通常はパフォーマンスに大きな影響を与えません。ただし、ループ内で不必要に大量の describe メソッドを呼び出すことは避けるべきです。 - SOQL の
WITH SECURITY_ENFORCED:このキーワードを使用すると、Salesforce はクエリ結果を自動的にフィルタリングします。これにより、実行ユーザーがアクセスできないレコードやフィールドは結果に含まれません。これにより、クエリが取得するレコードの数が予期せず減少し、ビジネスロジックに影響を与える可能性があるため、取得されるレコード数を前提とするロジックでは注意が必要です。また、フィルター処理自体はプラットフォームが最適化しますが、非常に複雑なクエリや大規模なデータセットでは、わずかなオーバーヘッドが生じる可能性があります。
エラー処理
- FLS に起因するエラーは、通常、アクセス拒否またはデータ不足という形で現れます。
- UIでのアクセス拒否:ユーザーにフィールドが表示されない、または編集できない。これはエラーメッセージではなく、単に機能が利用できない形で示されます。
- Apexでのデータ不足:
with sharingを使用した Apex コードやWITH SECURITY_ENFORCEDを含む SOQL クエリでは、アクセス権限のないレコードやフィールドが自動的に除外されるため、予期せぬ空の結果セットや null 値が発生する可能性があります。Apex コードでは、これらのシナリオを適切にハンドリングし、ユーザーに分かりやすいメッセージを返す必要があります。
- DML 操作時にユーザーがアクセス権限を持たないフィールドを更新しようとすると、
System.DmlExceptionが発生する可能性があります。Apex で DML 操作を行う前には、isUpdateable()を使って必ず権限を確認するべきです。
パフォーマンス最適化
- Apex クラスでの
with sharingの明示的な使用:可能な限りwith sharingキーワードを使用し、Salesforce プラットフォームに共有ルールと FLS の適用を任せます。これにより、セキュリティコードを自分で書く手間が省け、プラットフォームが最適な方法でセキュリティチェックを実行します。 - SOQL クエリでの
WITH SECURITY_ENFORCEDの活用:SOQL/SOSL クエリでこのキーワードを積極的に使用し、データ取得段階でセキュリティフィルタリングを行うことで、後続の Apex ロジックでの冗長なセキュリティチェックを減らし、コードを簡素化します。 Schema.DescribeFieldResultのキャッシュ:複数の場所で同じフィールドの FLS をチェックする必要がある場合、一度取得したSchema.DescribeFieldResultオブジェクトを変数に格納し、再利用することで、Describe API の呼び出し回数を減らし、効率を高めます。
よくある質問 FAQ
Q1:Field-Level Security (FLS) とページレイアウト(Page Layout)の「非表示」設定の違いは何ですか?
A1:FLS はデータアクセスそのものを制御するセキュリティ機能です。FLS で参照権限がないフィールドは、データとしてアクセスできず、ユーザーインターフェース(UI)にも表示されません。一方、ページレイアウトの「非表示」設定は、UI上での表示を制御するのみで、裏側のデータアクセス権限は影響しません。FLS でアクセスを拒否されているフィールドは、たとえページレイアウトで「表示」に設定されていても、ユーザーには見えません。セキュリティの観点からは FLS が優先されます。
Q2:Apex で FLS を考慮せずにデータを操作するとどうなりますか?
A2:Apex クラスが without sharing で定義されている場合、あるいは WITH SECURITY_ENFORCED なしで SOQL や DML 操作を行う場合、現在の実行ユーザーの FLS 設定を無視してデータにアクセスできてしまう可能性があります。これは重大なセキュリティホールにつながるため、特別な理由がない限り with sharing を使用し、SOQL には WITH SECURITY_ENFORCED を含めるべきです。アクセス権限のないフィールドを更新しようとすると、DML 操作時に System.DmlException が発生する場合があります。
Q3:FLS の設定ミスを防ぎ、組織のセキュリティを向上させるには、どのような監視指標を確認すべきですか?
A3:FLS の設定ミスは、ユーザーからの「データが見えない」「更新できない」といった報告や、監査ログから特定できます。監視指標としては、まずプロファイルと権限セットの割り当て状況を定期的にレビューすることです。特に、機密フィールドへのアクセスを持つ権限セットが意図しないユーザーに付与されていないかを確認します。次に、セットアップ監査履歴(Setup Audit Trail)で、プロファイルや権限セットの変更履歴を追跡します。これにより、誰がいつ FLS に影響を与える変更を行ったかを把握できます。さらに、Apex デバッグログで isAccessible() や isUpdateable() の結果を確認し、意図したセキュリティチェックが機能しているかを検証することも重要です。
まとめと参考資料
Field-Level Security (FLS) は、Salesforce 環境におけるデータプライバシーとセキュリティの要です。Salesforce コンサルタントとして、私はお客様が FLS を適切に設計・実装することで、法的規制の遵守、企業秘密の保護、そしてユーザーエクスペリエンスの最適化を実現できることを常に強調しています。宣言的な設定と Apex によるプログラム的なチェックを組み合わせることで、堅牢かつ柔軟なセキュリティモデルを構築できます。
- FLS は、オブジェクト内の個々のフィールドに対する参照・編集アクセスを制御する。
- プロファイルと権限セットを通じて設定され、役割ベースのアクセス制御を可能にする。
- Apex からは
isAccessible()/isUpdateable()メソッドや SOQL のWITH SECURITY_ENFORCEDキーワードで FLS を確認・強制できる。 - データプライバシー規制の遵守や機密情報の保護において不可欠な機能である。
- ページレイアウトの表示制御とは異なり、データアクセスそのものを制限する。
公式リソース
- 📖 公式ドキュメント:フィールドレベルセキュリティの設定
- 📖 公式ドキュメント:Securing Data with the Enforced Sharing and CRUD and FLS Enforcement Keywords
- 🎓 Trailhead モジュール:データセキュリティ
コメント
コメントを投稿