运行 个包含使用 innerHTML 从本地存储中提取内容的脚本

Running scripts with content pulled from local storage with innerHTML

我一直在玩 Web 开发,想创建一个基本应用程序,允许用户在文本区域中输入 html,该文本区域保存在本地存储中,然后插入到文档元素中.innerHTML.

最小工作示例:

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Prototyping</title>
</head>
<body>

    <!--- Using bootstrap v. 5.2.0 --->
    <form>
        <label for="content"></label>
        <textarea class="form-control" id="content"></textarea>
    </form>

    <div id="displayContent"></div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
            crossorigin="anonymous"></script>
    <script src="index.js"></script>
</body>
</html>

JavaScript

const userInput = document.getElementById('content');
const displayInput = document.getElementById('displayContent')

userInput.addEventListener('input', (event) => {
    localStorage.setItem(event.target.id, event.target.value);
    displayInput.innerHTML = localStorage.getItem(event.target.id);
});

现在我担心使用 .innerHTML 会允许用户注入 js 代码 <script>alert('HAHA')</script>。但是,脚本无法 运行。或者至少以我对 HTML 的有限了解,我无法获得 运行 的脚本。这就是我想要的,但我不明白为什么。检查页面时,我会看到 <script>。这是因为 localStorage 将输入转换为字符串吗?发生了什么阻止脚本 运行ning?

您尝试注入的警报“运行 失败”的原因是因为在这个阶段 DOM 已经被解析并且其中的所有 javascript 已经被解析执行。所以,代码不会再执行了。

不过,由于您要插入 HTML,所以将要添加的任何 HTML 也将被渲染。因此,还有一些方法可以像这样执行 javascript-code 。一个示例是以下片段作为输入:

<img src=z onerror="alert('Injected code')">

使用其他 event-listener-attributes 或延迟脚本可以获得类似的结果。

但是,如果您仅在 client-side 上保存和打开输入,而不将其公开给其他用户,则不会造成任何损害。这与您在 developer-menu 中使用控制台是一样的,即在每个现代浏览器中使用 built-in(在大多数浏览器中是 F12)。 如果这对您的 use-case 仍然是个问题,或者您将输入公开给其他用户,我强烈建议您解析 text-input,这样 js-code 就不会被执行。 实现这一点的最安全方法可能是只插入文本而不是 HTML:

displayInput.textContent = localStorage.getItem(event.target.id)

另一种方法可能是将 <> 编码为它们的 html 等价物 (source):

let content = event.target.value.replace(/</g, "&lt;").replace(/>/g, "&gt;")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)

希望对您有所帮助。坚持下去!