运行 个包含使用 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, "<").replace(/>/g, ">")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)
希望对您有所帮助。坚持下去!
我一直在玩 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, "<").replace(/>/g, ">")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)
希望对您有所帮助。坚持下去!