feat(clickTtHttpPageRoutes): add sensitive data masking and form body summarization

- Introduced functions to mask sensitive values in form submissions and summarize form body data, enhancing security and logging capabilities.
- Updated the proxy POST route to log detailed information about submitted forms, including field counts and redacted values for sensitive keys.
- Enhanced error handling for URL-encoded body parsing, improving robustness in form data processing.
This commit is contained in:
Torsten Schulz (local)
2026-03-11 12:25:45 +01:00
parent 1398e8911a
commit 3ea9cdd611

View File

@@ -56,6 +56,41 @@ function serializeFormBody(req) {
return null;
}
function maskSensitiveValue(key, value) {
if (!key) return value;
return /(pass|password|passwd|pwd|token|secret)/i.test(String(key)) ? '[redacted]' : value;
}
function summarizeFormBody(body) {
if (!body || typeof body !== 'string') {
return { fieldCount: 0, fields: [] };
}
try {
const params = new URLSearchParams(body);
const fields = [];
for (const [key, value] of params.entries()) {
fields.push({
key,
value: maskSensitiveValue(key, value),
});
}
return {
fieldCount: fields.length,
fields,
parseError: null,
};
} catch {
return {
fieldCount: 0,
fields: [],
parseError: 'body is not URL-encoded',
};
}
}
/** Domains, deren Links durch den Proxy umgeleitet werden (für Folge-Logs) */
const PROXY_DOMAINS = ['click-tt.de', 'httv.de', 'liga.nu'];
@@ -287,6 +322,7 @@ function injectProxyNavigationScript(html, proxyBaseUrl, pageBaseUrl, sid) {
'if(!anchor||event.defaultPrevented)return;',
"var targetUrl=normalizeUrl(anchor.getAttribute('href'),PAGE_BASE_URL);",
'if(!targetUrl||!shouldProxyUrl(targetUrl))return;',
"try{console.log('[ClickTT Proxy] anchor click',{href:anchor.getAttribute('href'),targetUrl:targetUrl,text:(anchor.textContent||'').trim().slice(0,120)});}catch(e){}",
'event.preventDefault();',
'navigateViaProxy(targetUrl);',
'},false);',
@@ -296,6 +332,17 @@ function injectProxyNavigationScript(html, proxyBaseUrl, pageBaseUrl, sid) {
'var submitter=event.submitter||null;',
'var targetUrl=getSubmitTarget(form,submitter);',
'if(!targetUrl||!shouldProxyUrl(targetUrl))return;',
'try{',
'var formDataEntries=[];',
'if(window.FormData){',
'var formData=new FormData(form);',
'formData.forEach(function(value,key){',
"var safeValue=/(pass|password|passwd|pwd|token|secret)/i.test(String(key))?'[redacted]':String(value);",
'formDataEntries.push({key:key,value:safeValue});',
'});',
'}',
"console.log('[ClickTT Proxy] form submit',{action:form.getAttribute('action'),targetUrl:targetUrl,submitterName:submitter&&submitter.name?submitter.name:null,submitterValue:submitter&&submitter.value?submitter.value:null,fieldCount:formDataEntries.length,fields:formDataEntries.slice(0,40)});",
'}catch(e){}',
"form.setAttribute('action',buildProxyUrl(targetUrl));",
'},true);',
'if(window.fetch){',
@@ -321,6 +368,7 @@ function injectProxyNavigationScript(html, proxyBaseUrl, pageBaseUrl, sid) {
'var nativeSubmit=window.HTMLFormElement.prototype.submit;',
'window.HTMLFormElement.prototype.submit=function patchedSubmit(){',
'var targetUrl=getSubmitTarget(this,null);',
'try{console.log("[ClickTT Proxy] direct form.submit()",{action:this.getAttribute("action"),targetUrl:targetUrl});}catch(e){}',
"if(targetUrl&&shouldProxyUrl(targetUrl)){this.setAttribute('action',buildProxyUrl(targetUrl));}",
'return nativeSubmit.apply(this,arguments);',
'};',
@@ -469,6 +517,16 @@ router.post('/proxy', async (req, res, next) => {
const contentType = req.get('content-type') || 'application/x-www-form-urlencoded';
const body = serializeFormBody(req);
const bodySummary = summarizeFormBody(body);
console.log('[ClickTT Proxy POST]', JSON.stringify({
sid,
targetUrl,
contentType,
fieldCount: bodySummary.fieldCount,
fields: bodySummary.fields,
parseError: bodySummary.parseError,
}));
const result = await clickTtHttpPageService.fetchWithLogging({
url: targetUrl,
@@ -658,10 +716,9 @@ router.get('/fetch', authenticate, async (req, res, next) => {
return res.status(400).json({ error: 'url ist erforderlich' });
}
// Nur click-tt.de und httv.de erlauben
if (!url.includes('click-tt.de') && !url.includes('httv.de')) {
if (!isAllowedProxyUrl(url)) {
return res.status(400).json({
error: 'Nur URLs von click-tt.de oder httv.de sind erlaubt',
error: 'Nur URLs von click-tt.de, httv.de oder liga.nu sind erlaubt',
});
}