Mobilfunknetz: server-seitige Whitelist (Pentest-INFO)
mobileNetwork akzeptierte serverseitig jeden stripHtml-bereinigten String – das Frontend-Dropdown beschränkte nur clientseitig. Jetzt Whitelist TELEKOM|VODAFONE|TELEFONICA (normalizeMobileNetwork), angewandt in Create- UND Update-Pfad (der Update-Spread reichte den Wert vorher ungefiltert an Prisma durch). Unbekannte/leere Werte werden zu null normalisiert. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -322,6 +322,17 @@ interface ContractCreateData {
|
||||
};
|
||||
}
|
||||
|
||||
// Erlaubte Mobilfunknetze. Server-seitige Whitelist, damit über einen
|
||||
// handgebauten Request kein beliebiger String in mobileNetwork landet
|
||||
// (das Frontend-Dropdown beschränkt schon, der Server vertraut ihm aber
|
||||
// nicht). Unbekannte/leere Werte werden zu null normalisiert.
|
||||
const ALLOWED_MOBILE_NETWORKS = new Set(['TELEKOM', 'VODAFONE', 'TELEFONICA']);
|
||||
function normalizeMobileNetwork(value: unknown): string | null {
|
||||
if (typeof value !== 'string') return null;
|
||||
const v = value.trim().toUpperCase();
|
||||
return ALLOWED_MOBILE_NETWORKS.has(v) ? v : null;
|
||||
}
|
||||
|
||||
export async function createContract(data: ContractCreateData) {
|
||||
const {
|
||||
energyDetails,
|
||||
@@ -387,7 +398,7 @@ export async function createContract(data: ContractCreateData) {
|
||||
mobileDetails: {
|
||||
create: {
|
||||
requiresMultisim: mobileDetails.requiresMultisim,
|
||||
mobileNetwork: mobileDetails.mobileNetwork ?? null,
|
||||
mobileNetwork: normalizeMobileNetwork(mobileDetails.mobileNetwork),
|
||||
dataVolume: mobileDetails.dataVolume,
|
||||
includedMinutes: mobileDetails.includedMinutes,
|
||||
includedSMS: mobileDetails.includedSMS,
|
||||
@@ -623,6 +634,11 @@ export async function updateContract(
|
||||
|
||||
if (mobileDetails) {
|
||||
const { simCards, ...mobileData } = mobileDetails;
|
||||
// Whitelist auf das Netz anwenden, bevor mobileData per Spread an
|
||||
// Prisma geht (Update-Pfad reicht sonst beliebige Strings durch).
|
||||
if ('mobileNetwork' in mobileData) {
|
||||
mobileData.mobileNetwork = normalizeMobileNetwork(mobileData.mobileNetwork);
|
||||
}
|
||||
const existing = await prisma.mobileContractDetails.findUnique({
|
||||
where: { contractId: id },
|
||||
});
|
||||
|
||||
@@ -97,6 +97,14 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🔒 Mobilfunknetz: server-seitige Whitelist (Pentest-INFO)**
|
||||
- `mobileNetwork` akzeptierte serverseitig jeden (stripHtml-bereinigten)
|
||||
String – das Frontend-Dropdown beschränkte nur clientseitig. Jetzt
|
||||
Whitelist `TELEKOM|VODAFONE|TELEFONICA` in `contract.service.ts`
|
||||
(`normalizeMobileNetwork`), angewandt in Create- UND Update-Pfad
|
||||
(Update-Spread wurde vorher ungefiltert durchgereicht). Unbekannte/
|
||||
leere Werte → null.
|
||||
|
||||
- [x] **🔒 Rate-Limiting: IPv6-Bypass-Härtung (ipKeyGenerator)**
|
||||
- Die Rate-Limiter mit eigenem `keyGenerator` (`loginRateLimiter`,
|
||||
`staffPasswordReAuthLimiter`) keyten auf die **volle** `req.ip`.
|
||||
|
||||
Reference in New Issue
Block a user