【问题标题】:Solving XSS issues解决 XSS 问题
【发布时间】:2018-12-22 05:40:25
【问题描述】:

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

【问题讨论】:

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


【解决方案1】:

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

我采用以下方法,查看您的输出(或者最好提前考虑一下),看看每个阶段是否存在问题:

  1. 让 Razor 来做,默认情况下 Razor 处理所有 HTML 的编码 页面上的字符,如果您使用 IHtmlString 所以避免这个Type (或返回它的方法 Html.Raw()) 所以@("&lt;script&gt;nastyThings()&lt;/script&gt;")string,所以它会被编码,并且脚本不会运行
  2. 如果它坏了,这意味着你的字符串中有一些 HTML/JS 你实际上想要渲染。所以试着把它直接移到 Razor 模板 (HTML/JS) 或通过链接 (JS) 获取
    • 而不是整个string 由用户控制"&lt;element onclick="javascript:alert('trouble')"&gt;&lt;/element&gt;" 使用模板@Html.Raw(Model.UserBadString)
    • 制作模板&lt;element onclick="mySafeJsFunction()"&gt;@Model.UserSafeString&lt;/element&gt;",这会从用户手中夺走对 JS 函数的控制权,并留给他们无法进行 XSS 的 Razor 编码参数
  3. 您希望用户能够控制 HTML,然后您必须使用 (https://github.com/mganss/HtmlSanitizer) 之类的方式清理输出到页面的字符串
    • 所以模板可以是@Html.Raw(sanitizer.Sanitize(Model.UserBadString)),但您可能想做一些比这更好的事情,良好的编码习惯等。主要的一点是string 已经过消毒

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

【讨论】:

    猜你喜欢
    • 2011-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多