mirror of https://github.com/FreshRSS/FreshRSS.git
API avoid logging passwords (#5001)
* API avoid logging passwords * Strip passwords and tokens from API logs * Only log failed requests information when in debug mode * Remove debug SHA * Clean also Apache logs * Better comments * Redact also token parameters * shfmt * Simplify whitespace * redacted
This commit is contained in:
parent
c75baefe40
commit
075cf4c800
|
@ -4,7 +4,7 @@ DocumentRoot /var/www/FreshRSS/p/
|
|||
RemoteIPHeader X-Forwarded-For
|
||||
RemoteIPTrustedProxy 10.0.0.1/8 172.16.0.1/12 192.168.0.1/16
|
||||
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_proxy
|
||||
CustomLog /dev/stdout combined_proxy
|
||||
CustomLog "|/var/www/FreshRSS/cli/sensitive-log.sh" combined_proxy
|
||||
ErrorLog /dev/stderr
|
||||
AllowEncodedSlashes On
|
||||
ServerTokens OS
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
# Strips sensitive passwords from (Apache) logs
|
||||
|
||||
# For e.g. GNU systems such as Debian
|
||||
# N.B.: `sed -u` is not available in BusyBox and without it there are buffering delays (even with stdbuf)
|
||||
sed -Eu 's/([?&])(Passwd|token)=[^& \t]+/\1\2=redacted/ig' 2>/dev/null ||
|
||||
|
||||
# For systems with gawk (not available by default in Docker of Debian or Alpine) or with BuzyBox such as Alpine
|
||||
$(which gawk || which awk) -v IGNORECASE=1 '{ print gensub(/([?&])(Passwd|token)=[^& \t]+/, "\\1\\2=redacted", "g") }'
|
|
@ -223,6 +223,31 @@ function html_only_entity_decode($text): string {
|
|||
return $text == '' ? '' : strtr($text, $htmlEntitiesOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove passwords in FreshRSS logs.
|
||||
* See also ../cli/sensitive-log.sh for Web server logs.
|
||||
* @param array<string,mixed>|string $log
|
||||
* @return array<string,mixed>|string
|
||||
*/
|
||||
function sensitive_log($log) {
|
||||
if (is_array($log)) {
|
||||
foreach ($log as $k => $v) {
|
||||
if (in_array($k, ['api_key', 'Passwd', 'T'])) {
|
||||
$log[$k] = '██';
|
||||
} else {
|
||||
$log[$k] = sensitive_log($v);
|
||||
}
|
||||
}
|
||||
} elseif (is_string($log)) {
|
||||
$log = preg_replace([
|
||||
'/\b(auth=.*?\/)[^&]+/i',
|
||||
'/\b(Passwd=)[^&]+/i',
|
||||
'/\b(Authorization)[^&]+/i',
|
||||
], '$1█', $log);
|
||||
}
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $attributes
|
||||
*/
|
||||
|
|
|
@ -18,7 +18,8 @@ FreshRSS_Context::initSystem();
|
|||
|
||||
// check if API is enabled globally
|
||||
if (!FreshRSS_Context::$system_conf->api_enabled) {
|
||||
Minz_Log::warning('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('Fever API: service unavailable!');
|
||||
Minz_Log::debug('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG);
|
||||
header('HTTP/1.1 503 Service Unavailable');
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
die('Service Unavailable!');
|
||||
|
@ -45,16 +46,16 @@ function debugInfo() {
|
|||
}
|
||||
}
|
||||
global $ORIGINAL_INPUT;
|
||||
return print_r(
|
||||
array(
|
||||
$log = sensitive_log([
|
||||
'date' => date('c'),
|
||||
'headers' => $ALL_HEADERS,
|
||||
'_SERVER' => $_SERVER,
|
||||
'_GET' => $_GET,
|
||||
'_POST' => $_POST,
|
||||
'_COOKIE' => $_COOKIE,
|
||||
'INPUT' => $ORIGINAL_INPUT
|
||||
), true);
|
||||
'INPUT' => $ORIGINAL_INPUT,
|
||||
]);
|
||||
return print_r($log, true);
|
||||
}
|
||||
|
||||
//Minz_Log::debug('----------------------------------------------------------------', API_LOG);
|
||||
|
|
|
@ -97,27 +97,29 @@ function debugInfo() {
|
|||
}
|
||||
}
|
||||
global $ORIGINAL_INPUT;
|
||||
return print_r(
|
||||
array(
|
||||
$log = sensitive_log([
|
||||
'date' => date('c'),
|
||||
'headers' => $ALL_HEADERS,
|
||||
'_SERVER' => $_SERVER,
|
||||
'_GET' => $_GET,
|
||||
'_POST' => $_POST,
|
||||
'_COOKIE' => $_COOKIE,
|
||||
'INPUT' => $ORIGINAL_INPUT
|
||||
), true);
|
||||
'INPUT' => $ORIGINAL_INPUT,
|
||||
]);
|
||||
return print_r($log, true);
|
||||
}
|
||||
|
||||
function badRequest() {
|
||||
Minz_Log::warning('badRequest() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
|
||||
Minz_Log::debug('badRequest() ' . debugInfo(), API_LOG);
|
||||
header('HTTP/1.1 400 Bad Request');
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
die('Bad Request!');
|
||||
}
|
||||
|
||||
function unauthorized() {
|
||||
Minz_Log::warning('unauthorized() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
|
||||
Minz_Log::debug('unauthorized() ' . debugInfo(), API_LOG);
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
header('Google-Bad-Token: true');
|
||||
|
@ -125,21 +127,24 @@ function unauthorized() {
|
|||
}
|
||||
|
||||
function notImplemented() {
|
||||
Minz_Log::warning('notImplemented() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
|
||||
Minz_Log::debug('notImplemented() ' . debugInfo(), API_LOG);
|
||||
header('HTTP/1.1 501 Not Implemented');
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
die('Not Implemented!');
|
||||
}
|
||||
|
||||
function serviceUnavailable() {
|
||||
Minz_Log::warning('serviceUnavailable() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
|
||||
Minz_Log::debug('serviceUnavailable() ' . debugInfo(), API_LOG);
|
||||
header('HTTP/1.1 503 Service Unavailable');
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
die('Service Unavailable!');
|
||||
}
|
||||
|
||||
function checkCompatibility() {
|
||||
Minz_Log::warning('checkCompatibility() ' . debugInfo(), API_LOG);
|
||||
Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
|
||||
Minz_Log::debug('checkCompatibility() ' . debugInfo(), API_LOG);
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
if (PHP_INT_SIZE < 8 && !function_exists('gmp_init')) {
|
||||
die('FAIL 64-bit or GMP extension! Wrong PHP configuration.');
|
||||
|
@ -172,8 +177,7 @@ function authorizationToUser() {
|
|||
if ($headerAuthX[1] === sha1(FreshRSS_Context::$system_conf->salt . $user . FreshRSS_Context::$user_conf->apiPasswordHash)) {
|
||||
return $user;
|
||||
} else {
|
||||
Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1], API_LOG);
|
||||
Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]);
|
||||
Minz_Log::warning('Invalid API authorisation for user ' . $user);
|
||||
unauthorized();
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue