Premessa

Obiettivo della guida è mettere in piedi un computer con wordpress accessibile solo tramite un onion service noto

Partiamo da 2 debian buster "pulite", appena installate. Di una di esse (il backend) sarà nascosta la posizione, l’IP, e ogni altro dettaglio; l’unico dettaglio del backend che verrà reso pubblico è il suo indirizzo .onion. La seconda macchina (il frontend) invece è del tutto pubblica. Le due macchine non condividono alcun dato segreto di nessun tipo. Qualsiasi macchina su Internet potrebbe svolgere il ruolo di frontend, anche non gestita dalle stesse persone che gestiscono il backend.

Backend

ovvero la macchina "nascosta"

Installazione

Passo 1: installare tor e configurare onion service

apt install tor iptables-persistent

Aggiungiamo al file /etc/tor/torrc le righe

/etc/tor/torrc
HiddenServiceDir /var/lib/tor/website/
HiddenServiceVersion 3
HiddenServicePort 80 127.0.0.1:80
HiddenServiceDir /var/lib/tor/ssh/
HiddenServiceVersion 3
HiddenServicePort 22 127.0.0.1:22

Riavviamo Tor

systemctl restart tor
head /var/lib/tor/*/hostname

Prendere nota degli indirizzi che appaiono: sono due indirizzi separati per entrare in ssh e per accedere al sito. Tenere segreto l’indirizzo ssh! Sara' parte delle misure di sicurezza per gestire il sito senza rivelarne la posizione.

Prima di proseguire al passo due, assicurati di essere in grado di raggiungere il computer usando ssh su onion service. Per fare questo, usa il comando:

torify ssh nomeutente@blablabla.onion # (1)
  1. blablabla.onion va sostituito con l’indirizzo onion mostrato dopo il riavvio di Tor sul tuo terminale.

Warning
NON proseguire al passo 2 finche' questo non funziona, o rimarrai chiuso fuori!

Passo 2: configurare wordpress

apt install apache2 unzip php-fpm php-mysql default-mysql-server iptables-persistent
wget https://avana.forteprenestino.net/progetti/hidden-wordpress/v1.0/backend.tar.gz
tar -C / -xzf backend.tar.gz
cd /var/www/
wget -nv 'https://wordpress.org/latest.zip'
unzip latest.zip
chown -R www-data. wordpress/
a2enmod proxy_fcgi setenvif rewrite
a2enconf 'php7*'

cd /var/www/wordpress; mv wp-content/ contents

sed -i 's+/var/www/html+/var/www/wordpress+' /etc/apache2/sites-enabled/000-default.conf

Aggiungere le seguenti righe nel wp-config.php. immediatamente prima di require_once( ABSPATH . 'wp-settings.php' );

define ('WP_CONTENT_FOLDERNAME', 'contents');
define ('WP_CONTENT_DIR', ABSPATH . WP_CONTENT_FOLDERNAME) ;
define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST'] . '/');
define('WP_CONTENT_URL', WP_SITEURL . WP_CONTENT_FOLDERNAME);

editiamo il file /etc/php/7.*/fpm/pool.d/www.conf :

  • rinominiamo il pool in wordpress

  • mettiamo chdir = /var/www/$pool

  • mettiamo php_admin_value[memory_limit] = 128M

  • mettiamo php_admin_value[display_errors] = off

systemctl restart apache2
systemctl restart 'php7*'

tr -dc '[:alnum:]' < /dev/urandom 2> /dev/null| head -c 64; echo  # (1)
mysql
CREATE DATABASE IF NOT EXISTS  wordpress;
CREATE USER 'wordpress'@'127.0.0.1';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'127.0.0.1' IDENTIFIED BY 'PasswordDiPrima'; # (2)

cd /var/www/wordpress
cp wp-config-sample.php wp-config.php
# editare il file wp-config.php inserendo
#   DB_USER      wordpress
#   DB_NAME      wordpress
#   DB_HOST      127.0.0.1
#   DB_PASSWORD  PasswordDiPrima

#   AUTH_KEY   una password casuale generata con lo stesso comando di prima (tr blabla)
# stessa cosa per secure_auth_key, logged_in_key, nonce_key, auth_salt, secure_auth_salt, logged_in_salt, nonce_salt
#   $table_prefix = 'wp_QualcheLetteraCasuale_'
# ad esempio #wp_jQtZfLL_

#nel wp-config.php
AUTOMATIC_UPDATER_DISABLED
DISALLOW_FILE_MODS
DISABLE_WP_CRON
  1. genera una password sicura; segnatela un attimo, dovrai poi usarla come password del database poche righe piu' avanti

  2. inserisci qui la password che hai generato poco fa

Aprire il torbrowser e andare su http://NomeOnionServiceHttps.onion/ dovrebbe chiedervi il nome del sito, e la creazione di un account di admin. Occhio: 1. scegliete una password sicura (ve ne propone una, salvatevela da qualche parte) 1. NON usate l’account di admin tutto il tempo. Usatelo solo per amministrazione. Fatevi un altro account con permessi piu' bassi

Per il computer di backend abbiamo concluso qui, ma…​ fate l’hardening, e' importante!

Passo 3: Hardening

Hardening: permettere accesso SSH solo da onion service

Prima di tutto verifica di essere in grado di entrare sul sistema attraverso onion service. Sul tuo computer, fai

torify ssh onionserviceSSH.onion (1)
  1. Ovviamente qui bisogna riportare l’onion service che abbiamo visualizzato nel passo 1 con il comando head

