解决XSS问题

时间:2018-07-13 19:46:07

标签: security asp.net-mvc-4 xss sql-injection

我正在尝试构建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>

1 个答案:

答案 0 :(得分:0)

主要问题是用户是否以不安全的方式控制了呈现给页面的某些数据。无论是他们的名字(我的名字是<script>function() { nasty stuff is happening here... }</script>)还是其他任何内容。

我采用以下方法,查看您的输出(或更好地考虑一下),看看在每个阶段是否有问题:

  1. 让Razor做到这一点,默认情况下Razor处理所有HTML的编码 页面上的字符,如果您使用 IHtmlString,因此请避免使用此Type(或将其返回的方法 Html.Raw()),因此@("<script>nastyThings()</script>")string,因此将被编码,脚本将无法运行
  2. 如果损坏,则意味着您的字符串中包含一些HTML / JS 您实际上要渲染。因此,请尝试将其直接移到 剃刀模板(HTML / JS)或通过链接(JS)获得
    • 不是整个string都是由用户"<element onclick="javascript:alert('trouble')"></element>"使用模板@Html.Raw(Model.UserBadString)
    • 制作模板<element onclick="mySafeJsFunction()">@Model.UserSafeString</element>”,这将使JS函数的控制权脱离了用户,并为它们提供了Razor编码的参数,而他们无法使用XSS
  3. 您希望用户控制HTML,然后必须使用(https://github.com/mganss/HtmlSanitizer之类的东西来清理输出到页面上的字符串。
    • 因此模板可以是@Html.Raw(sanitizer.Sanitize(Model.UserBadString)),但是您可能想做得比这更好,编码实践也要好。主要要点是string已被清除

顺便说一句,请确保对JS中.innerHTML之类的属性(或调用.html()的可怕jQuery eval())的使用情况保持密切关注,就像这些接受用户控制的内容,您将遇到完全相同的问题。但是可以应用相同的步骤,(1)改为使用.innerText,或者(3)在将其提供给JS(https://github.com/cure53/DOMPurify)之前,在字符串上使用类似DOMPurify的纯化库。不幸的是,在这种情况下,不建议使用选项(2),因为您或我必须保证剩下的一切安全,所以我宁愿相信DOMPurify可以这样做:)