税理士・社労士・司法書士・弁護士事務所向け:
顧問先のマイナンバー・財務・労務データを守るSCS★3水準のセキュリティ設計
この記事の要点と4つの章のご案内
| 章構成 | 主なテーマ | 要点と確認ポイント |
|---|---|---|
| 1. 基本と全体像 | なぜ士業事務所がサプライチェーン攻撃の「最優先ターゲット」にされるのか? | 士業事務所は「数百社分の決算書・給与台帳・マイナンバー・登記・訴訟資料」が集まる最重要拠点であり、顧問先の大手・中堅企業からSCS評価制度「3」の取得を求められるケースが急増しています。 |
| 2. 現場での進め方と対策 | 士業事務所における「従来のファイル管理」と「SCS★3準拠の貸金庫設計」の比較 | 士業で最も警戒すべき事故は「別の顧問先への試算表・給与明細メール誤送信」と「所内NASのランサムウェア全件暗号化」であり、顧問先別ポータル隔離と不変バックアップで根本から防げます。 |
| 3. 関連する制度とルール | 繁忙期でも無理なく移行できる「士業事務所のSCS★3 実践3ステップ」 | 自事務所がSCS★3を取得するだけでなく、顧問先の中小企業から「取引先にSCS★3を求められたがどうすればいいか」と相談された際の頼れる助言者になることができます。 |
| 4. 詳しい技術仕様としくみ | 顧問先企業からの「うちもSCS★3を取りたい」「高額なUTM見積もりが来た」という相談に応える | はい、十分対応可能です。企業法務・労務・税務を委託する大企業や中堅企業が最も重視しているのは、「自社の未公開決算情報・役員報酬・従業員のマイナンバー・係争資料が、他の顧問先のデータと混ざったり漏れたりしないか」という点です。クラウド会計・労務への多要素認証(パスキー)、顧問先別フォルダのアクセス権分離、そして書き換え不能バックアップの3点を整えれば、高価な設備なしで3水準の証跡を提示できます。 |
- 01. 士業事務所は「数百社分の決算書・給与台帳・マイナンバー・登記・訴訟資料」が集まる最重要拠点であり、顧問先の大手・中堅企業からSCS評価制度「3」の取得を求められるケースが急増しています。
- 02. 士業で最も警戒すべき事故は「別の顧問先への試算表・給与明細メール誤送信」と「所内NASのランサムウェア全件暗号化」であり、顧問先別ポータル隔離と不変バックアップで根本から防げます。
- 03. 自事務所がSCS★3を取得するだけでなく、顧問先の中小企業から「取引先にSCS★3を求められたがどうすればいいか」と相談された際の頼れる助言者になることができます。
01. なぜ士業事務所がサプライチェーン攻撃の「最優先ターゲット」にされるのか?
攻撃者の視点から見ると、1社ずつ中小企業や上場企業を攻撃するよりも、「100社〜500社の顧問先企業の決算書・源泉徴収票・社会保険手続き・M&A契約書・株主名簿を一括で預かっている士業事務所」のサーバー1台に侵入する方が、はるかに多くの機密情報を奪うことができます。
実際に国内外では、法律事務所や会計事務所のファイルサーバーがランサムウェアに感染し、確定申告期や年度末決算の直前に過去数年分の申告データや労務台帳が開けなくなる事案が発生しています。そのため2026年からのSCS評価制度(★3)では、製造業の下請けだけでなく、財務・労務・法務データを預かる専門職(士業事務所)に対しても同等のセキュリティ基準が求められています。
士業事務所の情報管理とSCS★3に関する3つの重要データ
番号法(マイナンバー法)および個人情報保護委員会の規則により、特定個人情報の漏洩や滅失・毀損のおそれは、規模を問わず厳格な安全管理措置と速やかな報告が義務付けられています。
「A社様へ送るべき試算表や給与明細PDFを、名前が似たB社様のメールに添付してしまった」という人的ミスは、メール添付をやめて顧問先別専用ボックスにすることで構造的にゼロにできます。
2〜3月の確定申告期、5月決算、6〜7月の労働保険年度更新・算定基礎届の時期には1日のシステム停止も許されません。不変バックアップからの即時復旧体制が生命線です。
ひと目でわかる構造図解:顧問先ごとの「貸金庫型データ隔離」と「誤送信ゼロのクライアントポータル」
02. 士業事務所における「従来のファイル管理」と「SCS★3準拠の貸金庫設計」の比較
所員の先生方やスタッフの業務効率を落とさず、むしろ「毎月の資料回収と試算表・給与明細の配布が楽になる」形でSCS★3の要件を満たす比較表です。
| 士業の主要業務 | ヒヤリハットや指摘が起きやすい従来の運用 | SCS★3・番号法を満たす推奨設計 |
|---|---|---|
| 01 試算表・給与明細・契約書の送付 | メールにパスワード付きZIP(PPAP)を添付して送信(宛先ミス時に取り消し不能)。 | 顧問先ごとの専用共有ボックスへ格納し、通知メールのみ自動送信(誤送信リスクを構造的に排除)。 |
| 02 所内ファイルサーバーの権限設計 | パート・アルバイトを含む全員が全顧問先(数百社分)のフォルダを閲覧・コピー可能。 | 主担当・副担当・審査役のみアクセスできる権限分離+マイナンバー区画の完全隔離。 |
| 03 クラウド会計・電子申告(e-Tax/e-Gov) | IDとパスワードだけでログインし、ブラウザにパスワードを保存したまま共有。 | FIDO2パスキー(生体認証)または多要素認証を100%強制し、退職者の権限は当日中に失効。 |
| 04 巡回監査用ノートPCの持ち出し | ノートPC内のDドライブに複数顧問先の弥生・TKC・申告データをそのまま保存して移動。 | フルディスク暗号化(BitLocker/FileVault)強制+ローカル保存を最小化し紛失時3分遠隔ワイプ。 |
03. 繁忙期でも無理なく移行できる「士業事務所のSCS★3 実践3ステップ」
月次監査や手続き業務を止めずに、3週間程度でSCS★3の要求水準を整えるための実践ステップです。
ステップ 01:全所員のPC暗号化と、クラウド会計・労務・メールへの「パスキー(多要素認証)」を設定する
まずは所内で使用しているすべてのパソコン(巡回監査用ノートPCを含む)でディスク暗号化(BitLocker / FileVault)が有効になっているかを確認し、管理台帳に記載します。同時に、メール(Microsoft 365 / Google Workspace)およびクラウド会計・労務ソフトへのログインに、フィッシングに強いパスキー(FIDO2生体認証)を設定します。
ステップ 02:メールでのZIP添付(PPAP)をやめ、「顧問先別専用フォルダ」での授受に統一する
顧問先ごとに独立したクラウド共有フォルダ(またはクライアントポータル)を用意し、月次の試算表、総勘定元帳、賃金台帳、就業規則案、登記完了証などはすべてその専用フォルダ内で受け渡すルールに切り替えます。これにより、「うっかり別の顧問先を宛先に入れて添付送信してしまう事故」が物理的に起こらなくなります。
ステップ 03:申告・決算・訴訟データの「書き換え不能バックアップ」と所内AI利用ルールを整える
所内サーバーやクラウド上の重要データを、ランサムウェアが原則として上書きできない「不変スナップショット保管庫」へ毎日自動退避します。さらに、所員が生成AIを活用する際の安全ルール(無料版への顧問先情報入力禁止・学習オフの法人環境のみ使用可)をA4・1枚の規程として明文化し、ホームページに情報セキュリティ基本方針を公開します。
04. 顧問先企業からの「うちもSCS★3を取りたい」「高額なUTM見積もりが来た」という相談に応える
中小企業の経営者が取引先から「SCS★3の取得要請」を受けたり、訪問販売業者から「200万円のセキュリティ機器リース」を迫られたりした際、真っ先に相談するのは最も身近な相談相手である顧問税理士・顧問社労士・顧問弁護士の先生方です。
顧問先企業が不必要な高額リース契約を結んでしまう前に、当社の登録情報処理安全確保支援士へお繋ぎいただくことで、適正コストでのSCS★★3取得とIT導入補助金・厚労省助成金の活用をサポートできます。
電子帳簿保存法・インボイス制度への対応と、契約書(freeeサイン)・請求書(freee会計)のデジタル化をセキュリティ対策と同時に進めることで、事務所側の記帳・監査工数も大幅に削減できます。
現場で陥りやすい落とし穴と回避策(士業事務所編)
所内の共有フォルダに「顧問先ログインID・パスワード一覧.xlsx」が置かれていると、万が一1台のPCがウイルス感染した際に全顧問先のアカウントが乗っ取られます。【回避策】顧問先自身のIDを共有するのではなく、必ず「会計事務所向けアドバイザー権限(招待機能)」で連携し、秘密情報は暗号化されたパスワード管理ツールへ移行しましょう。
確定申告期や年度更新の時期に、「【重要】電子申告データの再提出のお願い」といった本物そっくりの偽メールが士業事務所を狙って送られます。【回避策】メール内のリンクからは原則としてログインせず、必ずいつものブックマークまたは公式ソフトからメッセージボックスを確認する習慣を一貫してください。
人の入れ替わりがある時期に、チャットツールや共有フォルダのアカウント削除が漏れるケースが目立ちます。【回避策】「入退所時のアカウント付与・即日失効チェックリスト」を作成し、月1回の棚卸し記録を残すことでSCS★3の必須項目をクリアできます。
30秒でできる!士業事務所のSCS★3&守秘義務保護セルフチェック(3項目)
該当する項目にチェックを入れると、現在の状況と優先ステップが表示されます(ブラウザ内でのみ動作します)。
理解を深める確認クイズ(士業事務所の守秘義務・データ隔離編)
Q. 税理士事務所や社労士事務所で毎月発生する「顧問先への試算表・給与明細PDFの受け渡し」において、メール誤送信による情報漏洩を100%防ぎつつSCS★3に適合する方法はどれでしょうか?
選択肢 A:メール送信前に所員2人で宛先メールアドレスを指差し確認してからパスワード付きZIPを送る クリックして解説を見る →
ダブルチェックは大切ですが、繁忙期には人間の目視確認だけではどうしてもミスが起きてしまいます。
さらに、一度送信してしまったメール添付ファイルは後から回収できないため、注意力に頼るのではなく「仕組み(選択肢B)」で防ぐことが重要です。
選択肢 B:メールにファイルを一切添付せず、多要素認証と行レベル権限分離で守られた「顧問先専用ポータル(共有金庫)」へ格納する クリックして解説を見る →
大正解です!これが士業事務所における最も確実で効率的な解決策です。
A社様の専用ボックスにはA社様のログインID(パスキー)でしか入れないため、他社へ誤送信されるリスクが構造的に消滅し、万が一差し替えが必要な場合もその場で即座にファイルを更新・停止できます。
選択肢 C:全顧問先のPDFを1つの共有フォルダに入れ、ファイル名に各社のパスワードを書いておく クリックして解説を見る →
原則として避けてください!
「どの企業が顧問先にいるか」という一覧が見えること自体が守秘義務上の大きな問題になります。必ず顧問先1社ごとに構造的に分離された領域(選択肢B)を使用しましょう。
近江商人の「大福帳(だいふくちょう)・三方よし」と、現代の追記型データベース監査証跡
江戸時代の近江商人や両替商が用いた複式帳簿(大福帳・本帳)は、火災の際に真っ先に井戸や土蔵へ投げ込んで守れるよう丈夫な和紙と墨で記され、一度書いた数字を削り取って書き換えることは厳しく禁じられていました(訂正時は必ず朱線で消し、履歴を残すルール)。現代の電子帳簿保存法やSCS★3で求められる「追記型監査ログと書き換え不能(イミュータブル)ストレージ」は、まさに日本の商人と会計人が受け継いできた「誠実な帳面の心」を現代の暗号技術で再現したものなのです。
士業事務所様向け SCS★★3取得・顧問先支援パートナーのご案内
自事務所のセキュリティ強化から、顧問先企業へのSCS★3・freee導入・補助金活用の共同支援まで、登録情報処理安全確保支援士が伴走します。
場面別の実務確認ポイント
資格法上の守秘義務・マイナンバー安全管理措置とSCS★3を一体で満たし、事務所の社会的信用を高める経営判断のポイントがわかります。
顧問先との資料のやり取りで「誤送信を物理的にゼロにする方法」と、外出先でのノートPC保護手順(第2章)を解説しています。
e-Tax・e-Gov・freee・マネーフォワード・弥生・TKC等のID管理と、退職所員のアカウント即日失効リストの作り方が確認できます。
技術仕様セクションにて、PostgreSQL 19 FORCE RLSによる顧問先別分離と、HKDF-SHA256 + AES-256-GCM エンベロープ暗号化のRust実装を公開しています。
士業マルチテナント基盤における PostgreSQL 19 FORCE ROW LEVEL SECURITY 強制隔離と HKDF-SHA256 / AES-256-GCM 顧問先別エンベロープ暗号化
本モノグラフでは、税理士・社労士・法律事務所が数百社の顧問先データ(特定個人情報・財務諸表・労働条件通知書・訴訟証拠)を単一基盤上で安全に処理し、SCS評価制度(3〜4)および番号法ガイドラインのアクセス制御・暗号化要件を証明するため、(1) PostgreSQL 19 の ENABLE / FORCE ROW LEVEL SECURITY によるアプリケーションバグ耐性のある行レベル隔離、(2) RFC 5869 (HKDF-SHA256) を用いた顧問先ごとのデータ暗号化鍵(DEK)導出と AES-256-GCM 認証付き暗号(AEAD)における関連データ(AAD)束縛を定式化する。
01. PostgreSQL 19 FORCE ROW LEVEL SECURITY によるテナント越境(Cross-Tenant Leak)の数学的遮断:
Webアプリケーション層の WHERE client_tenant_id = 1 句のみに依存する設計は、ORMのクエリ組み立てミスやJOIN漏れによって他顧問先のレコードが混入するリスクを抱える。これに対し、データベースエンジン層で ALTER TABLE client_ledgers ENABLE ROW LEVEL SECURITY; ALTER TABLE client_ledgers FORCE ROW LEVEL SECURITY; を宣言し、トランザクション開始時に SET LOCAL app.current_client_id = '...' および SET LOCAL app.current_staff_id = '...' を束縛する。ポリシー述語 P(r) ⇔ (r.client_id = current_setting('app.current_client_id')::uuid) ∧ ∃ a ∈ Assignments(a.staff_id = current_staff ∧ a.client_id = r.client_id)$ が真である行のみが射影・更新されるため、万が一上位コードでWHERE句が欠落しても他顧問先の行は0件となる。
02. 顧問先別エンベロープ暗号化と AAD(Additional Authenticated Data)によるCiphertext移植攻撃の防止: 特定個人情報(マイナンバー)や未公開M&A資料の暗号化において、全顧問先で単一の暗号鍵を共有すると、データベースダンプや暗号文のコピー(Ciphertext Transplanting:顧問先Bの行の暗号文カラムを、自分が閲覧権限を持つ顧問先Aの行へコピーして復号させる攻撃)が成立する。これを防ぐため、マスター鍵 KEK から顧問先固有ソルト S_client と用途コンテキストを用いて DEK_client = HKDF-Expand(HKDF-Extract(S_client, KEK), "OK-SCS★3-MYNUMBER-V1" ∥ client_uuid, 32) を導出し、さらに AES-256-GCM の関連データ(AAD)として AAD = client_uuid ∥ record_id ∥ column_tag を束縛する。これにより、異なる顧問先IDや別レコードへ移植された暗号文は GCM 認証タグ検証(GHASH)で100%拒絶される。
03. 特定個人情報のアクセス監査証跡(ハッシュチェーン): 番号法ガイドラインに基づき、「どの所員が、いつ、どの顧問先の特定個人情報を復号したか」のイベント E_n は、直前の監査レコードハッシュ H_n-1 を連結した H_n = BLAKE3(H_n-1 ∥ E_n) として追記専用テーブルへ記録され、事後的なログ一部削除を数学的に検出可能とする。
| Security Domain | Protected Data Class | Cryptographic / DB Control | Verification Invariant |
|---|---|---|---|
| Multi-Tenant RDBMS | Tax Ledgers / Payroll / Legal Matters | PostgreSQL 19 FORCE ROW LEVEL SECURITY | relrowsecurity=true && relforcerowsecurity=true |
| Column-Level Vault | 12-Digit Individual Number (MyNumber) | Per-Client DEK + AES-256-GCM with AAD | Cross-tenant decrypt attempt fails authentication tag |
| Client Document Exchange | Trial Balance PDF / Payslips / Contracts | FIDO2 Portal + Zero Email Attachment (No PPAP) | 0 outbound encrypted ZIP attachments on SMTP gateway |
| Immutable Audit Trail | MyNumber Read / Export / Delete Events | Chained Hash Log + OpenZFS Snapshot | Continuous hash chain integrity verification |
#![forbid(unsafe_code)]
use std::collections::BTreeSet;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaffSessionContext {
pub staff_id: u32,
pub fido2_verified: bool,
pub mynumber_handler_authorized: bool,
pub assigned_client_ids: BTreeSet<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SealedClientRecord {
pub client_id: u64,
pub record_id: u64,
pub aad_context_tag: [u8; 32],
pub ciphertext_payload: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProfVaultError {
Fido2MfaRequired,
MyNumberClearanceMissing,
ClientTenantNotAssigned { client_id: u64 },
AadContextMismatchTransplantDetected,
InvalidMyNumberLength,
InvalidMyNumberCheckDigit,
}
/// Computes a deterministic 32-byte Additional Authenticated Data (AAD) binding tag
/// over (firm_domain_sep, client_id, record_id) to prevent cross-client ciphertext transplanting.
pub fn compute_tenant_aad_binding(client_id: u64, record_id: u64) -> [u8; 32] {
let mut out = [0u8; 32];
let domain = b"OK-SCS★3-PROF-TENANT-AAD-V1::";
out[..16].copy_from_slice(&domain[..16]);
out[16..24].copy_from_slice(&client_id.to_be_bytes());
out[24..32].copy_from_slice(&record_id.to_be_bytes());
out
}
/// Verifies the official 12-digit Japanese Individual Number (MyNumber) Modulo-11 check digit
/// defined by Ministry of Internal Affairs and Communications Order No. 85.
pub fn verify_mynumber_check_digit(digits_ascii: &[u8]) -> Result<(), ProfVaultError> {
if digits_ascii.len() != 12 || !digits_ascii.iter().all(|b| b.is_ascii_digit()) {
return Err(ProfVaultError::InvalidMyNumberLength);
}
let mut sum: u32 = 0;
// Let n = 1..=11 from least significant payload digit (index 10 down to 0)
for n in 1..=11usize {
let p_n = u32::from(digits_ascii[11 - n] - b'0');
let q_n = if n <= 6 { (n + 1) as u32 } else { (n - 5) as u32 };
sum += p_n * q_n;
}
let remainder = sum % 11;
let expected_check = if remainder <= 1 { 0 } else { 11 - remainder };
let actual_check = u32::from(digits_ascii[11] - b'0');
if actual_check != expected_check {
return Err(ProfVaultError::InvalidMyNumberCheckDigit);
}
Ok(())
}
/// Enforces FIDO2 MFA, MyNumber handler clearance, per-client RLS assignment,
/// and constant-time AAD context binding before unsealing a client's sensitive record.
pub fn authorize_and_verify_client_record_access(
ctx: &StaffSessionContext,
record: &SealedClientRecord,
target_client_id: u64,
target_record_id: u64,
) -> Result<(), ProfVaultError> {
if !ctx.fido2_verified {
return Err(ProfVaultError::Fido2MfaRequired);
}
if !ctx.mynumber_handler_authorized {
return Err(ProfVaultError::MyNumberClearanceMissing);
}
if !ctx.assigned_client_ids.contains(&target_client_id) {
return Err(ProfVaultError::ClientTenantNotAssigned {
client_id: target_client_id,
});
}
let expected_aad = compute_tenant_aad_binding(target_client_id, target_record_id);
let mut diff: u8 = 0;
for (a, b) in record.aad_context_tag.iter().zip(expected_aad.iter()) {
diff |= a ^ b;
}
if diff != 0 || record.client_id != target_client_id || record.record_id != target_record_id {
return Err(ProfVaultError::AadContextMismatchTransplantDetected);
}
Ok(())
}