e vedi se funziona. Se va tutto bene, aprire /etc/ssh/sshd_config e cambiare il ListenAddress a 127.0.0.1 dopodiché lanciate systemctl reload ssh.

Hardening: php
php_admin_value[disable_functions] = assert,eval,system,proc_open,popen,show_source,symlink,safe_mode,allow_url_fopen

Far girare php come utente dedicato php-wordpress, lasciare tutti i file di proprieta' di root, tranne la wp-content/uploads/ che deve essere di proprieta' di php-wordpress

chiudere ogni porta in ingresso
fare in modo che wordpress non possa comunicare con l’esterno (iptables)

Con questo comando le connessioni con l’esterno saranno limitate a root e a Tor. Inoltre solo root si potra' connettere a Tor, per evitare che altri utenti possano usare Tor per esfiltrare messaggi.

iptables -A OUTPUT  -m owner --uid-owner debian-tor -j ACCEPT
iptables -A OUTPUT  -m owner --uid-owner root -j ACCEPT

iptables -A OUTPUT -d 127.0.0.0/8 -j ACCEPT
iptables -P OUTPUT DROP
iptables-save > /etc/iptables/rules.v4
Caution
Verificate bene, prima di applicare queste regole, o vi butterete fuori dal sistema
accesso solo con chiave pubblica

Configuratevi le chiavi pubbliche sul vostro computer. Dopo aver fatto questo, e testato di essere in grado di entrare sul sistema senza bisogno di password, andate nel file /etc/ssh/sshd_config, mettere

PasswordAuthentication no
Caution
Verificate bene, prima di applicare queste regole, o vi butterete fuori dal sistema

Manutenzione

Le regole di hardening che abbiamo impostato rendono leggermente più complicate alcune procedure di manutenzione ordinaria.

Installazione nuovi plugin

In un’installazione "normale" di wordpress, i plugin si possono installare dall’interfaccia web. Questo, per motivi di sicurezza, è stato bloccato. Come si fa, dunque ad installare un plugin?

cd /var/www/wordpress/wp-content/plugins/
wget wordpress.org/blablabla.zip
unzip blablabla.zip

Aggiornamento wordpress

TODO

Frontend

apt install varnish tor socat apache2
wget https://avana.forteprenestino.net/progetti/hidden-wordpress/v1.0/frontend.tar.gz
tar -C / -xzf frontend.tar.gz

Creare un file /etc/default/tunnel.env con dentro:

/etc/default/tunnel.env
HS=IltuoOnionServiceWeb.onion

dove ovviamente al posto di IltuoOnionServiceWeb dovete mettere l’indirizzo del vostro servizio web

Caution
Non mettete qui l’onion service del servizio ssh, ma quello dedicato all’HTTP

In /etc/systemd/system/tunnel_hs.service mettere

/etc/systemd/system/tunnel_hs.service
[Unit]
Description=TCP proxy for onion service

[Service]
Type=simple
EnvironmentFile=/etc/default/tunnel.env
ExecStart=/usr/bin/socat -d -lydaemon TCP4-LISTEN:8080,fork,bind=localhost,reuseaddr,retry SOCKS4A:localhost:${HS}:80,socksport=9050
PrivateTmp=true
NoNewPrivileges=true
RestartSec=5
Restart=on-failure

[Install]
WantedBy=multi-user.target

fare poi mkdir /etc/systemd/system/varnish.service.d/

/etc/systemd/system/varnish.service.d/override.conf
[Service]
EnvironmentFile=/etc/default/tunnel.env

In fondo ad /etc/apache2/envvars, inserire la riga:

. /etc/default/tunnel.env
export HS
/etc/varnish/default.vcl
vcl 4.0;
import std;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    unset req.http.accept-encoding;
    set req.http.host = std.getenv("HS");
}
sub vcl_deliver {
    unset resp.http.Link;
}

Configuriamo apache2 modificando il file /etc/apache2/sites-enabled/000-default.conf, trasformandolo in

/etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        ProxyPass / "http://localhost:6081/"
        ProxyPassReverse / "http://localhost:6081/"

        ProxyHTMLEnable On
        ProxyHTMLExtended On
        ProxyHTMLMeta On
        ProxyHTMLInterp On
        ProxyHTMLURLMap "http://${HS}/" "/" [v]
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Avviate il tutto con

systemctl daemon-reload
systemctl start tunnel_hs
systemctl enable tunnel_hs
a2enmod proxy_html proxy_http
systemctl restart varnish
systemctl restart apache2

Limiti

Questa guida si basa su alcune assunzioni, senza le quali il sistema va fatto in maniera diversa.

Molte configurazioni del Backend si basano sul fatto che c’e` un solo sito web da ospitare. Anche molti hardening fanno la stessa assunzione.

Se il backend viene serimanete compromesso, potrebbe essere rivelata la posizione del server (ma e` difficile). Se il backend viene compromesso, l’anonimato degli amministratori del sito potrebbe essere a rischio. Si raccomanda quindi di usare una versione di torbrowser aggiornata.

Meta

Questo documento è stato prodotto a partire da questo documento asciidoc e poi trasformato in html con

asciidoctor -b html5 -a toc --safe hidden-wordpress.asciidoc

Puoi copiarlo e tradurlo come ti pare, per scopi non commerciali.

Se vuoi tradurlo, parti dal file asciidoc, traducilo e ricompilalo.