Security fixes N4/H2/H1 + hide template editor for non-admins

This commit is contained in:
Kühn
2026-08-28 10:15:31 +02:00
parent a35721abec
commit 03d20b0e09
19 changed files with 31 additions and 56 deletions

View File

@@ -77,8 +77,18 @@ async function browseOUTree(searchBase) {
throw new Error('LDAP nicht konfiguriert.');
}
const client = await createClient();
// H1: Validate searchBase - must be a DN under the configured LDAP_SEARCH_BASE
// (prevents arbitrary LDAP tree browsing outside the allowed scope)
const base = searchBase || LDAP_SEARCH_BASE;
if (base !== LDAP_SEARCH_BASE) {
const escapeDNRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const basePattern = new RegExp(',' + escapeDNRegex(LDAP_SEARCH_BASE) + '$', 'i');
if (!basePattern.test(base)) {
throw new Error('Ungültige Suchbasis: muss unterhalb von ' + LDAP_SEARCH_BASE + ' liegen.');
}
}
const client = await createClient();
try {
const { searchEntries } = await client.search(base, {
@@ -342,10 +352,19 @@ async function searchADGroups(query) {
throw new Error('LDAP nicht konfiguriert.');
}
// H2: Validate query - length limit + only safe characters (prevents LDAP injection & DoS)
const safeQuery = String(query || '').trim();
if (!safeQuery || safeQuery.length < 2 || safeQuery.length > 100) {
return [];
}
if (!/^[a-zA-Z0-9äöüÄÖÜß._\- ]+$/.test(safeQuery)) {
return [];
}
const client = await createClient();
try {
const escapedQuery = query.replace(/[()*\\]/g, '\\$&');
const escapedQuery = safeQuery.replace(/[()*\\]/g, '\\$&');
const { searchEntries } = await client.search(LDAP_SEARCH_BASE, {
filter: `(&(objectClass=group)(|(cn=*${escapedQuery}*)(displayName=*${escapedQuery}*)(sAMAccountName=*${escapedQuery}*)))`,
scope: 'sub',

View File

@@ -87,7 +87,8 @@ const allowedOrigins = validCorsOrigins.length > 0
: ['http://localhost:5000', 'http://localhost:5173', 'http://127.0.0.1:5000', 'http://127.0.0.1:5173'];
app.use(cors({ origin: allowedOrigins, credentials: true }));
// Punkt 14: Body-Size-Limit to prevent DoS via large payloads
app.use(express.json({ limit: process.env.BODY_LIMIT || '1mb' }));
// N4: 10MB to accommodate file uploads (matches UPLOAD_MAX_MB)
app.use(express.json({ limit: process.env.BODY_LIMIT || '10mb' }));
// Punkt 8: Cookie-Parser für HttpOnly-Cookie Auth
app.use(cookieParser());