# Förhindra XSS i PHP: avvärj cross-site scripting säkert

> Förhindra XSS i PHP: koda utdata rätt efter sammanhang, använd mallar med auto-escaping och sätt en Content Security Policy. Med exempel.

Källa: https://phpsos.de/sv/ratgeber/xss-php/  
Aktualitet: 2026-10-25  
Leverantör: PHP SOS, PHP-nödhjälp och serversäkerhet. Omedelbar hjälp via WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20beh%C3%B6ver%20hj%C3%A4lp%20med%20v%C3%A5r%20PHP-server.%20F%C3%B6retag%3A%20%E2%80%A6%20Webbplats%3A%20%E2%80%A6

**Kort sagt:** XSS i PHP förhindrar ni genom att koda varje utmatning efter sitt sammanhang: `htmlspecialchars()` för HTML, `json_encode()` med skyddsalternativ för JavaScript, granskade URL:er för länkar. Mallar med automatisk escaping tar över mycket av detta. En Content Security Policy och HttpOnly-cookies begränsar skadan om en sårbarhet ändå finns kvar.

## Varför cross-site scripting bör granskas nu

Uppmärksamheten ligger i oktober 2026 på PHP2Shell, två kritiska sårbarheter i PHP-tolken, för vilka patchar finns sedan den 21 oktober 2026. Många företag låter i den vevan granska sina webbapplikationer. Det är ett bra tillfälle att också titta på svagheter i den egna koden som ingen PHP-uppdatering åtgärdar.

Cross-site scripting, kort XSS, är en av dem. OWASP Top 10 för XSS inom kategorin injektion. Till skillnad från en sårbarhet i servern riktar sig angreppet här mot besökare och användare av er webbplats, till exempel kunder i butiken eller medarbetare i backend.

Följderna kan bli betydande: övertagna sessioner hos administratörer, manipulerade formulär som skickar data till tredje part eller förfalskat innehåll på er webbplats. Tas ett administratörskonto över kan det leda ända till fullständig kontroll över applikationen.

## Hur uppstår XSS i PHP-applikationer?

XSS uppstår när en applikation matar ut data från en ej tillförlitlig källa ogranskade på en sida. Webbläsaren kan då inte längre skilja mellan ert innehåll och insmugglad kod och kör båda.

Man skiljer på tre former. Vid reflekterad XSS kommer innehållet direkt från den aktuella förfrågan, till exempel från en sökterm i URL:en. Vid lagrad XSS ligger det i databasen, till exempel i en kommentar eller ett profilfält, och drabbar var och en som öppnar sidan. DOM-baserad XSS uppstår i webbläsarens JavaScript när skript skriver in värden från URL:en på sidan.

Ej tillförlitliga är alla data som inte står fast i koden: formulärfält, URL-parametrar, cookies, filnamn, svar från externa gränssnitt och innehåll från den egna databasen som någon gång kom utifrån.

## Koda utdata rätt efter sammanhang

Den viktigaste regeln lyder: Koda vid utmatningen, och anpassat till platsen där värdet hamnar. För HTML-innehåll och attribut med citattecken är `htmlspecialchars()` rätt medel. En liten hjälpfunktion hindrar att alternativ glöms bort:

```php
<?php
function e(?string $wert): string
{
    return htmlspecialchars($wert ?? '', ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
?>
<h2><?= e($produkt['name']) ?></h2>
<input type="text" name="suche" value="<?= e($_GET['q'] ?? '') ?>">
```

Andra sammanhang kräver andra medel:

| Sammanhang | Säker metod |
|---|---|
| HTML-innehåll, attribut med citattecken | `htmlspecialchars()` med `ENT_QUOTES` och UTF-8 |
| Data för JavaScript | `json_encode()` med `JSON_HEX_TAG`, `JSON_HEX_AMP`, `JSON_HEX_APOS`, `JSON_HEX_QUOT` |
| Parameter i en URL | `rawurlencode()` för det enskilda värdet |
| Fullständig URL från användarinmatning | Kontrollera schemat, tillåt bara `https` och `http`, sedan `htmlspecialchars()` |
| Attribut utan citattecken, event handlers, CSS | undvik, sätt inte in värden där |

För data som ett skript behöver är ett dataattribut eller ett JSON-block oftast den renaste vägen:

```php
<?php
$daten = json_encode($konfiguration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<div id="app" data-konfig="<?= e($daten) ?>"></div>
```

I JavaScript läser ni sedan ut värdet via dataattributet och sätter innehåll med `textContent` i stället för med `innerHTML`.

## Mallar, HTML-rensning och ramverk

