security-review-construction について
建設ソフトウェアや連携機能を構築するチーム向けのセキュリティレビュースキルです。財務、BIM/CAD、取引先、現場、文書データなどを守るためのガイダンスとチェックリストを提供します。
主な機能
- 01建設データ保護のガイダンス
- 02BIM/CAD セキュリティチェックリスト
- 03取引先・財務データの保護策
- 04現場データ収集の制御
- 05連携・文書のセキュリティ確認
- 06デプロイ前のレビューチェックリスト
活用シーン
- 01ERP や BIM 連携のセキュリティレビュー
- 02プロジェクト原価データの保護評価
- 03現場データ収集の保護策の確認
- 04建設システムのデプロイ準備
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill security-review-constructionインストール後、Claude Code で/security-review-constructionを入力して読み込まれたか確認します。
同梱ファイルclaw.jsoninstructions.md
詳細
建設システム向けセキュリティレビュースキル
このスキルは、すべての建設ソフトウェアシステムがセキュリティのベストプラクティスに従い、機密性の高いプロジェクトデータ、財務情報、ビジネスインテリジェンスを保護できるようにします。
有効化するタイミング
- ERP/BIM システムの連携を構築するとき
- 建設ダッシュボードを作成するとき
- コスト/財務データを扱うとき
- ドキュメント管理システムを構築するとき
- 現場データ収集用の API を作成するとき
- 外部プラットフォーム(Procore、PlanGrid など)と連携するとき
- 下請業者/ベンダーのデータを扱うとき
- 支払い申請を処理するとき
建設業界特有のセキュリティ上の懸念
1. 財務データの保護
# CRITICAL: Construction financial data security
# ❌ NEVER Do This
project_budget = 15000000 # Hardcoded in source
margin_percentage = 0.18 # Business-sensitive info in code
# ✅ ALWAYS Do This
import os
from cryptography.fernet import Fernet
# Load from secure configuration
project_config = load_secure_config(os.environ['PROJECT_CONFIG_PATH'])
# Encrypt sensitive data at rest
def encrypt_financial_data(data: dict) -> bytes:
key = os.environ.get('ENCRYPTION_KEY')
f = Fernet(key)
return f.encrypt(json.dumps(data).encode())
財務データのチェックリスト
- コスト見積もりが保存時に暗号化されている
- 利益率/上乗せ額のデータがログに露出していない
- 支払い情報がトークン化されている
- 過去の価格情報が競合他社から保護されている
- 入札額が開札まで安全に保護されている
2. BIM/CAD データのセキュリティ
# BIM data often contains proprietary design information
# ❌ NEVER store BIM directly in public cloud without encryption
s3.upload_file('model.ifc', bucket='public-bucket')
# ✅ ALWAYS encrypt and control access
def upload_bim_secure(file_path: str, project_id: str):
# Encrypt file
encrypted_path = encrypt_file(file_path)
# Generate pre-signed URL with expiration
presigned_url = s3.generate_presigned_url(
'get_object',
Params={
'Bucket': 'secure-bim-bucket',
'Key': f'{project_id}/{os.path.basename(file_path)}'
},
ExpiresIn=3600 # 1 hour expiration
)
# Log access
audit_log.info(f"BIM access granted: {project_id}")
return presigned_url
BIM/CAD のチェックリスト
- IFC/RVT ファイルが保存時に暗号化されている
- 監査証跡のためにアクセスが記録されている
- ダウンロードリンクに有効期限が設定されている
- アクセス履歴を追跡できるバージョン管理が行われている
- エラーメッセージに設計データが含まれていない
3. 下請業者/ベンダーのデータ
# Subcontractor data includes business-sensitive information
class SubcontractorDataHandler:
"""Secure handling of subcontractor data"""
# Fields that require encryption
SENSITIVE_FIELDS = [
'insurance_policy_number',
'bank_account',
'tax_id',
'bonding_capacity',
'historical_pricing'
]
def store_subcontractor(self, data: dict) -> str:
# Encrypt sensitive fields
for field in self.SENSITIVE_FIELDS:
if field in data:
data[field] = self.encrypt(data[field])
# Store with audit trail
sub_id = self.db.insert(data)
self.audit.log(f"Subcontractor created: {sub_id}")
return sub_id
def get_subcontractor(self, sub_id: str, requester_id: str) -> dict:
# Check authorization
if not self.can_access(requester_id, sub_id):
raise PermissionError("Unauthorized access to subcontractor data")
# Log access
self.audit.log(f"Subcontractor accessed: {sub_id} by {requester_id}")
# Return with decrypted sensitive fields (only to authorized users)
return self.decrypt_sensitive_fields(self.db.get(sub_id))
ベンダーデータのチェックリスト
- 保険/保証情報が暗号化されている
- 銀行口座情報が保護されている(PCI 準拠)
- UI で納税者番号がマスキングされている(末尾 4 桁のみ表示)
- 価格履歴へのアクセスが制御されている
- 証明書の有効期限通知が安全に行われている
4. 現場データ収集のセキュリティ
# Mobile/field data collection must be secure
from datetime import datetime, timedelta
import hashlib
class FieldDataCollector:
"""Secure field data collection"""
def validate_photo_submission(self, photo_data: dict) -> bool:
# Verify GPS timestamp is recent (within 24 hours)
photo_time = datetime.fromisoformat(photo_data['timestamp'])
if datetime.now() - photo_time > timedelta(hours=24):
raise ValueError("Photo timestamp too old - possible replay attack")
# Verify file hash matches
file_hash = hashlib.sha256(photo_data['content']).hexdigest()
if file_hash != photo_data['declared_hash']:
raise ValueError("File integrity check failed")
# Validate GPS coordinates are within project boundary
if not self.is_within_project_bounds(
photo_data['lat'],
photo_data['lon'],
photo_data['project_id']
):
self.audit.warn(f"Photo from outside project bounds: {photo_data}")
return True
def submit_daily_report(self, report: dict, user_id: str) -> str:
# Verify user is assigned to project
if not self.is_assigned_to_project(user_id, report['project_id']):
raise PermissionError("User not assigned to this project")
# Sign report with user credentials
report['signature'] = self.sign_report(report, user_id)
report['submitted_at'] = datetime.now().isoformat()
return self.db.insert(report)
現場データのチェックリスト
- GPS データの妥当性が検証されている
- 写真のタイムスタンプが検証されている
- ファイル整合性チェックが行われている(ハッシュ化)
- 提出時にユーザー認証が行われている
- オフラインデータの同期が保護されている
5. CWICR データベースのセキュリティ
# CWICR contains proprietary cost data
class CWICRAccessControl:
"""Access control for CWICR database"""
TIERS = {
'basic': ['public_rates', 'standard_descriptions'],
'professional': ['regional_rates', 'productivity_factors'],
'enterprise': ['custom_rates', 'historical_data', 'analytics']
}
def search(self, query: str, user_id: str) -> list:
# Get user tier
tier = self.get_user_tier(user_id)
# Limit results based on tier
allowed_fields = self.TIERS[tier]
# Execute search with field restrictions
results = self.vector_search(
query=query,
fields=allowed_fields,
limit=self.get_tier_limit(tier)
)
# Log search for analytics
self.audit.log(f"CWICR search: {user_id}, query='{query[:50]}...'")
return results
def export_data(self, user_id: str, format: str) -> bytes:
# Enterprise only
if self.get_user_tier(user_id) != 'enterprise':
raise PermissionError("Export requires enterprise tier")
# Watermark exported data
data = self.get_exportable_data(user_id)
watermarked = self.add_watermark(data, user_id)
return watermarked
CWICR のチェックリスト
- 階層型アクセス制御が実装されている
- ユーザー/階層ごとに API レート制限が設定されている
- データのエクスポートに透かしが入れられている
- 一括ダウンロードが制限されている
- 競合他社によるアクセスが監視されている
6. 連携のセキュリティ(Procore、PlanGrid など)
# Secure OAuth integration with construction platforms
class ConstructionPlatformIntegration:
"""Secure integration with external platforms"""
def __init__(self, platform: str):
self.platform = platform
# Load credentials from secure vault
self.credentials = self.vault.get(f'{platform}_oauth')
def authenticate(self) -> str:
# Use OAuth 2.0 with PKCE
code_verifier = secrets.token_urlsafe(32)
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).decode().rstrip('=')
# Never store tokens in code or logs
token = self.oauth_flow(code_verifier, code_challenge)
# Store token securely
self.secure_token_store.set(
key=f'{self.platform}_token',
value=token,
ttl=token['expires_in']
)
return token
def sync_data(self, project_id: str) -> dict:
# Validate project access before sync
if not self.has_project_access(project_id):
raise PermissionError(f"No access to project {project_id}")
# Rate limit syncs
self.rate_limiter.check(f'sync_{self.platform}')
# Sync with retry and error handling
try:
data = self.api_client.get_project_data(project_id)
self.validate_incoming_data(data)
return data
except APIError as e:
# Log error without sensitive details
self.logger.error(f"Sync failed for {project_id}: {type(e).__name__}")
raise
連携のチェックリスト
- PKCE を使用した OAuth 2.0 が実装されている
- トークンが安全な保管庫に保存されている(環境変数には保存しない)
- トークンの更新が自動化されている
- API レート制限が遵守されている
- Webhook の署名が検証されている
- 受信データの検証が行われている
7. ドキュメント管理のセキュリティ
# Construction documents often contain confidential information
class SecureDocumentManager:
"""Secure document handling for construction"""
# Document classification levels
CLASSIFICATIONS = {
'public': [],
'internal': ['daily_reports', 'schedules'],
'confidential': ['contracts', 'bids', 'financials'],
'restricted': ['legal', 'hr', 'insurance']
}
def upload_document(self, file: bytes, metadata: dict, user_id: str) -> str:
# Scan for malware
if not self.malware_scan(file):
raise SecurityError("Malware detected in uploaded file")
# Classify document
classification = self.classify_document(metadata)
# Check user can upload to this classification
if not self.can_upload(user_id, classification):
raise PermissionError(f"Cannot upload {classification} documents")
# Encrypt based on classification
if classification in ['confidential', 'restricted']:
file = self.encrypt(file)
# Store with audit trail
doc_id = self.storage.put(file, metadata)
self.audit.log(f"Document uploaded: {doc_id} by {user_id}")
return doc_id
def download_document(self, doc_id: str, user_id: str) -> bytes:
# Check access
doc = self.storage.get_metadata(doc_id)
if not self.can_access(user_id, doc['classification']):
raise PermissionError("Access denied")
# Log download
self.audit.log(f"Document downloaded: {doc_id} by {user_id}")
# Return decrypted content
return self.decrypt(self.storage.get(doc_id))
ドキュメントのチェックリスト
- アップロード時にマルウェアスキャンが行われている
- ドキュメント分類システムが導入されている
- ロールベースのアクセス制御が実装されている
- ダウンロードの監査ログが記録されている
- 機密ドキュメントが暗号化されている
- 保持ポリシーが適用されている
建設システムのデプロイ前セキュリティチェックリスト
データ保護
- 財務データが保存時と転送時に暗号化されている
- BIM/CAD ファイルがアクセス制御によって保護されている
- 下請業者の PII が保護されている(GDPR/CCPA 準拠)
- CWICR データへのアクセスが適切な階層に分けられている
- バックアップの暗号化が有効になっている
認証と認可
- 管理者ユーザーに多要素認証が設定されている
- ロールベースのアクセス制御が実装されている
- セッション管理が安全である(タイムアウト、単一デバイス)
- API キーが定期的にローテーションされている
- OAuth 連携で PKCE が使用されている
監査とコンプライアンス
- すべてのデータアクセスが記録されている
- ログが改ざん防止されている(追記専用)
- 保持ポリシーが文書化されている
- 監査用のデータエクスポート機能がある
- コンプライアンスレポートが自動化されている
連携のセキュリティ
- すべての外部 API が認証されている
- Webhook の署名が検証されている
- すべての入力データが検証されている
- レート制限が実装されている
- エラーメッセージがサニタイズされている
現場データのセキュリティ
- モバイルアプリで証明書ピンニングが使用されている
- オフラインデータが暗号化されている
- GPS/タイムスタンプが検証されている
- 写真の整合性が検証されている
- 同期プロトコルが安全である
リソース
忘れないでください:建設データには、財務、法務、競争に関する情報が含まれます。情報漏えいは、入札の失注、法的責任、評判の毀損につながる可能性があります。セキュリティは任意ではありません。
コメント
Markdown 対応