Seafile mit WAF/Antivirus unter Ubuntu 18.04


Installation ‚aller‘ notwendigen Anwendungen/Module

# apt update
# apt upgrade

# apt install joe vim ntp ssh openssl ldap-utils
# apt install apache2 libapache2-mod-security2 libapache2-mod-fcgid
# apt install php-mbstring php-gettext
# apt install perl python
# apt install php python-flup libapache2-mod-php
# apt install mysql-server php-mysql
# apt install clamav clamav-daemon
# apt install poppler-utils libreoffice libreoffice-script-provider-python python2.7 # libpython2.7 python-pip mysql-server python-setuptools python-imaging python-mysqldb python-memcache python-ldap
# apt install python-pip

Neustart des Systems

Prüfen, ob modsecurity aktiv ist

# apachectl -M | grep security
security2_module (shared)

Modsecurity konfigurieren

# mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

# vi /etc/modsecurity/modsecurity.conf

SecRuleEngine On
 
SecRequestBodyAccess On
 
SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
     "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
 
SecRule REQUEST_HEADERS:Content-Type "application/json" \
     "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
 
SecRequestBodyLimit 9663676416
 
SecRequestBodyNoFilesLimit 131072
 
SecRequestBodyInMemoryLimit 131072
 
SecRequestBodyLimitAction Reject
 
SecRule REQBODY_ERROR "!@eq 0" \
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
 
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"id:'200003',phase:2,t:none,log,deny,status:400, \
msg:'Multipart request body failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
 
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
 
SecPcreMatchLimit 100000
SecPcreMatchLimitRecursion 100000
 
SecRule TX:/^MSC_/ "!@streq 0" \
        "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
 
SecResponseBodyAccess On
 
SecResponseBodyMimeType text/plain text/html text/xml
 
SecResponseBodyLimit 524288
 
SecResponseBodyLimitAction ProcessPartial
 
SecTmpDir /tmp/
 
SecDataDir /tmp/
 
SecUploadDir /tmp/
 
SecAuditEngine RelevantOnly
 
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
 
SecAuditLogParts ABDEFHIJZ
 
SecAuditLogType Serial
 
SecAuditLog /var/log/apache2/modsec_audit.log
 
SecArgumentSeparator &
 
SecCookieFormat 0
 
SecUnicodeMapFile unicode.mapping 20127
 
SecStatusEngine On
 
SecTmpSaveUploadedFiles On

Aktuelles ModSecurity Core Rule Set (CRS) herunterladen

# mv /usr/share/modsecurity-crs/ /usr/share/modsecurity-crs~
# export GIT_SSL_NO_VERIFY=1
# git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git /usr/share/modsecurity-crs
# cd /usr/share/modsecurity-crs
# cp crs-setup.conf.example crs-setup.conf

# vi /etc/apache2/mods-enabled/security2.conf

