ASP.NETCore MVC Model 数据注解过滤,post重复提交 ,XSS攻击

本随笔只是个人学习记录。

一、Model的数据注解

  开发asp.netcore 程序时(asp.netcore mvc 或这 asp.netcore webapi),在model 上使用数据注解,可以根据注解对客户端传递进来的数据进行过滤。具体为,当客户端数据传递到具体的action时,在进入action 方法体内部之前,对客户端传递进来的参数,根据数据注解进行验证,验证通过则执行action,不通过则返回。

部分内置的数据注解特性如下(来源官网):

 更多特性,移步官网:https://docs.microsoft.com/zh-cn/dotnet/api/system.componentmodel.dataannotations?view=netcore-3.1

数据注解参考官网:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-3.1

https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/razor-pages/validation?view=aspnetcore-3.1&tabs=visual-studio

https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/first-mvc-app/validation?view=aspnetcore-3.1

二、POST重复提交

  在asp.netcore mvc中,提交数据到post 方法后,如果只是返回了某个view,而此时url并没有发生改变。再此刷新,会产生重复提交。为了防止重复提交,需要使用重定向。

创建学生时,保存数据前,地址是 :https://localhost:5001/Home/Create

    

 保存数据后,地址还是:https://localhost:5001/Home/Create,此时,如果刷新网页,会造成 上一步骤的数据重复提交到 Create 进行保存。此时,会产生两条一样的数据保存到数据库,而这个过程,是不经意产生的,并不是我们想要的。

    

如果使用重定向,则如下图所示,此时地址已经改变,数据不会发生post 重复提交,这里即是不会提交到Create

    

三、XSS 跨站脚本攻击

  跨站脚本攻击,在html页面表单的input输入框中,输入脚本,比如html、js脚本,asp.netcore后台程序不经过处理则进行存储。取出数据显示时,会自动执行所保存的脚本,破坏应用程序。虽然前端可以对输入的数据进行编码,但终究不安全,需要在后台进行编码。

    

四 此随笔关键代码片段:(源码太多,我只贴出关键代码片段)

Model Student 代码:

namespace MVCTemplate.Models
{
    public class Student
    {
        public int Id { get; set; }
     
        //数据注解 data anotation
        [MinLength(3), Required,Display(Name ="FirstName")]
        public string FirstName { get; set; }

        [Required,Display(Name ="LastName")]
        public string LastName { get; set; }

        [Required,Display(Name ="性别")]
        public Gender Gender { get; set; }

        [Required,Display(Name ="生日")]
        public DateTime Birthday { get; set; }

    }

    public enum Gender
    {
        女=0,
        男=1,
        其他=2
    }
}

前端 HTML代码片段:

@model MVCTemplate.Models.Student
<h1>创建学生</h1>
<div>
    <form method="post">
        <label asp-for="FirstName"></label>
        <input asp-for="@Model.FirstName" />
        <label asp-for="LastName"></label>
        <input asp-for="@Model.LastName" />
        <label asp-for="Birthday"></label>
        <input asp-for="@Model.Birthday" type="date" />
        <label asp-for="Gender"></label>
        <select asp-for="@Model.Gender" asp-        items="@Html.GetEnumSelectList<Gender>()"></select>
        <button type="submit">保存数据</button>
    </form>
</div>

后台 代码片段:

public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        private readonly IRepository<Student> _repository;

        private readonly HtmlEncoder _htmlEncoder;
        /// <summary>
        /// 采用构造函数注入
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="repository"></param>
        public HomeController(ILogger<HomeController> logger, IRepository<Student> repository, HtmlEncoder htmlEncoder)
        {
            _logger = logger;
            _repository = repository;
            _htmlEncoder = htmlEncoder;//htmlEoncoder,不需要再 ConfigureServices中手动注册,运行时会自动注册。
        }

        [HttpPost] //post 请求
        [ValidateAntiForgeryToken]//用于防止跨站请求伪造,针对post的Action,一定要加上这个。
        public IActionResult Create(Student stuModel)
        {
            //数据注解,mvc框架会在匹配参数时,根据数据注解来判断传递进来的参数是否合法(符合要求),如果不合法,
            //则不会进入到方法内。即数据注解会在参数匹配时进行拦截。
            if (!ModelState.IsValid)
            {
                return Content("数据输入有误");
            }

            //对数据进行编码,防止XSS攻击。 比如会将输入的js脚本的<>这两个符号编码成&gt,&lt
            stuModel.FirstName = _htmlEncoder.Encode(stuModel.FirstName);

            //return new ObjectResult(stuModel);//返回json数据
            _repository.Add(stuModel);

            //带上 stuModel 返回页面detail。这种方式,容易产生重复提交post.因为返回后的地址不变,刷新页面,会重新提交post请求。
            //为了避免post重复提交,应该使用重定向
            // return View("Detail",stuModel);
            return RedirectToAction(nameof(Detail), stuModel);
        }

        public IActionResult Detail(Student stuModel)
        {
            return View(stuModel);
        }
        /*
         * 其他代码,太多了,这里就不贴出来了。
         */
    }
原文地址:https://www.cnblogs.com/Fengyinyong/p/13741845.html