seguridad: Wordfence desactiva las application passwords por defecto
Wordfence trae loginSec_disableApplicationPasswords=1 de fabrica. Con eso wp_is_application_passwords_available() devuelve false, la seccion desaparece del perfil sin dar ni un aviso, y la autenticacion por REST responde 401. Los bots de la carta publican asi (publicabot, de icalvotorre), o sea que estaban sin poder publicar y la carta 738 se compone manana. Lo introdujimos nosotros: en produccion Wordfence no estaba instalado, se anadio el 31-jul. No salio en el ensayo porque probamos lectura de la REST API pero nunca autenticacion. Lo detecto Inma; la traza es un 401 real suyo contra /wp-json/wp/v2/users/me a las 11:14 UTC. Aplicado en produccion y comprobado con su prueba de humo: POST a /wp-json/wp/v2/posts devuelve 201, y el ultimo uso de publicabot pasa de 29-jul a hoy. Se anade como paso 3e y no como arreglo de una vez porque el paso 3d reinstala Wordfence si falta, y una instalacion nueva vuelve a ponerlo a 1. Dos detalles del propio script, que fallaban en silencio: - va por heredoc y no por la funcion wp(), porque esa expande "$*" y se come las comillas del codigo PHP. - y sin --skip-plugins, o la clase wfConfig de Wordfence no existe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,10 @@ ADMINS_KO="pabloarias:1047:FEA_WP_PASS_PABLOARIAS josek:1049:FEA_WP_PASS_JOSEK a
|
|||||||
|
|
||||||
wp() { ssh -o BatchMode=yes "$SRV" "docker exec -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-plugins --skip-themes $*" 2>/dev/null; }
|
wp() { ssh -o BatchMode=yes "$SRV" "docker exec -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-plugins --skip-themes $*" 2>/dev/null; }
|
||||||
|
|
||||||
|
# Variante que SI carga los plugins. Hace falta para el paso 3e: sin ella la clase
|
||||||
|
# wfConfig de Wordfence no existe y el eval falla en silencio.
|
||||||
|
wpp() { ssh -o BatchMode=yes "$SRV" "docker exec -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-themes $*" 2>/dev/null; }
|
||||||
|
|
||||||
echo "=== 1. Rotar la contrasena de los 6 administradores ==="
|
echo "=== 1. Rotar la contrasena de los 6 administradores ==="
|
||||||
for entry in $ADMINS_OK $ADMINS_KO; do
|
for entry in $ADMINS_OK $ADMINS_KO; do
|
||||||
login=${entry%%:*}; rest=${entry#*:}; id=${rest%%:*}; var=${rest##*:}
|
login=${entry%%:*}; rest=${entry#*:}; id=${rest%%:*}; var=${rest##*:}
|
||||||
@@ -128,6 +132,42 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 3e. Wordfence NO debe bloquear las application passwords ==="
|
||||||
|
# Wordfence trae loginSec_disableApplicationPasswords=1 POR DEFECTO, y con eso
|
||||||
|
# wp_is_application_passwords_available() devuelve false: la seccion desaparece del
|
||||||
|
# perfil y, lo que importa, la autenticacion por REST falla con 401. Los bots de la
|
||||||
|
# carta publican asi (publicabot, de icalvotorre), o sea que con esto en 1 no publican.
|
||||||
|
#
|
||||||
|
# Detectado el 3-ago despues del cutover, con un 401 real de icalvotorre contra
|
||||||
|
# /wp-json/wp/v2/users/me. En produccion nunca paso porque alli Wordfence no estaba
|
||||||
|
# instalado; lo introdujimos nosotros al anadirlo.
|
||||||
|
#
|
||||||
|
# Va aqui y no una sola vez a mano porque el paso 3d reinstala Wordfence si falta, y
|
||||||
|
# una instalacion nueva vuelve a ponerlo a 1.
|
||||||
|
if [ $DRY -eq 1 ]; then
|
||||||
|
echo " [dry-run] pondria loginSec_disableApplicationPasswords a 0"
|
||||||
|
else
|
||||||
|
# Por heredoc y no por la funcion wp(): esa expande "$*" y se come las comillas
|
||||||
|
# del codigo PHP. Y SIN --skip-plugins, o la clase wfConfig no existe.
|
||||||
|
ssh -o BatchMode=yes "$SRV" "WPC=$WPC bash -s" <<'REMOTE'
|
||||||
|
W="docker exec -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-themes"
|
||||||
|
$W eval 'wfConfig::set("loginSec_disableApplicationPasswords", 0);' >/dev/null 2>&1
|
||||||
|
v=$($W eval 'echo var_export(wfConfig::get("loginSec_disableApplicationPasswords"), true);' 2>/dev/null)
|
||||||
|
echo " loginSec_disableApplicationPasswords = $v (tiene que ser '0')"
|
||||||
|
echo " disponibles?: $($W eval '$_SERVER["HTTPS"]="on"; echo wp_is_application_passwords_available() ? "SI" : "NO -- los bots no podran publicar";' 2>/dev/null)"
|
||||||
|
echo " application passwords que existen (no se tocan, se coordinan con Inma):"
|
||||||
|
$W eval '
|
||||||
|
foreach (get_users(["fields" => "ID"]) as $id) {
|
||||||
|
foreach (WP_Application_Passwords::get_user_application_passwords($id) as $p) {
|
||||||
|
$u = get_user_by("id", $id);
|
||||||
|
echo " ", $u->user_login, " / ", $p["name"], " ultimo uso ",
|
||||||
|
($p["last_used"] ? date("Y-m-d", $p["last_used"]) : "nunca"), PHP_EOL;
|
||||||
|
}
|
||||||
|
}' 2>/dev/null
|
||||||
|
REMOTE
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== 4. Verificacion ==="
|
echo "=== 4. Verificacion ==="
|
||||||
echo " administradores que quedan:"
|
echo " administradores que quedan:"
|
||||||
|
|||||||
Reference in New Issue
Block a user