security - 解决 XSS 问题
问题描述
我正在尝试构建一个 MVC 应用程序,但被告知这不是检索数据的好方法,并且容易受到跨站点脚本的影响。我从来没有做过安全工作,也一直在努力学习,但我无法绕开它。
我猜这里有几个缺陷。我可以使用任何特定的编码吗?
我没有在这里粘贴整个代码,但试图找出可以阻止 XSS 攻击的地方。
模型和视图模型
namespace ThePeopleSearchApplication.Models
{
public class UserViewModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
public class UserModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
}
控制器
namespace ThePeopleSearchApplication.Controllers
{
public class MyController : Controller
{
// GET: My
public ActionResult Index()
{
return View();
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUserAjax(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
return Content("{\"message\": \"search for userId: " +
userId + " result\", \"result\": " + convertToJson(myUser) + " }");
}
private string convertToJson(UserModel myUser)
{
return "{ \"userId\": \"" + myUser.UserId + "\", \"FirstName\": \"" +
myUser.FirstName + "\", \"LastName\": \"" + myUser.LastName + "\", \"Email\": \"" +
myUser.Email + "\", \"Status\": \"" + myUser.Status + "\"}";
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUser(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
var viewModel = new UserViewModel
{
UID = userId,
FName = myUser.FirstName,
LName = myUser.LastName,
Email = myUser.Email,
Status = myUser.Status,
};
return this.View(viewModel);
}
private UserModel fetchUserFromLdap(string userId)
{
var retVal = new UserModel();
if (String.IsNullOrEmpty(userId))
{
retVal.UID = "N/A";
retVal.FName = "N/A";
retVal.LName = "N/A";
retVal.Email = "N/A";
retVal.Status = "N/A";
}
else
{
retVal.UID = userId;
retVal.FName = "FirstName";
retVal.LName = "LastName";
retVal.Email = "email@example.com";
retVal.Status = "<div style=background-color:#F00800>My Status</div>";
}
return retVal;
}
}
}
看法
@model ThePeopleSearchApplication.Models.UserViewModel
@{
ViewBag.Title = "Search result for user: " + Model.UserId;
var ulId = "ul-id" + Model.UserId;
var formId = "form" + Model.UserId;
}
<html>
<head>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
</head>
<body>
<h1>Search result for user: @Model.UserId</h1>
<ul id="@Html.Raw(ulId)">
<li>@Model.FirstName</li>
<li>@Model.LastName</li>
<li>@Model.Email</li>
<li>@Html.Raw(Model.Status)</li>
</ul>
<form id=@formId name=@formId action=/My/SearchUser enctype="multipart/form-data">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script type="text/javascript">
var theForm = document.@formId;
$(theForm).submit(function() {
alert('Valid form');
return true;
});
// just to demonstrate potential usage $(theForm).submit();
</script>
<div>
Ajax search:
<form id="ajax-search" name="ajax-search">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script>
$("#ajax-search").submit(function() {
var url = "/My/SearchUserAjax"; // the script where you handle the form input.
$.ajax({
type: "POST",
url: url,
data: $("#ajax-search").serialize(), // serializes the form's elements.
success: function(data)
{
var obj = JSON.parse(data);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.message); // show response from the php script.
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.userId);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.FirstName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.LastName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.Status);
$('#ajax-search').append('<hr/>');
}
});
return false; // avoid to execute the actual submit of the form.
});
</script>
</div>
</body>
</html>
解决方案
主要问题是如果用户以不安全的方式控制您呈现给页面的某些数据。无论是来自他们的名字(我的名字是<script>function() { nasty stuff is happening here... }</script>
)还是任何其他内容。
我采用以下方法,查看您的输出(或更好地考虑一下),看看每个阶段是否存在问题:
IHtmlString
让 Razor 来做,默认情况下,Razor 处理页面上所有 HTML 字符的编码,如果你使用 an所以避免这个Type
(或返回它的方法,如Html.Raw()
)则不适用, 所以将@("<script>nastyThings()</script>")
被string
编码,脚本不会运行- 如果它坏了,这意味着你的字符串中有一些你真正想要渲染的 HTML/JS。因此,请尝试将其直接移动到 Razor 模板 (HTML/JS) 或通过链接 (JS) 获取
- 而不是整个
string
由用户"<element onclick="javascript:alert('trouble')"></element>"
使用模板控制@Html.Raw(Model.UserBadString)
- 制作模板
<element onclick="mySafeJsFunction()">@Model.UserSafeString</element>
“,这将 JS 函数的控制权从用户手中夺走,并留给他们无法进行 XSS 的 Razor 编码参数
- 而不是整个
- 您希望用户可以控制 HTML,然后您必须使用类似 ( https://github.com/mgans/HtmlSanitizer )
来清理输出到页面的字符串
- 所以模板可能是
@Html.Raw(sanitizer.Sanitize(Model.UserBadString))
,但您可能想做一些比这更好的事情,良好的编码实践等。重点是string
经过消毒
- 所以模板可能是
顺便说一句,确保您密切关注属性的用法,例如在 JS(或调用.innerHTML
jQuery 的可怕的 jQuery )中,就好像它们包含用户控制的内容一样,您将遇到完全相同的问题。但是可以应用相同的步骤,(1) 使用,或 (3) 在将字符串提供给 JS ( https://github.com/cure53/DOMPurify ) 之前,在字符串上使用净化库,如 DOMPurify。不幸的是,在这种情况下不推荐使用选项 (2),因为剩下的任何东西都必须由你或我确保安全,我宁愿相信 DOMPurify 会这样做:).html()
eval()
.innerText
推荐阅读
- python - 请问这个功能怎么解决?
- python-3.x - 我如何使用忙于 opencv 的 camara?
- r - 只制作一些特征 dummyVars
- mysql - 即使有索引,mysql 内连接也比 2 个单独的查询慢 50-500 倍
- aem - 首次将组件放在页面上时,如何更改 AEM 创建的节点的名称?
- sql - SQL 2014 如何从一天发生的事件中提取数据?
- sql - 错误:操作数数据类型 nvarchar 对 sum 运算符无效
- gitlab-ci - gitlab ci yml 仅为发布候选分支运行特定阶段
- jupyter-notebook - 如何将我的 Jupyter 笔记本屏幕调整到以前的大小?
- java - 如何使用 Java 开关创建布尔条件?