Der alte Walter: XSS bei generierten Inhalten in HTML

Beitrag lesen

Hallo,

ich bin online auf teils widersprüchliche Aussagen gestoßen und würde nun gerne für mehr Klarheit sorgen...

Ausgangssituation: ich weise via JavaScript FETCH requests mein PHP Script an, Daten in eine JSON zu schreiben, bzw. Daten aus der JSON Datei zu laden.

(Dies ist für meinen Usecase ausreichend, da das System im Endeffekt nur von einer Handvoll Personen genutzt wird und auch nicht öffentlich im Netz zugänglich sein wird. Im Prinzip sind daher XSS Attacken eigentlich nahezu auszuschließen – dennoch: entweder entwickle ich etwas richtig (OWASP konform) oder eben gar nicht... 🤪)

Ursprünglich sah meine Lösung vor, vor Speicherung in die JSON Datei sämtliche Inputs zu reinigen:

// PHP
function sanitizeStr(string $str): string {
    return trim(htmlspecialchars($str ?? '', ENT_QUOTES, 'UTF-8'));
}

Das führte erwarteterweise zu Problemen, da nun Strings im HTML zum Zeitpunkt der Darstellung nicht mehr korrekt dargestellt wurden, z.B. " Zitat 1 " & " Zitat 2 "

Darüber hinaus werden diese Zeichen aber von Input Feldern SEHR WOHL interpretiert, was zu einer Diskrepanz zwischen HTML Text und dem Text in den Input Feldern führt. Daher passen nun gewisse Input Felder zur Bearbeitung des HTML Textes nun nicht mehr zu ebendiesen.

Ich habe sanitizeStr daher aus meinem Code gestrichen.

Momentan behelfe ich mir damit, den Schritt der String-Säuberung zu überspringen, den Original Input in meiner JSON Datei zu speichern, diesen auch in Originalform abzurufen und Attacken durch Einschränkung der Browser-Interpretationsspielräume zu vermeiden, daher statt z.B.:


myForm.innerHTML = `
      <input type="text" id="nameInput" name="name" value="${
        data ? data.name : ""
      }" autocomplete="off" required aria-required="true" aria-describedby="dataHelp"/>
    `;

besser:


myForm.innerHTML = `
<input type="text" id="nameInput" name="name" autocomplete="off" required aria-required="true" aria-describedby="dataHelp"/>`;
const nameInput = crudDialogContent.querySelector("#nameInput");
nameInput.value = data?.name || "";

Dieselbe Vorgangsweise für Buttons, i.e.


const myBtn = document.querySelector("#myBtn");
      myBtn.setAttribute("aria-label", label);

etc.

Momentan komme ich mir allerdings vor, als wolle ich ein Shakespeare Sonett schreiben, ohne jemals das Alphabet gelernt zu haben. 😢

  1. Momentane Strategie: Sanitization komplett überspringen, User Inputs weder in JavaScript noch in PHP behandeln und eindeutig nicht zweideutig unmissverständliche Zuweisungen wenn innerHTML. ...Strategie richtig?

  2. neben innerHTML weitere diesbezüglich potentiell „gefährliche“ Properties im JavaScript? (.textContent, .innerText, .type, .id, .name, .autocomplete, .required, .setAttribute, .value reagieren meines Wissens ja eher unempfindlich, bzw. sind „safe“...)

Danke für eure Hilfe!