在我的开发中,我有一个与 SO 非常匹配的标签系统。而且它还允许非拉丁字符。
我正在使用 Razor 页面。我应该在什么时候以及如何清理/编码此流程中的字符串?
这是我的获取请求的示例:
try {
const response = await fetch("api/tags?" + new URLSearchParams({ prefix: curPrefix, count: 12 }));
if (!response.ok) throw new Error("Network response was not OK");
const jsonData = await response.json();
if (jsonData.prefix === getPrefix()) {
var newTags = jsonData.tags.filter(tag => !selectedTags.find(x => x.name == tag.name));
setSuggestedTags(newTags);
}
} catch (error) {
console.error("There has been a problem with your fetch operation:", error);
}
基本上,每当您处理来自客户端的数据时,您都必须小心,包括将用户生成的数据发送回浏览器时。在您的示例中,缺少一些关键位,但这里有一个完整的示例,说明它如何容易受到 XSS 攻击。
页面模型的操作方法返回一些标签。其中一些包含 HTML,因为它是
JsonResult
,所以 HTML 不会转义:
public IActionResult OnGetTags()
=> new JsonResult((List<string>)[ "Carrot", "<strong>Spinach</strong>", """<img src="nothing" onerror="alert('Mexican Jumping Bean');"/>"""]);
Razor 页面,其中使用
innerHTML
获取标签并将其插入到页面中,这允许浏览器实际解析 HTML 代码:
<button onclick="fetchTags()">Suggest some Tags pls</button>
<ul id="tags"></ul>
<script>
async function fetchTags() {
try {
const response = await fetch('@Url.Page("", "Tags")');
if (!response.ok)
throw new Error("Network response was not OK");
setSuggestedTags(await response.json());
}
catch (error) {
console.error("There has been a problem with your fetch operation:", error);
}
}
function setSuggestedTags(newTags) {
newTags.forEach(t => {
const li = document.createElement('li');
li.innerHTML = t; //this pwns your visitor
tags.append(li);
});
}
</script>
如果你使用
innerText
而不是 innerHTML
就好了,那么 HTML 标签就会裸露在页面上,看起来和一开始输入时一样难看。
同样,如果您使用常用的 Razor 语法在页面上放置标签,它会自动转义它们:
<ul>
@foreach (var tag in Model.Tags) {
<li>@tag</li> @* this is fine *@
}
</ul>
当然,您可能还想在其他地方防止这种情况发生。例如,您可以确保当用户首先尝试保存此类标签时拒绝这些标签。重要的是,这必须在服务器端进行,也许可以通过仔细地剥离各种特殊字符或拒绝包含它们的任何标签来实现。我不会做的是转义传入的数据并以这种方式存储它,因为这会导致双重转义,并且不同的上下文无论如何都需要不同的转义。另外,以后搜索数据库会很头疼,因为每个非英文字母字符都可能是
Á
之类的。
在数据库中存储标签时,请确保使用参数化来防止 SQL 注入。有些工具主要自行处理此问题,例如使用实体框架时,您通常不直接使用 SQL。