mirror of https://github.com/FreshRSS/FreshRSS.git
Rework trusted proxies (#5549)
* Rework trusted proxies Fix https://github.com/FreshRSS/FreshRSS/issues/5502 Follow-up of https://github.com/FreshRSS/FreshRSS/pull/3226 New environment variable `TRUSTED_PROXY`: set to 0 to disable, or to a list of trusted IP ranges compatible with https://httpd.apache.org/docs/current/mod/mod_remoteip.html#remoteiptrustedproxy New internal environment variable `CONN_REMOTE_ADDR` to remember the true IP address of the connection (e.g. last proxy), even when using mod_remoteip. Current working setups should not observe any significant change. * Minor whitespace * Safer trusted sources during install Rework of https://github.com/FreshRSS/FreshRSS/pull/5358 https://github.com/FreshRSS/FreshRSS/issues/5357 * Minor readme
This commit is contained in:
parent
0182d84142
commit
e7689459f2
|
@ -29,5 +29,6 @@ ENV CRON_MIN ''
|
|||
ENV DATA_PATH ''
|
||||
ENV FRESHRSS_ENV 'development'
|
||||
ENV LISTEN '0.0.0.0:8080'
|
||||
ENV TRUSTED_PROXY 0
|
||||
|
||||
EXPOSE 8080
|
||||
|
|
|
@ -58,6 +58,7 @@ ENV DATA_PATH ''
|
|||
ENV FRESHRSS_ENV ''
|
||||
ENV LISTEN ''
|
||||
ENV OIDC_ENABLED ''
|
||||
ENV TRUSTED_PROXY ''
|
||||
|
||||
ENTRYPOINT ["./Docker/entrypoint.sh"]
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ ENV DATA_PATH ''
|
|||
ENV FRESHRSS_ENV ''
|
||||
ENV LISTEN ''
|
||||
ENV OIDC_ENABLED ''
|
||||
ENV TRUSTED_PROXY ''
|
||||
|
||||
ENTRYPOINT ["./Docker/entrypoint.sh"]
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ ENV DATA_PATH ''
|
|||
ENV FRESHRSS_ENV ''
|
||||
ENV LISTEN ''
|
||||
ENV OIDC_ENABLED ''
|
||||
ENV TRUSTED_PROXY ''
|
||||
|
||||
ENTRYPOINT ["./Docker/entrypoint.sh"]
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ ENV DATA_PATH ''
|
|||
ENV FRESHRSS_ENV ''
|
||||
ENV LISTEN ''
|
||||
ENV OIDC_ENABLED ''
|
||||
ENV TRUSTED_PROXY ''
|
||||
|
||||
ENTRYPOINT ["./Docker/entrypoint.sh"]
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ ENV DATA_PATH ''
|
|||
ENV FRESHRSS_ENV ''
|
||||
ENV LISTEN ''
|
||||
ENV OIDC_ENABLED ''
|
||||
ENV TRUSTED_PROXY ''
|
||||
|
||||
ENTRYPOINT ["./Docker/entrypoint.sh"]
|
||||
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
ServerName freshrss.localhost
|
||||
Listen 80
|
||||
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 "|/var/www/FreshRSS/cli/sensitive-log.sh" combined_proxy
|
||||
ErrorLog /dev/stderr
|
||||
AllowEncodedSlashes On
|
||||
ServerTokens OS
|
||||
TraceEnable Off
|
||||
ErrorLog /dev/stderr
|
||||
|
||||
# For logging the original user-agent IP instead of proxy IPs:
|
||||
<IfModule mod_remoteip.c>
|
||||
# Can be disabled by setting the TRUSTED_PROXY environment variable to 0:
|
||||
RemoteIPHeader X-Forwarded-For
|
||||
# Can be overridden by the TRUSTED_PROXY environment variable:
|
||||
RemoteIPTrustedProxy 10.0.0.1/8 172.16.0.1/12 192.168.0.1/16
|
||||
</IfModule>
|
||||
|
||||
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_proxy
|
||||
CustomLog "|/var/www/FreshRSS/cli/sensitive-log.sh" combined_proxy
|
||||
|
||||
<IfDefine OIDC_ENABLED>
|
||||
<IfModule !auth_openidc_module>
|
||||
|
|
|
@ -330,6 +330,13 @@ services:
|
|||
FRESHRSS_ENV: development
|
||||
# Optional advanced parameter controlling the internal Apache listening port
|
||||
LISTEN: 0.0.0.0:80
|
||||
# Optional parameter, remove for automatic settings, set to 0 to disable,
|
||||
# or (if you use a proxy) to a space-separated list of trusted IP ranges
|
||||
# compatible with https://httpd.apache.org/docs/current/mod/mod_remoteip.html#remoteiptrustedproxy
|
||||
# This impacts which IP address is logged (X-Forwarded-For or REMOTE_ADDR).
|
||||
# This also impacts external authentication methods;
|
||||
# see https://freshrss.github.io/FreshRSS/en/admins/09_AccessControl.html
|
||||
TRUSTED_PROXY: 172.16.0.1/12 192.168.0.1/16
|
||||
# Optional parameter, set to 1 to enable OpenID Connect (only available in our Debian image)
|
||||
# Requires more environment variables. See https://freshrss.github.io/FreshRSS/en/admins/16_OpenID-Connect.html
|
||||
OIDC_ENABLED: 0
|
||||
|
|
|
@ -11,6 +11,16 @@ if [ -n "$LISTEN" ]; then
|
|||
find /etc/apache2/ -type f -name FreshRSS.Apache.conf -exec sed -r -i "\\#^Listen#s#^.*#Listen $LISTEN#" {} \;
|
||||
fi
|
||||
|
||||
if [ -n "$TRUSTED_PROXY" ]; then
|
||||
if [ "$TRUSTED_PROXY" -eq 0 ]; then
|
||||
# Disable RemoteIPHeader and RemoteIPTrustedProxy
|
||||
find /etc/apache2/ -type f -name FreshRSS.Apache.conf -exec sed -r -i "/^\s*RemoteIP.*$/s/^/#/" {} \;
|
||||
else
|
||||
# Custom list for RemoteIPTrustedProxy
|
||||
find /etc/apache2/ -type f -name FreshRSS.Apache.conf -exec sed -r -i "\\#^\s*RemoteIPTrustedProxy#s#^.*#\tRemoteIPTrustedProxy $TRUSTED_PROXY#" {} \;
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$OIDC_ENABLED" ] && [ "$OIDC_ENABLED" -ne 0 ]; then
|
||||
a2enmod -q auth_openidc
|
||||
fi
|
||||
|
|
|
@ -7,7 +7,7 @@ volumes:
|
|||
services:
|
||||
|
||||
traefik:
|
||||
image: traefik:2.6
|
||||
image: traefik:2.10
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
logging:
|
||||
|
@ -42,6 +42,8 @@ services:
|
|||
- traefik.enable=false
|
||||
|
||||
freshrss:
|
||||
environment:
|
||||
TRUSTED_PROXY: 172.16.0.1/12
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.middlewares.freshrssM1.compress=true
|
||||
|
|
|
@ -25,3 +25,4 @@ services:
|
|||
environment:
|
||||
TZ: Europe/Paris
|
||||
CRON_MIN: '3,33'
|
||||
TRUSTED_PROXY: 172.16.0.1/12 192.168.0.1/16
|
||||
|
|
|
@ -79,7 +79,7 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
|
|||
'error' => [
|
||||
_t('feedback.access.denied'),
|
||||
' [HTTP Remote-User=' . htmlspecialchars(httpAuthUser(false), ENT_NOQUOTES, 'UTF-8') .
|
||||
' ; Remote IP address=' . ($_SERVER['REMOTE_ADDR'] ?? '') . ']'
|
||||
' ; Remote IP address=' . connectionRemoteAddress() . ']'
|
||||
]
|
||||
], false);
|
||||
break;
|
||||
|
|
|
@ -208,9 +208,14 @@ function saveStep3(): bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (FreshRSS_Context::$system_conf->auth_type === 'http_auth' && !empty($_SERVER['REMOTE_ADDR']) && is_string($_SERVER['REMOTE_ADDR'])) {
|
||||
// Trust by default the remote IP address (e.g. proxy) used during install to provide remote user name
|
||||
FreshRSS_Context::$system_conf->trusted_sources = [ $_SERVER['REMOTE_ADDR'] ];
|
||||
if (FreshRSS_Context::$system_conf->auth_type === 'http_auth' &&
|
||||
connectionRemoteAddress() !== '' &&
|
||||
empty($_SERVER['REMOTE_USER']) && empty($_SERVER['REDIRECT_REMOTE_USER']) && // No safe authentication HTTP headers
|
||||
(!empty($_SERVER['HTTP_REMOTE_USER']) || !empty($_SERVER['HTTP_X_WEBAUTH_USER'])) // but has unsafe authentication HTTP headers
|
||||
) {
|
||||
// Trust by default the remote IP address (e.g. last proxy) used during install to provide remote user name via unsafe HTTP header
|
||||
FreshRSS_Context::$system_conf->trusted_sources[] = connectionRemoteAddress();
|
||||
FreshRSS_Context::$system_conf->trusted_sources = array_unique(FreshRSS_Context::$system_conf->trusted_sources);
|
||||
}
|
||||
|
||||
// Create default user files but first, we delete previous data to
|
||||
|
|
|
@ -194,9 +194,12 @@ return array(
|
|||
# Disable self-update,
|
||||
'disable_update' => false,
|
||||
|
||||
# Trusted IPs that are allowed to send unsafe headers
|
||||
# Please read the documentation, before configuring this
|
||||
# https://freshrss.github.io/FreshRSS/en/admins/09_AccessControl.html
|
||||
# Trusted IPs (e.g. of last proxy) that are allowed to send unsafe HTTP headers.
|
||||
# The connection IP used during FreshRSS setup is automatically added to this list.
|
||||
# Will be checked against CONN_REMOTE_ADDR (if available, to be robust even when using Apache mod_remoteip)
|
||||
# or REMOTE_ADDR environment variable.
|
||||
# This array can be overridden by the TRUSTED_PROXY environment variable.
|
||||
# Read the documentation before configuring this https://freshrss.github.io/FreshRSS/en/admins/09_AccessControl.html
|
||||
'trusted_sources' => [
|
||||
'127.0.0.0/8',
|
||||
'::1/128',
|
||||
|
|
|
@ -24,13 +24,15 @@ variable containing the email address of the authenticated user (e.g. `REMOTE_US
|
|||
|
||||
## External Authentication
|
||||
|
||||
You may also use the `Remote-User` or `X-WebAuth-User` header to integrate with a your reverse-proxy’s authentication.
|
||||
You may also use the `Remote-User` or `X-WebAuth-User` HTTP headers to integrate with a reverse-proxy’s authentication.
|
||||
|
||||
To enable this feature, you need to add the IP range (in CIDR notation) of your trusted proxy in the `trusted_sources` configuration option.
|
||||
To allow only one IPv4, you can use a `/32` like this: `trusted_sources => [ '192.168.1.10/32' ]`.
|
||||
Likewise to allow only one IPv6, you can use a `/128` like this: `trusted_sources => [ '::1/128' ]`.
|
||||
|
||||
WARNING: FreshRSS will trust any IP configured in the `trusted_sources` option, if your proxy isn’t properly secured, an attacker could simply attach this header and get admin access.
|
||||
You may alternatively pass a `TRUSTED_PROXY` environment variable in a format compatible with [Apache’s `mod_remoteip` `RemoteIPTrustedProxy`](https://httpd.apache.org/docs/current/mod/mod_remoteip.html#remoteiptrustedproxy).
|
||||
|
||||
> ☠️ WARNING: FreshRSS will trust any IP configured in the `trusted_sources` option, if your proxy isn’t properly secured, an attacker could simply attach this header and get admin access.
|
||||
|
||||
## No Authentication
|
||||
|
||||
|
|
|
@ -653,21 +653,43 @@ function checkCIDR(string $ip, string $range): bool {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the client is allowed to send unsafe headers
|
||||
* This uses the REMOTE_ADDR header to determine the sender’s IP
|
||||
* and the configuration option "trusted_sources" to get an array of the authorized ranges
|
||||
*
|
||||
* Use CONN_REMOTE_ADDR (if available, to be robust even when using Apache mod_remoteip) or REMOTE_ADDR environment variable to determine the connection IP.
|
||||
*/
|
||||
function connectionRemoteAddress(): string {
|
||||
$remoteIp = $_SERVER['CONN_REMOTE_ADDR'] ?? '';
|
||||
if ($remoteIp == '') {
|
||||
$remoteIp = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
}
|
||||
if ($remoteIp == 0) {
|
||||
$remoteIp = '';
|
||||
}
|
||||
return $remoteIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the client (e.g. last proxy) is allowed to send unsafe headers.
|
||||
* This uses the `TRUSTED_PROXY` environment variable or the `trusted_sources` configuration option to get an array of the authorized ranges,
|
||||
* The connection IP is obtained from the `CONN_REMOTE_ADDR` (if available, to be robust even when using Apache mod_remoteip) or `REMOTE_ADDR` environment variables.
|
||||
* @return bool, true if the sender’s IP is in one of the ranges defined in the configuration, else false
|
||||
*/
|
||||
function checkTrustedIP(): bool {
|
||||
if (FreshRSS_Context::$system_conf === null) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) {
|
||||
if (checkCIDR($_SERVER['REMOTE_ADDR'], $cidr)) {
|
||||
return true;
|
||||
}
|
||||
$remoteIp = connectionRemoteAddress();
|
||||
if ($remoteIp === '') {
|
||||
return false;
|
||||
}
|
||||
$trusted = getenv('TRUSTED_PROXY');
|
||||
if ($trusted != 0 && is_string($trusted)) {
|
||||
$trusted = preg_split('/\s+/', $trusted, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
if (empty($trusted)) {
|
||||
$trusted = FreshRSS_Context::$system_conf->trusted_sources;
|
||||
}
|
||||
foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) {
|
||||
if (checkCIDR($remoteIp, $cidr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
11
p/.htaccess
11
p/.htaccess
|
@ -35,3 +35,14 @@ AddDefaultCharset UTF-8
|
|||
</FilesMatch>
|
||||
Header edit Set-Cookie ^(.*)$ "$1; SameSite=Lax"
|
||||
</IfModule>
|
||||
|
||||
# Provide the true IP address of the connection (e.g. last proxy), even when using mod_remoteip
|
||||
<IfModule mod_setenvif.c>
|
||||
SetEnvIfExpr "%{CONN_REMOTE_ADDR} =~ /(.*)/" CONN_REMOTE_ADDR=$1
|
||||
</IfModule>
|
||||
<IfModule !mod_setenvif.c>
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteRule .* - [E=CONN_REMOTE_ADDR:%{CONN_REMOTE_ADDR}]
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
|
Loading…
Reference in New Issue