zoukankan      html  css  js  c++  java
  • 让 ASP.NET JS验证和服务端的 双验证 更简单

    只用JavaScript验证安全不安全

    谁都知道,答案是不安全,非常的不安全。因为在客户端进行的验证相当于“让用户自己验证自己”,很明显是不靠谱的。你不能避免一些恶意用户人为的修改自己的表单进行欺骗,也不能避免第三方对表单进行截获后进行篡改再提交。

    所以说,从安全的角度来说,单纯的依靠js验证,是不安全的,任何健壮的系统都必须在后端进行验证。


    双验证大大增加了工作量,如何解决?

    方案1:笨方法,都写一遍

    方案2:现有框架 ,比如MVC自带验证支持双向验证 ,不足点是要写 model加attrbute 也要有一定工作量

    方案3:自已封装



    我的选择方案:方案3

    思路
    page 加载时通过Key去存储表 form规则,通过form规则生成前台元素的绑定,完成前台验证。后台函数通过key在获取表单规则进行后台验证。(可以用缓存机质提高性能)

    实现

    后台代码:

    通过GetInitScript存储form规则并且赋值给 ViewState["intisript"]去前台绑定




    前台调用只要绑定 viewState["intiscript"] (其实什么都不要写,保证元素name和 viewstate中一致就可以了):

    <body>
        <form id="form1" runat="server" class="contact_form">
        <ul>
            <li>
                <h2>
                    表单验证</h2>
                <span class="required_notification">* 表示必填项</span> </li>
            <li>
                <label for="name">
                    姓名:</label>
                <input type="text" name="name" />
            </li>
            <li>
                <label>
                    姓别:</label>
                <input type="radio" value="1" name="sex" />男
                <input type="radio" value="0" name="sex" />女 </li>
            <li>
                <label for="email">
                    电子邮件:</label>
                <input type="email" name="email" />
            </li>
            <li>
                <label for="website">
                    手 机:</label>
                <input type="text" name="phone" />
            </li>
            <li>
                <label for="website">
                    学 历:</label>
                <select name="education" >
                    <option value="">==请选择==</option>
                    <option value="1">大学</option>
                </select>
            </li>
            <li>
                <label for="message">
                    备注:</label>
                <textarea name="remark" cols="40" rows="6"></textarea>
            </li>
            <li></li>
        </ul>
        <br />
        <asp:Button ID="Button1" runat="server" Text="submit" CssClass="submit" OnClick="Button1_Click" />
        </form>
        <%=ViewState["intiscript"]%>
    </body>
    
    
    

      

     ViewState["intiscript"] 将生成一段脚本 给HTML元素添加 pattern、placeholder和requierd 等属性 ,有了这些属性可以很方便的使用JS等插件进行前端验证

    下面是通过
    ViewState["intiscript"] 生成出来的HTML
    
    
    
    
     



    后台使用 PostValidation函数进行验证



    我们来看看效果:

    
    


    提交成功验证通过了,下面我来改下前端元素采 用恶意参数 提交后台




    前台验证通过:


    后台还是要把你给揪出来


    最后附上C#验证类代码:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace SyntacticSugar
    {
        /// <summary>
        /// ** 描述:可以方便实现前后端双验证,基于jquery
        /// ** 创始时间:2015-6-4
        /// ** 修改时间:-
        /// ** 作者:sunkaixuan
        /// ** 使用说明:http://www.cnblogs.com/sunkaixuan/p/4550580.html
        /// </summary>
        public class ValidationSugar
        {
    
            private static List<ValidationOption> ValidationOptionList = new List<ValidationOption>();
    
            /// <summary>
            /// 前台注入
            /// </summary>
            /// <param name="pageKey"></param>
            /// <param name="itemList"></param>
            public static string GetInitScript(string pageKey, List<OptionItem> itemList)
            {
                //初始化后不在赋值
                if (ValidationOptionList.Any(it => it.PageKey == pageKey))
                {
                    return (ValidationOptionList.Single(c => c.PageKey == pageKey).Script);
                }
                else
                {
                    ValidationOption option = new ValidationOption();
                    string uk = Guid.NewGuid().ToString().Replace("-", "");//唯一函数名
                    string script = @"<script>
    var bindValidation{1}=function(name,params){{
         var selectorObj=$(""[name='""+name+""']"");
         selectorObj.after(""<span class=""form_hint"">""+params.tip+""</span>"");
         if(params.pattern!=null)
         selectorObj.attr(""pattern"",params.pattern);
         if(params.placeholder!=null)
         selectorObj.attr(""placeholder"",params.placeholder);
         if(params.isRequired==true)
         selectorObj.attr(""required"",params.isRequired);
    }}
    {0}</script>";
                    StringBuilder itemsCode = new StringBuilder();
                    foreach (var item in itemList)
                    {
                        switch (item.Type)
                        {
                            case OptionItemType.Mail:
                                item.Pattern = @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$";
                                break;
                            case OptionItemType.Int:
                                item.Pattern = @"^\d{1,11}$";
                                break;
                            case OptionItemType.Double:
                                item.Pattern = @"^\d{1,11}$";
                                break;
                            case OptionItemType.IdCard:
                                item.Pattern = @"^(\d{15}$|^\d{18}$|^\d{17}(\d|X|x))$";
                                break;
                            case OptionItemType.Date:
                                item.Pattern = @"^(((1[8-9]\d{2})|([2-9]\d{3}))([-\/])(10|12|0?[13578])([-\/])(3[01]|[12][0-9]|0?[1-9])$)|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/])(11|0?[469])([-\/])(30|[12][0-9]|0?[1-9])$)|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/])(0?2)([-\/])(2[0-8]|1[0-9]|0?[1-9])$)|(^([2468][048]00)([-\/])(0?2)([-\/])(29)$)|(^([3579][26]00)([-\/])(0?2)([-\/])(29)$)|(^([1][89][0][48])([-\/])(0?2)([-\/])(29)$)|(^([2-9][0-9][0][48])([-\/])(0?2)([-\/])(29)$)|(^([1][89][2468][048])([-\/])(0?2)([-\/])(29)$)|(^([2-9][0-9][2468][048])([-\/])(0?2)([-\/])(29)$)|(^([1][89][13579][26])([-\/])(0?2)([-\/])(29)$)|(^([2-9][0-9][13579][26])([-\/])(0?2)([-\/])(29))|(((((0[13578])|([13578])|(1[02]))[\-\/\s]?((0[1-9])|([1-9])|([1-2][0-9])|(3[01])))|((([469])|(11))[\-\/\s]?((0[1-9])|([1-9])|([1-2][0-9])|(30)))|((02|2)[\-\/\s]?((0[1-9])|([1-9])|([1-2][0-9]))))[\-\/\s]?\d{4})(\s(((0[1-9])|([1-9])|(1[0-2]))\:([0-5][0-9])((\s)|(\:([0-5][0-9])\s))([AM|PM|am|pm]{2,2})))?$";
                                break;
                            case OptionItemType.Mobile:
                                item.Pattern = @"^[0-9]{11}$";
                                break;
                            case OptionItemType.Telephone:
                                item.Pattern = @"^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}$";
                                break;
                            case OptionItemType.Fax:
                                item.Pattern = @"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$";
                                break;
                            case OptionItemType.Regex:
                                break;
                        }
                        itemsCode.AppendFormat("bindValidation{0}('{1}',{{   tip:'{2}',pattern:'{3}',placeholder:'{4}',isRequired:{5} }})", uk, item.FormFiledName, item.Tip, item.Pattern, item.Placeholder,item.IsRequired?"true":"false");
                        itemsCode.AppendLine();
                    }
                    option.Script = string.Format(script, itemsCode.ToString(), uk);
                    script = null;
                    itemsCode.Clear();
                    option.PageKey = pageKey;
                    option.ItemList = itemList;
                    ValidationOptionList.Add(option);
                    return (option.Script);
                }
            }
    
            /// <summary>
            /// 后台验证
            /// </summary>
            /// <param name="pageKey"></param>
            /// <param name="errorMessage">json格式</param>
            /// <returns></returns>
            public static bool PostValidation(string pageKey, out string errorMessage)
            {
                bool isSuccess = true;
                errorMessage = string.Empty;
                if (!ValidationOptionList.Any(c => c.PageKey == pageKey))
                {
                    throw new ArgumentNullException("ValidationSugar.PostValidation.pageKey");
                }
                var context = System.Web.HttpContext.Current;
                var itemList = ValidationOptionList.Where(c => c.PageKey == pageKey).Single().ItemList;
                var successItemList = itemList.Where(it => (it.IsRequired && !string.IsNullOrEmpty(context.Request[it.FormFiledName]) || !it.IsRequired)).Where(it => Regex.IsMatch(context.Request[it.FormFiledName], it.Pattern.Replace(@"\",@""))).ToList();
                isSuccess = (successItemList.Count == itemList.Count);
                if (!isSuccess)
                {
                    errorMessage = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(itemList);
                }
                return isSuccess;
            }
    
    
            private class ValidationOption
            {
                public string PageKey { get; set; }
                public string Script { get; set; }
                public List<OptionItem> ItemList { get; set; }
    
            }
    
            public enum OptionItemType
            {
                Mail = 0,
                Int = 2,
                Double = 3,
                IdCard = 4,
                Date = 5,
                /// <summary>
                /// 移动电话
                /// </summary>
                Mobile = 6,
                /// <summary>
                /// 座机
                /// </summary>
                Telephone = 7,
                Fax = 8,
                /// <summary>
                /// 没有合适的,请使用正则验证
                /// </summary>
                Regex = 1000
    
            }
            /// <summary>
            /// 验证选项
            /// </summary>
            public class OptionItem
            {
                /// <summary>
                /// 验证类型
                /// </summary>
                public OptionItemType Type { get; set; }
                /// <summary>
                /// 正则
                /// </summary>
                public string Pattern { get; set; }
                /// <summary>
                /// 是否必填
                /// </summary>
                public bool IsRequired { get; set; }
                /// <summary>
                /// 表单字段名(name或者id)
                /// </summary>
                public string FormFiledName { get; set; }
                /// <summary>
                /// 水印
                /// </summary>
                public string Placeholder { get; set; }
                /// <summary>
                /// 提醒
                /// </summary>
                public string Tip { get; set; }
    
            }
        }
    }
    

      



    源码下载:http://pan.baidu.com/s/1mgoXpsW

    时间问题只支持HTML5验证,需要高版本浏览器,以后我会慢慢完善


  • 相关阅读:
    MySQL中MyISAM为什么比InnoDB查询快
    .Net Core导入千万级数据至Mysql
    细说MySql索引原理
    原生Swagger界面太low(推荐)
    开源分布式调度系统分享(ScheduleMaster)
    tfs agent cicd 自动编译 xcpoy失败
    .net 网站
    Android App Arch
    Android 多进程引发的一次crash
    Scrapy 抓取数据入门操作
  • 原文地址:https://www.cnblogs.com/sunkaixuan/p/4550580.html
Copyright © 2011-2022 走看看