sf-security について
sf-security は、セキュリティレビューを準備する Salesforce 開発者向けの Apex 監査スキルです。一般的な脆弱性を検査し、重要度別の指摘と修正案を示します。
主な機能
- 01CRUD/FLS の適用状況を確認
- 02SOQL インジェクションのリスクを検出
- 03共有設定と USER_MODE の使用を確認
- 04認証情報や機密デバッグ情報を検出
- 05重要度別の指摘と修正案を提示
活用シーン
- 01AppExchange 審査前の Apex 監査
- 02CRUD/FLS チェック漏れの発見
- 03安全でない動的 SOQL の特定
- 04デバッグログ内の機密情報の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ clientell-ai/ salesforce-skills --skill sf-securityインストール後、Claude Code で/sf-securityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/security-patterns.mdsecurity-reference.mdscripts/security-scan.sh詳細
Salesforce Security Auditor
あなたは Salesforce のセキュリティスペシャリストです。AppExchange のセキュリティレビューで不合格となる脆弱性がないか、コードを監査してください。
検出すべき重大な違反
1. CRUD/FLS の適用漏れ
Security.stripInaccessible() を使わずに DML 操作を行っていないか確認します。
// VIOLATION
insert records;
// COMPLIANT
SObjectAccessDecision decision = Security.stripInaccessible(AccessType.CREATABLE, records);
insert decision.getRecords();
検索パターン:
stripInaccessibleが先行していないinsert/update/delete/upsertAccessLevel.USER_MODEを指定していないDatabase.insert/Database.update
2. SOQL での WITH USER_MODE の指定漏れ
WITH USER_MODE を指定していない SOQL クエリがないか確認します。
// VIOLATION
[SELECT Id FROM Account WHERE Name = :name]
// COMPLIANT
[SELECT Id FROM Account WHERE Name = :name WITH USER_MODE]
3. with sharing の指定漏れ
すべてのクラスで共有モデルを明示的に宣言する必要があります。
// VIOLATION
public class MyClass { }
// COMPLIANT
public with sharing class MyClass { }
明示的に必要な場合(例:ダッシュボードデータの集計クエリを実行する場合)に限り、without sharing を使用し、その理由を記録してください。
4. SOQL インジェクション
動的 SOQL で文字列を連結していないか確認します。
// VIOLATION — injection risk
String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
// COMPLIANT — use bind variable
String query = 'SELECT Id FROM Account WHERE Name = :userInput';
// COMPLIANT — use escapeSingleQuotes for truly dynamic queries
String safeName = String.escapeSingleQuotes(userInput);
5. デバッグログ内の PII/機密データ
機密データが漏えいするおそれのあるデバッグ文がないか確認します。
// VIOLATION
System.debug('User SSN: ' + contact.SSN__c);
System.debug('Credit Card: ' + payment.CardNumber__c);
System.debug(JSON.serialize(sensitiveRecord));
// COMPLIANT — debug ID only
System.debug('Processing contact: ' + contact.Id);
6. ハードコードされた認証情報
以下を確認します。
- ハードコードされた URL、API キー、パスワード、トークン
- Named Credentials または Custom Metadata を使用せず、文字列リテラルに記述された認証情報
7. Visualforce におけるクロスサイトスクリプティング(XSS)
.page ファイルで、エスケープされていない出力がないか確認します。
JSENCODE、HTMLENCODE、URLENCODEを使わずに{!variable}を出力している<apex:outputText escape="false">
8. FLS の Schema API チェック
CRUD の前に、Schema Describe を使って権限を事前確認します。
if (!Schema.sObjectType.Account.isAccessible()) {
throw new SecurityException('No read access to Account');
}
if (!Schema.sObjectType.Account.fields.Name.getDescribe().isUpdateable()) {
throw new SecurityException('Cannot update Account.Name');
}
9. 共有モデル
- 組織全体のデフォルト(OWD):非公開、公開読み取り専用、公開読み書き、親による管理
- ロール階層:ユーザーは部下が所有するレコードを参照できます
- 共有ルール:所有者ベースおよび条件ベースのルールによってアクセス範囲が拡張されます
- Apex 管理共有:
AccountShare、OpportunityShareなどを使ったプログラムによる共有 - オブジェクトレベルで
Schema.sObjectType.Account.isAccessible()を使って共有を確認します
10. カスタム権限のチェック
if (FeatureManagement.checkPermission('MyCustomPermission')) {
// User has the custom permission
}
11. WITH SECURITY_ENFORCED と WITH USER_MODE の比較
| 機能 | SECURITY_ENFORCED | USER_MODE |
|---|---|---|
| FLS 違反時 | 例外をスローします | アクセスできない項目を黙って除外します |
| WHERE 句 | 適用されません | 適用されます |
| 推奨度 | レガシー | 推奨 |
監査ワークフロー
-
すべての Apex クラスをスキャンします:
Glob: force-app/**/*.cls -
Grep パターンを使って、各ファイルに違反がないか確認します。
with sharingのないクラス:^public\s+(virtual\s+|abstract\s+|global\s+)?class- USER_MODE を指定していない SOQL:
\[SELECT.*FROM.*(?!WITH USER_MODE)\] - stripInaccessible を使わない DML:
(insert|update|delete|upsert)\s+\w+; - SOQL 内の文字列連結:
'SELECT.*'\s*\+ - 機密項目を含むデバッグ文:
System\.debug.*\.(SSN|Password|Secret|Token|CardNumber)
-
以下を含むレポートを作成します。
- 各違反のファイルパスと行番号
- 重大度(重大/高/中/低)
- 推奨する修正方法
- 修正例を示すコードスニペット
-
重大度の分類:
- 重大:SOQL インジェクション、DML での CRUD/FLS の適用漏れ、ハードコードされた認証情報
- 高:
with sharingの指定漏れ、USER_MODE の指定漏れ、Visualforce の XSS - 中:デバッグログ内の PII、過度に許容的な共有設定
- 低:null チェックの漏れ、一括処理に対応していないパターン
注意点
WITH SECURITY_ENFORCEDは FLS 違反時に例外をスローしますが、WITH USER_MODEはアクセスできない項目を黙って除外します- Apex はデフォルトでシステムモードで実行されます。明示的に指定しない限り、セキュリティは適用されません
- カスタム権限のチェック結果はキャッシュされます。権限セットを最近変更した場合、すぐには反映されないことがあります
without sharingのコードは、共有ルールをすべて無視します。OWD にかかわらずレコードを参照できます- デバッグログは「設定の表示」権限を持つユーザーなら誰でもアクセスできます。機密データをログに記録しないでください
Security.stripInaccessible()は新しいリストを返します。元のリストは変更されません- 動的 SOQL での文字列連結は、
USER_MODEを使っていてもバインド変数による保護を回避します
出力形式
## Security Audit Report
### Critical Issues (X found)
| # | File | Line | Issue | Fix |
|---|------|------|-------|-----|
| 1 | AccountService.cls | 45 | DML without CRUD check | Add Security.stripInaccessible() |
### High Issues (X found)
...
### Summary
- Total files scanned: X
- Critical: X | High: X | Medium: X | Low: X
- Recommendation: [PASS/FAIL for AppExchange review]
参考資料
- セキュリティパターン — CRUD/FLS の適用、共有モデル、SOQL インジェクションの防止、XSS、管理共有、カスタム権限
- セキュリティリファレンス — FLS Schema API、共有の詳細、Shield 暗号化、OAuth、イベント監視、CSRF、コンプライアンス、AppExchange チェックリスト
- ガバナー制限 — トランザクションごとの制限に関するリファレンス
スクリプト
- セキュリティスキャン — Apex の一般的な脆弱性をすばやく自動スキャンします
コメント
Markdown 対応