mirror of
				https://github.com/optim-enterprises-bv/Mailu-OIDC.git
				synced 2025-10-30 01:32:22 +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
	 Florent Daigniere
					Florent Daigniere