Assessor_2.0/src/domain/microsoft-security-baseline...

85 lines
4.6 KiB
TypeScript

import type { AdmxPolicyCatalog, GpoPolicyIdentityResolution } from './gpo-policy-identity';
import type { GpoPolicyObservation } from './gpo-policy';
export const MICROSOFT_BASELINE_SETTINGS_ANALYZER = {
id: 'microsoft-baseline-gpo-settings',
version: '1.4.0'
} as const;
export interface MicrosoftSecurityBaselineSetting {
version: 1;
id: string;
baselineId: string;
backupId: string;
template?: {
names: Array<{ value: string; sourcePath: string; sourceSha256: string }>;
context?: { productFamily: string; productVersion: string; role: 'Client' | 'Member Server' | 'Domain Controller' };
};
observation: Pick<GpoPolicyObservation,
'sourcePath' | 'sourceSha256' | 'scope' | 'deliveryMechanism' | 'parser' | 'reducer' | 'state' | 'values'
| 'registryPolicy' | 'sourceLines' | 'sourceRecords' | 'effectiveState' | 'diagnosticCodes'>;
identity: GpoPolicyIdentityResolution;
}
export interface MicrosoftSecurityBaselineAnalysis {
version: 1;
id: string;
baselineId: string;
packageSha256: string;
analyzer: { id: typeof MICROSOFT_BASELINE_SETTINGS_ANALYZER.id; version: '1.0.0' | '1.1.0' | '1.2.0' | '1.3.0' | '1.4.0' };
analyzedAt: string;
status: 'complete' | 'partial';
admxCatalog: AdmxPolicyCatalog;
backupCount: number;
registryPolicyFileCount: number;
settings: MicrosoftSecurityBaselineSetting[];
diagnosticCodes: string[];
}
export interface StoredMicrosoftSecurityBaselineAnalysis {
version: 1;
analysis: MicrosoftSecurityBaselineAnalysis;
supersedesAnalysisId?: string;
}
export function microsoftSecurityBaselineAnalysisValidationErrors(analysis: MicrosoftSecurityBaselineAnalysis): string[] {
const errors: string[] = [];
if (analysis.version !== 1 || !analysis.id.trim() || !analysis.baselineId.trim() || !/^[a-f0-9]{64}$/.test(analysis.packageSha256)
|| analysis.analyzer.id !== MICROSOFT_BASELINE_SETTINGS_ANALYZER.id
|| !['1.0.0', '1.1.0', '1.2.0', '1.3.0', '1.4.0'].includes(analysis.analyzer.version)
|| !Number.isFinite(Date.parse(analysis.analyzedAt)) || analysis.admxCatalog.source.baselineId !== analysis.baselineId
|| analysis.admxCatalog.source.packageSha256 !== analysis.packageSha256) {
errors.push('Die Microsoft-Baselineanalyse besitzt ungültige Identität oder Provenienz.');
}
if (![analysis.backupCount, analysis.registryPolicyFileCount].every(value => Number.isSafeInteger(value) && value >= 0)
|| new Set(analysis.settings.map(setting => setting.id)).size !== analysis.settings.length) {
errors.push('Die Microsoft-Baselineanalyse besitzt ungültige Zählwerte oder doppelte Einstellungen.');
}
for (const setting of analysis.settings) {
const template = setting.template;
if (template && (!Array.isArray(template.names) || template.names.some(name => typeof name.value !== 'string'
|| !name.value.trim() || name.value.length > 2048 || typeof name.sourcePath !== 'string' || !name.sourcePath.trim()
|| !/^[a-f0-9]{64}$/.test(name.sourceSha256))
|| (template.context && (!template.names.length || !['Client', 'Member Server', 'Domain Controller'].includes(template.context.role)
|| !template.context.productFamily?.trim() || !template.context.productVersion?.trim())))) {
errors.push('Die Baselinevorlage besitzt ungueltige Namen, Rollen oder Quellenreferenzen.');
}
if (setting.version !== 1 || !setting.id.trim() || setting.baselineId !== analysis.baselineId || !setting.backupId.trim()
|| !['registry-policy', 'security-template', 'advanced-audit-policy'].includes(setting.observation.deliveryMechanism)
|| (setting.observation.deliveryMechanism === 'registry-policy' ? setting.observation.state !== 'instruction'
: !['configured', 'conflicted'].includes(setting.observation.state))
|| !setting.observation.sourcePath.trim() || !/^[a-f0-9]{64}$/.test(setting.observation.sourceSha256)
|| setting.observation.values.length !== 1 || setting.observation.effectiveState !== 'unknown') {
errors.push('Die Microsoft-Baselineanalyse enthält eine ungültige Registry-Policy-Einstellung.');
}
}
return [...new Set(errors)];
}
export function storedMicrosoftSecurityBaselineAnalysisValidationErrors(record: StoredMicrosoftSecurityBaselineAnalysis): string[] {
const errors = microsoftSecurityBaselineAnalysisValidationErrors(record.analysis);
if (record.version !== 1) errors.push('Die persistierte Microsoft-Baselineanalyse besitzt eine ungültige Version.');
if (record.supersedesAnalysisId === record.analysis.id) errors.push('Eine Microsoft-Baselineanalyse darf sich nicht selbst ersetzen.');
return [...new Set(errors)];
}