00 / Arquitectura
Com està construït aquest web
Treballo en un SOC, així que aquest web és també una declaració d'intencions: si no fos capaç d'assegurar el meu propi lloc, poc tindria a aportar assegurant el de ningú. A sota hi ha les decisions que hi ha al darrere i el motiu de cadascuna, no una llista de tecnologies.
Resum del stack
- Frontend
- Astro 7 (SSG) · Tailwind CSS · TypeScript
- Backend
- PHP 8 (PDO) · MySQL / MariaDB · sin framework
- Infraestructura
- CDMON · Apache · Cloudflare · TLS
- Idiomes
- Español · English · Català
01 / Superficie d'atac del frontend
El lloc es compila a HTML pla, de manera que la major part del risc classic de servidor desapareix. El que queda es tanca per capcalera.
-
CSP amb hash recalculats a cada compilacio
script-src porta el SHA-256 de cada script del lloc i no inclou ‘unsafe-inline’. Un <script> injectat no s'executa: no pot portar un hash que la politica no conegui. Els hash es generen sols en compilar, no es mantenen a ma.
astro.config.mjs -
HSTS a un any, deliberadament sense preload
includeSubDomains actiu. Es deixa fora de la llista de precarrega expressament: entrar-hi es facil i sortir-ne triga mesos, i per a un portfolio aquest compromis no compensa.
server/.htaccess -
Aillament del document
X-Frame-Options DENY contra el clickjacking, Cross-Origin-Opener-Policy i Cross-Origin-Resource-Policy en same-origin, i Permissions-Policy que apaga geolocalitzacio, microfon i camera encara que res no les demani.
server/.htaccess -
Res de tercers
Sense CDN, sense Google Fonts, sense etiquetes d'analitica externa. Les tipografies van autoallotjades amb subset llati. Cada domini que es treu es un tercer menys que pot caure, canviar el fitxer que serveix o registrar la IP del visitant.
02 / Consola d'administracio
La part amb acces a la base de dades i a les pujades. Aqui es on el detall importa de debo.
-
Consultes preparades reals, no emulades
PDO amb ATTR_EMULATE_PREPARES a false. Amb l'emulacio activada el driver interpola els valors al client abans d'enviar-los, i aquesta interpolacio es justament on han viscut historicament els salts d'entrecometat en certs jocs de caracters.
server/db.php -
Login que no revela si l’usuari existeix
Contra un usuari inexistent es verifica igualment un hash fictici. Sense aquest pas, la resposta torna abans quan l'usuari no existeix i el temps permet enumerar comptes validos. Les contrasenyes van amb bcrypt i es rehashegen soles si puja el cost.
server/admin/auth.php -
CSRF en temps constant, amb el cas buit cobert
El token es compara amb hash_equals. A mes s'exigeix que el de la sessio existeixi i no estigui buit: sense aquesta condicio, una peticio sense galeta creava una sessio nova amb el token a cadena buida i la comparacio de dues cadenes buides retornava cert, deixant passar la peticio.
server/admin/auth.php -
Sessions endurides i amb caducitat doble
Regeneracio de l'identificador despres del login (fixacio de sessio), galetes HttpOnly, Secure i SameSite=Lax, use_strict_mode perque ningu no imposi un identificador propi, i tancament tant per inactivitat com per durada maxima absoluta.
server/admin/auth.php -
Bloqueig de forca bruta per IP
Els intents fallits es compten en una finestra temporal i bloquegen la IP en superar el llindar. La IP es pren de REMOTE_ADDR llevat que es declari explicitament un proxy de confianca: fiar-se de X-Forwarded-For sense proxy al davant permet falsejar la IP i saltar-se el limit sencer.
server/lib/http.php
03 / Contingut que no em pertany
Imatges pujades a la consola i missatges escrits per desconeguts: tot el que entra de fora es tracta com a hostil fins que es demostri el contrari.
-
Les imatges es validen per contingut, no per extensio
Primer el tipus MIME real amb finfo, i despres getimagesize(), que nomes reconeix imatges de debo. Un polyglot amb capcalera GIF falsificada passa el primer filtre pero no el segon. Hi ha a mes un topall de dimensions perque ningu no tombi el servidor amb una imatge de 30000 px de costat.
server/lib/upload.php -
La carpeta de pujades no executa codi
Defensa en profunditat: encara que la validacio fallés i s'hi colés un .php, el .htaccess d'aquella carpeta retira els handlers i apaga el motor, de manera que es serviria com a text pla. Els fitxers es desen amb nom aleatori, mai amb el que envia el client.
server/uploads/.htaccess -
El formulari no pot convertir-se en un relay de spam
S'eliminen salts de linia i caracters de control abans que cap valor toqui una capcalera de correu. Sense aquest sanejament, un nom amb CRLF permet injectar capcaleres (un Bcc:, per exemple) i fer servir el formulari per enviar correu a tercers.
server/api/contact.php -
Exportacions CSV sense injeccio de formules
Excel i LibreOffice executen com a formula qualsevol cel·la que comenci per =, +, - o @. Com que la safata exporta text escrit per desconeguts, aquestes cel·les es prefixen perque es tractin com a text i no com a codi en obrir el fitxer.
server/admin/partials/layout.php
04 / Analitica propia i privacitat
Saber quanta gent hi entra no exigeix muntar el perfil de ningu. L'analitica es propia i desa el minim.
-
L'adreca IP no s'emmagatzema
Es desa un SHA-256 de la IP amb una sal del servidor. Serveix per comptar visitants unics aproximats i per frenar floods, pero no permet reconstruir l'adreca ni creuar-la amb cap altra base de dades.
server/api/visit.php -
Sense galetes de seguiment i amb Do Not Track respectat
No hi ha bàner de consentiment perque no hi ha res a consentir. Si el navegador envia el senyal Do Not Track, la visita ni tan sols es registra.
-
Del referrer es descarta la query
Nomes es conserva esquema, host i ruta. Els parametres d'una URL aliena solen portar identificadors de sessio o de campanya, i no hi ha cap rao perque acabin a la meva base de dades.
server/api/visit.php -
Retencio acotada i purga automatica
Les visites s'esborren als 400 dies, els intents de login als 90 i el registre d'auditoria a l'any. La purga va incorporada al mateix flux, sense dependre d'un cron que ningu no recorda revisar.
server/api/visit.php
05 / SEO tecnic
Un portfolio que no apareix no serveix de res. El posicionament aqui es una questio d'estructura, no de repetir paraules clau.
-
Un unic graf de dades estructurades
Person, WebSite, ProfilePage, BreadcrumbList i FAQPage viatgen en un sol bloc JSON-LD enllacat per @id, en comptes de blocs solts que poden contradir-se entre ells. Cada article del blog hi afegeix el seu propi BlogPosting.
src/components/Seo.astro -
410 Gone en lloc de 404 per al que s’ha retirat
Dos projectes es van retirar del lloc amb les URL ja indexades. Un 404 diu al cercador que la pagina podria tornar, i la reintenta durant setmanes; un 410 li diu que la retirada es deliberada i definitiva, i la treu de l'index forca abans.
server/.htaccess -
hreflang reciproc, i nomes on hi ha traduccio
Cada pagina traduida declara totes les seves germanes i un x-default. Les que existeixen en un sol idioma no en declaren cap: anunciar un alternatiu que no existeix trenca el grup sencer, i Google llavors el descarta del tot.
src/pages/sitemap.xml.ts -
SEO local amb senyals coherents
Badalona i Barcelona apareixen al titol, a la descripcio, a les etiquetes geo i dins del bloc Person amb address, homeLocation i areaServed. El senyal importa quan es el mateix a tot arreu, no quan es repeteix en un sol lloc.
src/config.ts
06 / Llegible per a models de llenguatge
Cada cop es pregunta mes a un assistent i menys a un cercador. Si la resposta sobre mi l'ha de donar una IA, prefereixo que llegeixi dades ordenades i no que improvisi.
-
llms.txt generat a cada compilacio
Un resum en text pla seguint la convencio de llmstxt.org, sense HTML ni soroll. Surt de les mateixes fonts que alimenten el web, aixi que no pot quedar desfasat respecte del que es veu a la pantalla.
src/pages/llms.txt.ts -
Politica explicita per a rastrejadors d’IA
GPTBot, ClaudeBot, PerplexityBot, Google-Extended i Applebot tenen permis escrit. Els rastrejadors de SEO comercial, que nomes consumeixen amplada de banda de l'allotjament compartit, estan bloquejats. Es una decisio presa, no el resultat de no haver tocat el fitxer.
public/robots.txt -
Divulgacio de vulnerabilitats per RFC 9116
Un /.well-known/security.txt amb contacte, idiomes i data de caducitat. Es el primer que busca qui troba una fallada i la vol reportar be; no tenir-lo es la rao habitual que un avis acabi en un formulari generic o enlloc.
public/.well-known/security.txt -
Analisi estatica a cada push
CodeQL cobreix el frontend en TypeScript i JavaScript. Com que CodeQL no analitza PHP, el backend el revisa Semgrep amb regles d'injeccio, XSS i secrets, i tots dos resultats arriben en format SARIF a la mateixa pestanya. Dependabot vigila les dependencies cada setmana.
.github/workflows/codeql.yml
Cada punt d'aquesta pàgina correspon a codi que pots obrir al repositori. Si trobes res que no quadri, el canal per avisar-me és a /.well-known/security.txt
Mètriques de rendiment (PageSpeed Insights)
* Mesura sobre el servidor de producció de CDMON amb HTTPS i TLS actius. És una foto d'un moment concret, no una garantia permanent: comprova-ho tu mateix si t'interessa.