const message = location.hash.slice(1);
document.querySelector("#result").innerHTML = message;
次のコードは、文字列表示だけが目的なら比較的安全です。
const message = location.hash.slice(1);
document.querySelector("#result").textContent = message;
OWASPも、postMessageなどで受け取った値をeval()やinnerHTMLへ渡さず、表示だけならtextContentを使うよう推奨しています。
XSSの根本原因を「文字列からコードへの変換」と説明する考え方は有用です。
ただし、ブラウザーがすべての文字列を無差別にコードへ変換するわけではありません。
正確には、次の条件がそろうと問題になります。
攻撃者が制御できる文字列
+
コードやマークアップを解釈するSink
+
不適切なエンコードまたはサニタイズ
=
XSS
たとえば、textContentは通常、文字列を文字として表示します。
一方、innerHTMLは文字列をHTMLとして解析します。