Mallmotorer som Twig och Blade kodar utdata automatiskt som standard. Det utesluter en stor del av de typiska felen. Farligt blir det där det beteendet medvetet stängs av, till exempel med filtret `raw` i Twig eller syntaxen `{!! !!}` i Blade. Sådana ställen bör vara sällsynta i koden och granskas riktat vid varje kodgranskning.

Ska er applikation medvetet tillåta HTML från användare, till exempel formatering i kommentarer eller i ett redaktionssystem, räcker inte kodning, eftersom HTML:en ju ska visas. Då behöver ni ett granskat rensningsbibliotek som HTML Purifier, som bara släpper igenom en fast lista med tillåtna element och attribut. Egna filter med reguljära uttryck är erfarenhetsmässigt luckfulla.

> **Viktigt:**
> Granska särskilt backend-områden. XSS i vyer som bara administratörer ser underskattas ofta, men drabbar just de konton som har flest rättigheter.

## Hitta XSS i befintlig PHP-kod

I etablerade applikationer är den första frågan oftast inte hur man kodar rätt utan var det hittills har glömts. En pragmatisk början är att söka efter ställen där variabler matas ut direkt:

```bash
# Direkt utmatning av förfrågningsdata
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Avstängd auto-escaping i Twig och Blade
grep -rnE "\|raw|\{!!" templates/ resources/views/
```

Träffar är kontrolluppdrag, inga färdiga fynd. Lagrad XSS hittar en sådan sökning bara delvis, eftersom värdena där kommer från databasen. Granska därför dessutom alla vyer som visar innehåll från användare: kommentarer, profiler, ordernoteringar, supportärenden. Vid CMS och butiker hör tillägg och teman från tredje part uttryckligen dit, för där sitter en stor del av utmatningslogiken.

## Andra försvarslinjen: CSP och säkra cookies

Även med noggrann kod kan ett ställe förbises. Två åtgärder begränsar då skadan. En Content Security Policy tillåter webbläsaren bara skript från fastlagda källor och förbjuder inbäddade skript om de inte uttryckligen frisläpps:

```apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
```

Inför en sådan policy stegvis, först i rent rapportläge via `Content-Security-Policy-Report-Only`, eftersom befintliga inbäddningar av analys- eller betaltjänster oftast måste kompletteras. Fler headers beskriver guiden [Säkerhetsheaders för webbplatser](https://phpsos.de/sv/ratgeber/sicherheits-header/).

Dessutom bör sessionscookies ha attributet `HttpOnly`, så att skript inte kan läsa dem. Hur ni skyddar sessioner i stort står i guiden [Säkra sessioner i PHP](https://phpsos.de/sv/ratgeber/session-sicherheit-php/). En närliggande svaghet på databassidan behandlar [Förhindra SQL-injektion i PHP](https://phpsos.de/sv/ratgeber/sql-injection-php/).

## Hur hjälper PHP SOS konkret?

- Vi granskar mallar och utmatningar i er applikation efter saknad eller felaktig kodning.
- Vi bedömer fynd efter nåbarhet och berörda konton och visar konkreta rättelser.
- Vi inför en Content Security Policy stegvis, utan att störa butiks- eller betalfunktioner.
- Vi testar på nytt efter rättelsen och dokumenterar resultatet.

En oberoende granskning beskriver tjänsten [Säkerhetsgranskning och penetrationstest](https://phpsos.de/sv/leistungen/sicherheitsaudit-penetrationstest/).


## Vanliga frågor

**Räcker htmlspecialchars mot XSS?**  
För vanlig text i HTML-innehåll och i attribut med citattecken, ja, om ni anger ENT_QUOTES och teckenuppsättningen UTF-8. I JavaScript, i URL:er eller i CSS gäller andra regler, där krävs en egen, lämplig kodning.

**Ska jag filtrera indata vid lagring eller vid utmatning?**  
Koda vid utmatning, anpassat efter målet. Indata bör ni kontrollera för rimlighet vid mottagandet, till exempel längd och format. Den som bara filtrerar vid lagring missar data från andra källor och försvårar senare användning i andra sammanhang.

**Vad ger en Content Security Policy?**  
En Content Security Policy fastställer från vilka källor webbläsaren får ladda och köra skript. Den kan avsevärt begränsa följderna av en förbisedd XSS-sårbarhet men ersätter inte korrekt kodning.

**Hur tillåter jag formatering som fet stil eller länkar i kommentarer?**  
Använd ett granskat bibliotek för HTML-rensning med en vitlista över tillåtna element och attribut. Egna reguljära uttryck för att ta bort skript är felbenägna och bör inte användas.

## Källor

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net: säkerhetsmeddelanden](https://www.php.net/)
