ApiCSPReport: Log user ID instead of name, and limit urls to origin

These reports often contain false-positives from gadgets and
browser extensions that use a cross-domain requests for retreiving
information from a web API. (E.g. not for fetching executable JS
code, or for sending data elsewhere.)

Those API requests aren't static like "/foo.js?v2" but rather
dynamic, like /query/input+from+user, containing information about
what the user was reading, who or what they interacted with on
the wiki and/or text they entered or selected specifically.
(e.g. investigating user behaviour, counter-vandalism,
Google Translate tools, WHOIS gadgets, etc.)

Details of such action don't need to be recorded, and shown on
Logstash dashboards by default in the 'message' field. In fact,
I don't think it is needed for anything by default. If there's a
security problem, I imagine the origin suffices for a CSP block
and/or to start investigating.

Same for the user name. I don't want to see "[enwiki] John, referer
/wiki/Topic_read, chrome-extension/xyz, vandal-query.org/George".

These now log: "[enwiki] user_id 123, referer /wiki/Topic_read,
chrome-extension/xyz, vandal-query.org"

The user name still available when purposely investigating (via
public tools) by resolving the user ID.

Bug: T207900
Change-Id: Ic9855400c8cfedfa92b6659a4ad29c4dc28fb256
This commit is contained in:
Timo Tijhof 2019-04-17 00:32:30 +01:00 committed by Krinkle
parent 64bd7a7e4b
commit 5f34361759

View file

@ -54,7 +54,7 @@ class ApiCSPReport extends ApiBase {
// XXX Is it ok to put untrusted data into log??
'csp-report' => $report,
'method' => __METHOD__,
'user' => $this->getUser()->getName(),
'user_id' => $this->getUser()->getId() || 'logged-out',
'user-agent' => $userAgent,
'source' => $this->getParameter( 'source' ),
] );
@ -176,15 +176,32 @@ class ApiCSPReport extends ApiBase {
$flagText = '[' . implode( ', ', $flags ) . ']';
}
$blockedFile = $report['blocked-uri'] ?? 'n/a';
$blockedOrigin = isset( $report['blocked-uri'] )
? $this->originFromUrl( $report['blocked-uri'] )
: 'n/a';
$page = $report['document-uri'] ?? 'n/a';
$line = isset( $report['line-number'] ) ? ':' . $report['line-number'] : '';
$line = isset( $report['line-number'] )
? ':' . $report['line-number']
: '';
$warningText = $flagText .
' Received CSP report: <' . $blockedFile .
'> blocked from being loaded on <' . $page . '>' . $line;
' Received CSP report: <' . $blockedOrigin . '>' .
' blocked from being loaded on <' . $page . '>' . $line;
return $warningText;
}
/**
* @param string $url
* @return string
*/
private function originFromUrl( $url ) {
$bits = wfParseUrl( $url );
unset( $bits['user'], $bits['pass'], $bits['query'], $bits['fragment'] );
$bits['path'] = '';
$serverUrl = wfAssembleUrl( $bits );
// e.g. "https://example.org" from "https://example.org/foo/b?a#r"
return $serverUrl;
}
/**
* Stop processing the request, and output/log an error
*