mirror of
https://github.com/optim-enterprises-bv/Mailu-OIDC.git
synced 2025-10-29 09:12:41 +00:00
Add snuffleupagus
This seems to work in my limited testing.
This commit is contained in:
@@ -52,16 +52,32 @@ RUN set -euxo pipefail \
|
||||
mkdir -p /root/.cargo/registry/index && \
|
||||
git clone --bare https://github.com/rust-lang/crates.io-index.git /root/.cargo/registry/index/github.com-1285ae84e5963aae \
|
||||
; pip install -r requirements-${MAILU_DEPS}.txt \
|
||||
; apk del -r .build-deps \
|
||||
; rm -rf /root/.cargo /tmp/*.pem \
|
||||
; } \
|
||||
; rm -rf /root/.cache
|
||||
|
||||
ARG SNUFFLEUPAGUS_VERSION=0.8.3
|
||||
ENV SNUFFLEUPAGUS_URL https://github.com/jvoisin/snuffleupagus/archive/refs/tags/v$SNUFFLEUPAGUS_VERSION.tar.gz
|
||||
|
||||
RUN set -euxo pipefail \
|
||||
; curl -sL ${SNUFFLEUPAGUS_URL} | tar xz \
|
||||
; cd snuffleupagus-$SNUFFLEUPAGUS_VERSION \
|
||||
; rm -rf src/tests/*php7*/ src/tests/*session*/ src/tests/broken_configuration/ src/tests/*cookie* src/tests/upload_validation/ \
|
||||
; apk add --virtual .build-deps php81-dev php81-cgi php81-simplexml php81-xml pcre-dev build-base php81-pear php81-openssl re2c \
|
||||
; ln -s /usr/bin/phpize81 /usr/bin/phpize \
|
||||
; ln -s /usr/bin/pecl81 /usr/bin/pecl \
|
||||
; ln -s /usr/bin/php-config81 /usr/bin/php-config \
|
||||
; ln -s /usr/bin/php81 /usr/bin/php \
|
||||
; pecl install vld-beta \
|
||||
; make -j $(grep -c processor /proc/cpuinfo) release \
|
||||
; cp src/.libs/snuffleupagus.so /app \
|
||||
; apk del -r .build-deps
|
||||
|
||||
# base mailu image
|
||||
FROM system
|
||||
|
||||
COPY --from=build /app/venv/ /app/venv/
|
||||
COPY --chown=root:root --from=build /app/snuffleupagus.so /usr/lib/php81/modules/
|
||||
|
||||
ENV VIRTUAL_ENV=/app/venv
|
||||
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
|
||||
|
||||
@@ -21,6 +21,8 @@ RUN set -euxo pipefail \
|
||||
; ln -s /usr/bin/php81 /usr/bin/php \
|
||||
; gpg --import /tmp/snappymail.asc \
|
||||
; gpg --import /tmp/roundcube.asc \
|
||||
; echo extension=snuffleupagus > /etc/php81/conf.d/snuffleupagus.ini \
|
||||
; rm -f /tmp/*asc \
|
||||
; mkdir -p /run/nginx \
|
||||
; mkdir -p /conf
|
||||
|
||||
@@ -41,7 +43,8 @@ RUN set -euxo pipefail \
|
||||
; cd roundcube \
|
||||
; rm -rf CHANGELOG.md SECURITY.md INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \
|
||||
; ln -sf index.php /var/www/roundcube/public_html/sso.php \
|
||||
; rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query}
|
||||
; rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query} \
|
||||
; sed -i '/suhosin.session.encrypt/d;/mbstring\.func_overload/d' program/lib/Roundcube/bootstrap.php
|
||||
|
||||
COPY roundcube/config/config.inc.php /conf/
|
||||
COPY roundcube/login/mailu.php /var/www/roundcube/plugins/mailu/
|
||||
@@ -81,6 +84,7 @@ COPY start.py /
|
||||
COPY php.ini /defaults/
|
||||
COPY php-webmail.conf /etc/php81/php-fpm.d/php-webmail.conf
|
||||
COPY nginx-webmail.conf /conf/
|
||||
COPY snuffleupagus.rules /etc/snuffleupagus.rules.tpl
|
||||
|
||||
EXPOSE 80/tcp
|
||||
VOLUME /data
|
||||
|
||||
@@ -11,3 +11,5 @@ log_errors=On
|
||||
zlib.output_compression=Off
|
||||
access.log = /dev/fd/2
|
||||
error_log = /dev/fd/2
|
||||
module=snuffleupagus.so
|
||||
sp.configuration_file=/etc/snuffleupagus.rules
|
||||
|
||||
@@ -5,7 +5,7 @@ $config = array();
|
||||
// Generals
|
||||
$config['db_dsnw'] = '{{ DB_DSNW }}';
|
||||
$config['temp_dir'] = '/dev/shm/';
|
||||
$config['des_key'] = '{{ SECRET_KEY }}';
|
||||
$config['des_key'] = '{{ ROUNDCUBE_KEY }}';
|
||||
$config['cipher_method'] = 'AES-256-CBC';
|
||||
$config['identities_level'] = 0;
|
||||
$config['reply_all_mode'] = 1;
|
||||
|
||||
126
webmails/snuffleupagus.rules
Normal file
126
webmails/snuffleupagus.rules
Normal file
@@ -0,0 +1,126 @@
|
||||
# This is based on default configuration file for Snuffleupagus (https://snuffleupagus.rtfd.io),
|
||||
# for php8.
|
||||
# It contains "reasonable" defaults that won't break your websites,
|
||||
# and a lot of commented directives that you can enable if you want to
|
||||
# have a better protection.
|
||||
|
||||
# Harden the PRNG
|
||||
sp.harden_random.enable();
|
||||
|
||||
# Disabled XXE
|
||||
sp.xxe_protection.enable();
|
||||
|
||||
# Global configuration variables
|
||||
sp.global.secret_key("{{ SNUFFLEPAGUS_KEY }}");
|
||||
|
||||
# Globally activate strict mode
|
||||
# https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
|
||||
sp.global_strict.enable();
|
||||
|
||||
# Prevent unserialize-related exploits
|
||||
# sp.unserialize_hmac.enable();
|
||||
|
||||
# Only allow execution of read-only files. This is a low-hanging fruit that you should enable.
|
||||
sp.readonly_exec.enable();
|
||||
|
||||
# PHP has a lot of wrappers, most of them aren't usually useful, you should
|
||||
# only enable the ones you're using.
|
||||
sp.wrappers_whitelist.list("file,php,phar,mailsosubstreams");
|
||||
|
||||
# Prevent sloppy comparisons.
|
||||
sp.sloppy_comparison.enable();
|
||||
|
||||
# Use SameSite on session cookie
|
||||
# https://snuffleupagus.readthedocs.io/features.html#protection-against-cross-site-request-forgery
|
||||
sp.cookie.name("PHPSESSID").samesite("lax");
|
||||
|
||||
# Harden the `chmod` function (0777 (oct = 511, 0666 = 438)
|
||||
sp.disable_function.function("chmod").param("permissions").value("438").drop();
|
||||
sp.disable_function.function("chmod").param("permissions").value("511").drop();
|
||||
|
||||
# Prevent various `mail`-related vulnerabilities
|
||||
sp.disable_function.function("mail").param("additional_parameters").value_r("\\-").drop();
|
||||
|
||||
# Since it's now burned, me might as well mitigate it publicly
|
||||
sp.disable_function.function("putenv").param("assignment").value_r("LD_").drop()
|
||||
|
||||
# This one was burned in Nov 2019 - https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80
|
||||
sp.disable_function.function("putenv").param("assignment").value_r("GCONV_").drop()
|
||||
|
||||
# Since people are stupid enough to use `extract` on things like $_GET or $_POST, we might as well mitigate this vector
|
||||
sp.disable_function.function("extract").param("array").value_r("^_").drop()
|
||||
sp.disable_function.function("extract").param("flags").value("0").drop()
|
||||
|
||||
# This is also burned:
|
||||
# ini_set('open_basedir','..');chdir('..');…;chdir('..');ini_set('open_basedir','/');echo(file_get_contents('/etc/passwd'));
|
||||
# Since we have no way of matching on two parameters at the same time, we're
|
||||
# blocking calls to open_basedir altogether: nobody is using it via ini_set anyway.
|
||||
# Moreover, there are non-public bypasses that are also using this vector ;)
|
||||
sp.disable_function.function("ini_set").param("option").value_r("open_basedir").drop()
|
||||
|
||||
# Prevent various `include`-related vulnerabilities
|
||||
sp.disable_function.function("require_once").value_r("\.(inc|phtml|php)$").allow();
|
||||
sp.disable_function.function("include_once").value_r("\.(inc|phtml|php)$").allow();
|
||||
sp.disable_function.function("require").value_r("\.(inc|phtml|php)$").allow();
|
||||
sp.disable_function.function("include").value_r("\.(inc|phtml|php)$").allow();
|
||||
sp.disable_function.function("require_once").drop()
|
||||
sp.disable_function.function("include_once").drop()
|
||||
sp.disable_function.function("require").drop()
|
||||
sp.disable_function.function("include").drop()
|
||||
|
||||
# Prevent `system`-related injections
|
||||
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
|
||||
sp.disable_function.function("shell_exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
|
||||
sp.disable_function.function("exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
|
||||
sp.disable_function.function("proc_open").param("command").value_r("^gpg ").allow();
|
||||
sp.disable_function.function("proc_open").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
|
||||
|
||||
# Prevent runtime modification of interesting things
|
||||
sp.disable_function.function("ini_set").param("option").value("assert.active").drop();
|
||||
sp.disable_function.function("ini_set").param("option").value("zend.assertions").drop();
|
||||
sp.disable_function.function("ini_set").param("option").value("memory_limit").drop();
|
||||
sp.disable_function.function("ini_set").param("option").value("include_path").drop();
|
||||
sp.disable_function.function("ini_set").param("option").value("open_basedir").drop();
|
||||
|
||||
# Detect some backdoors via environment recon
|
||||
sp.disable_function.function("ini_get").param("option").value("allow_url_fopen").drop();
|
||||
sp.disable_function.function("ini_get").param("option").value("open_basedir").drop();
|
||||
sp.disable_function.function("ini_get").param("option").value_r("suhosin").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("eval").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("exec").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("system").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("shell_exec").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("proc_open").drop();
|
||||
sp.disable_function.function("function_exists").param("function").value("passthru").drop();
|
||||
sp.disable_function.function("is_callable").param("value").value("eval").drop();
|
||||
sp.disable_function.function("is_callable").param("value").value("exec").drop();
|
||||
sp.disable_function.function("is_callable").param("value").value("system").drop();
|
||||
sp.disable_function.function("is_callable").param("value").value("shell_exec").drop();
|
||||
sp.disable_function.function("is_callable").filename_r("/app/libraries/snappymail/pgp/gpg\.php$").param("value").value("proc_open").allow();
|
||||
sp.disable_function.function("is_callable").param("value").value("proc_open").drop();
|
||||
sp.disable_function.function("is_callable").param("value").value("passthru").drop();
|
||||
|
||||
# Ghetto error-based sqli detection
|
||||
#sp.disable_function.function("mysql_query").ret("FALSE").drop();
|
||||
#sp.disable_function.function("mysqli_query").ret("FALSE").drop();
|
||||
#sp.disable_function.function("PDO::query").ret("FALSE").drop();
|
||||
|
||||
# Ensure that certificates are properly verified
|
||||
sp.disable_function.function("curl_setopt").param("value").value("1").allow();
|
||||
sp.disable_function.function("curl_setopt").param("value").value("2").allow();
|
||||
# `81` is SSL_VERIFYHOST and `64` SSL_VERIFYPEER
|
||||
sp.disable_function.function("curl_setopt").param("option").value("64").drop().alias("Please don't turn CURLOPT_SSL_VERIFYCLIENT off.");
|
||||
sp.disable_function.function("curl_setopt").param("option").value("81").drop().alias("Please don't turn CURLOPT_SSL_VERIFYHOST off.");
|
||||
|
||||
# File upload
|
||||
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ph").drop();
|
||||
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ht").drop();
|
||||
|
||||
# Logging lockdown
|
||||
sp.disable_function.function("ini_set").param("option").value_r("error_log").drop()
|
||||
sp.disable_function.function("ini_set").param("option").value_r("display_errors").drop()
|
||||
|
||||
sp.auto_cookie_secure.enable();
|
||||
sp.cookie.name("roundcube_sessauth").samesite("strict");
|
||||
sp.cookie.name("roundcube_sessid").samesite("strict");
|
||||
sp.ini_protection.policy_silent_fail();
|
||||
@@ -51,7 +51,9 @@ if not secret_key:
|
||||
print(f"Can't read SECRET_KEY from file: {exc}", file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
context['SECRET_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUNDCUBE_KEY', 'utf-8'), 'sha256').hexdigest()
|
||||
context['ROUNDCUBE_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUNDCUBE_KEY', 'utf-8'), 'sha256').hexdigest()
|
||||
context['SNUFFLEPAGUS_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('SNUFFLEPAGUS_KEY', 'utf-8'), 'sha256').hexdigest()
|
||||
conf.jinja("/etc/snuffleupagus.rules.tpl", context, "/etc/snuffleupagus.rules")
|
||||
|
||||
# roundcube plugins
|
||||
# (using "dict" because it is ordered and "set" is not)
|
||||
@@ -118,7 +120,7 @@ if os.path.exists("/var/run/nginx.pid"):
|
||||
os.system("nginx -s reload")
|
||||
|
||||
# clean env
|
||||
[env.pop(key, None) for key in env.keys() if key == "SECRET_KEY" or key.startswith("ROUNDCUBE_")]
|
||||
[env.pop(key, None) for key in env.keys() if key == "SECRET_KEY" or key.endswith("_KEY")]
|
||||
|
||||
# run nginx
|
||||
os.system("php-fpm81")
|
||||
|
||||
Reference in New Issue
Block a user