Belegübersicht: fail-closed Portal-Scoping (R144)
Pentester R144 (fail-closed, kein Finding): listAll scopte ueber 'if (isCustomerPortal && customerId)'. Fiele customerId bei einem Portal-Token mal falsy aus, rutschte er in den Staff-Zweig (alle Belege). Jetzt: Portal-Token wird IMMER gescoped; ohne customerId -> leere Menge (customerIds=[]) statt undefined/Staff. In:[] kann nie matchen. Aktuell nicht erreichbar (Portal-Token traegt immer customerId), aber robuster. Verifiziert: customerIds=[] -> 0 Belege. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,13 +50,18 @@ function handleError(res: Response, error: unknown, fallback: string) {
|
||||
export async function listAll(req: AuthRequest, res: Response): Promise<void> {
|
||||
try {
|
||||
// Portal-User: nur eigene + vertretene Kunden MIT Vollmacht.
|
||||
// Fail-closed (Pentest R144): Ein Portal-Token wird IMMER gescoped. Fehlt
|
||||
// wider Erwarten die customerId (null/0), ergibt das eine LEERE Menge –
|
||||
// nicht den Staff-Zweig (der alle Belege zeigen würde).
|
||||
let customerIds: number[] | undefined;
|
||||
if (req.user?.isCustomerPortal && req.user.customerId) {
|
||||
customerIds = [req.user.customerId];
|
||||
const representedIds: number[] = (req.user as any).representedCustomerIds || [];
|
||||
for (const repCustId of representedIds) {
|
||||
if (await authorizationService.hasAuthorization(repCustId, req.user.customerId)) {
|
||||
customerIds.push(repCustId);
|
||||
if (req.user?.isCustomerPortal) {
|
||||
customerIds = req.user.customerId ? [req.user.customerId] : [];
|
||||
if (req.user.customerId) {
|
||||
const representedIds: number[] = (req.user as any).representedCustomerIds || [];
|
||||
for (const repCustId of representedIds) {
|
||||
if (await authorizationService.hasAuthorization(repCustId, req.user.customerId)) {
|
||||
customerIds.push(repCustId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user