<IfModule security2_module>
        # Default Debian dir for modsecurity's persistent data
        SecDataDir /var/cache/modsecurity
 
        # Include all the *.conf files in /etc/modsecurity.
        # Keeping your local configuration in that directory
        # will allow for an easy upgrade of THIS file and
        # make your life easier
        IncludeOptional /etc/modsecurity/*.conf
 
        # Include OWASP ModSecurity CRS rules if installed
        # IncludeOptional /usr/share/modsecurity-crs/owasp-crs.load
 
        IncludeOptional /usr/share/modsecurity-crs/*.conf
        IncludeOptional /usr/share/modsecurity-crs/rules/*.conf
</IfModule>

# systemctl restart apache2

Testen der Konfiguration

# vi /var/www/html/test.html

<!DOCTYPE html>
<html>
<body>
 
<form action="upload.php" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload Image" name="submit">
</form>
 
</body>
</html>

# vi /var/www/html/upload.php

<?php
$target_dir = "/tmp/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
 
// Check if file already exists
if (file_exists($target_file)) {
    echo "Sorry, file already exists.";
    $uploadOk = 0;
}
// Check file size
#if ($_FILES["fileToUpload"]["size"] > 500000) {
#    echo "Sorry, your file is too large.";
#    $uploadOk = 0;
#}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
    echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
    } else {
        echo "Sorry, there was an error uploading your file.";
    }
}
?>

# vi /usr/share/modsecurity-crs/rules/REQUEST-000-AV.conf

SecRule FILES_TMPNAMES "@inspectFile /usr/share/modsecurity-crs/util/av-scanning/runav.pl" \
        "phase:2,t:none,block,msg:'Virus found in uploaded file',id:'950115',tag:'MALICIOUS_SOFTWARE/VIRUS',tag:'PCI/5.1',severity:'2',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-MALICIOUS_SOFTWARE/VIRUS-%{matched_var_name}=%{tx.0}"

Testen des Upload mittels http://ip-adresse/test.html.

Erscheint nun beim Upload einer Malware-Datei „Forbidden – You don’T have permission to access …“ funktioniert der Filter.
Das ganze kann auch im log ( /var/log/apache/modsec_audit.log ) geprüft werden.

MySQL-Anpassungen

Bei der MySQL-Installation wurde nicht nach einem Passwort gefragt.
Um die Passwortbasierte Anmeldung zu aktivieren, und das Passwort zu ändern folgende Schritte ausführen:

# mysql -u root
(keine Passwortabfrage!)
mysql> USE mysql;
Database changed
mysql> UPDATE user SET plugin=’mysql_native_password‘ WHERE User=’root‘;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
mysql> exit;
Bye

# mysql_secure_installation

Prüfen, ob die Änderungen erfolgreich waren:
# mysql -u root -p

Installation Seafile

# apt-get install python2.7 libpython2.7 python-setuptools python-pil python-ldap python-urllib3 ffmpeg python-pip python-mysqldb python-memcache
NOT DONE: # pip install pillow moviepy
# mkdir /opt/seafile
# mkdir /opt/seafile/installed
# cd /opt/seafile/installed/

# wget –no-check-certificate https://download.seadrive.org/seafile-server_6.2.5_x86-64.tar.gz
# cd ..
# tar xzfv installed/seafile-server_6.2.5_x86-64.tar.gz
# cd seafile-server-6.2.5/

# ./setup-seafile-mysql.sh
[Konfiguration durchführen]

Danach die Dienste einmal starten (es wird nach einem admin account gefragt)
# /opt/seafile/seafile-server-latest/seafile.sh start
# /opt/seafile/seafile-server-latest/seahub.sh start

Startskript erstellen

# adduser –disabled-login –gecos „seafile“ seafile –home /opt/seafile/
# chown -R seafile:seafile /opt/seafile/

# vi /etc/init.d/seafile-server

#!/bin/bash
### BEGIN INIT INFO
# Provides:          seafile-server
# Required-Start:    $local_fs $remote_fs $network mysql
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Seafile server
# Description:       Start Seafile server
### END INIT INFO

# Change the value of "user" to your linux user name
user=seafile

# Change the value of "seafile_dir" to your path of seafile installation
seafile_dir=/opt/seafile
script_path=${seafile_dir}/seafile-server-latest
seafile_init_log=${seafile_dir}/logs/seafile.init.log
seahub_init_log=${seafile_dir}/logs/seahub.init.log

# Change the value of fastcgi to true if fastcgi is to be used
fastcgi=false
# Set the port of fastcgi, default is 8000. Change it if you need different.
fastcgi_port=8000

case "$1" in
        start)
                sudo -u ${user} ${script_path}/seafile.sh start >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh start-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh start >> ${seahub_init_log}
                fi
        ;;
        restart)
                sudo -u ${user} ${script_path}/seafile.sh restart >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh restart-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh restart >> ${seahub_init_log}
                fi
        ;;
        stop)
                sudo -u ${user} ${script_path}/seafile.sh $1 >> ${seafile_init_log}
                sudo -u ${user} ${script_path}/seahub.sh $1 >> ${seahub_init_log}
        ;;
        *)
                echo "Usage: /etc/init.d/seafile-server {start|stop|restart}"
                exit 1
        ;;
esac

# chmod +x /etc/init.d/seafile-server
# update-rc.d seafile-server defaults

Es kommt vor, daß der Seafile Server nach einem Neustart nicht startet. Daher habe ich den Startaufruf nochmals in einen CronJob eingefügt.
# crontab -e

@reboot sleep 120 && service seafile-server start
@reboot sleep 240 && service seafile-server start

Nun ist es Zeit für einen Neustart um zu sehen, ob der Server auch erfolgreich startet.

Apache inkl. https konfigurieren

# a2enmod rewrite
# a2enmod fcgid
# a2enmod proxy_http
# a2enmod proxy_fcgi
# a2enmod ssl

?? # vi /etc/apache2/apache2.conf
?? (am besten am Ende einfügen)
??

?? ...
?? FastCGIExternalServer /var/www/seahub.fcgi -host 127.0.0.1:8000
?? ...
?? 

# vi /etc/apache2/sites-available/transfer.conf

# Redirection of port 80 to port 443

  ServerName transfer.demo.hoelzle.net
  KeepAlive Off
  RewriteEngine On
  RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

# vi /etc/apache2/sites-available/transfer-ssl.conf


  ServerName transfer.demo.hoelzle.net
  DocumentRoot /var/www
  Alias /media /opt/seafile/seafile-server-latest/seahub/media

  SSLEngine On
  SSLCertificateFile /etc/ssl/certs/wildcard-demo-hoelzle-net.cer
  SSLCertificateKeyFile /etc/ssl/private/wildcard-demo-hoelzle-net.key
  SSLCertificateChainFile /etc/ssl/certs/GlobalSignG2.crt
  SSLCACertificateFile /etc/ssl/certs/AlphaSSL.crt

  RewriteEngine On
  
   Require all granted
  

  #
  # seafile httpserver
  #
  ProxyPass /seafhttp http://127.0.0.1:8082
  ProxyPassReverse /seafhttp http://127.0.0.1:8082
  RewriteRule ^/seafhttp - [QSA,L]

  #
  # seahub
  #
  SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
  ProxyPass / http://127.0.0.1:8000/
  ProxyPassReverse / http://127.0.0.1:8000/


Anpassen der URL (http -> https und den Port 8000 entfernen)
# vi /opt/seafile/conf/ccnet.conf
[…]
SERVICE_URL = https://transfer.demo.hoelzle.net
[…]

# vi /opt/seafile/conf/seahub_settings.py

[...]
FILE_SERVER_ROOT = 'https://transfer.demo.hoelzle.net/seafhttp'
[...]

# a2dissite 000-default.conf
# a2ensite transfer.conf
# a2ensite transfer-ssl.conf
# service apache2 restart

Hiermit ist die eigentliche Installation beendet.

Cleanup script

Erstellen eines Skripts, um jeden Sonntag um 2 Uhr den Bereinigungsvorgang zu starten.

# mkdir /opt/seafile/script
# vi /opt/seafile/script/sfcleanup.sh

#!/bin/bash
/etc/init.d/seafile-server stop
sleep 10
sudo -u seafile /opt/seafile/seafile-server-latest/seaf-gc.sh -r
sleep 5
/etc/init.d/seafile-server start
echo Seafile cleanup done!

# chmod +x /opt/seafile/script/sfcleanup.sh
# crontab -e

0 2 * * Sun /opt/seafile/script/sfcleanup.sh