你的位置:首页 > ASP.net教程

[ASP.net教程]让 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" >  <ul>    <li>      <h2>        表单验证</h2>      <span >* 表示必填项</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" Css 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;/// <summary>/// ** 描述:可以方便实现前后端双验证,基于jquery/// ** 创始时间:2015-6-4/// ** 修改时间:-/// ** 作者:sunkaixuan/// ** 使用说明:-/// </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 OptioItemType.Mail:            item.Pattern = @"^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";            break;          case OptioItemType.Int:            item.Pattern = @"^\\d{1,11}$";            break;          case OptioItemType.Double:            item.Pattern = @"^\\d{1,11}$";            break;          case OptioItemType.IdCard:            item.Pattern = @"^(\\d{15}$|^\\d{18}$|^\\d{17}(\\d|X|x))$";            break;          case OptioItemType.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 OptioItemType.Mobile:            item.Pattern = @"^[0-9]{11}$";            break;          case OptioItemType.Telephone:            item.Pattern = @"^(\\(\\d{3,4}\\)|\\d{3,4}-|\\s)?\\d{8}$";            break;          case OptioItemType.Fax:            item.Pattern = @"^[+]{0,1}(\\d){1,3}[ ]?([-]?((\\d)|[ ]){1,12})+$";            break;          case OptioItemType.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 OptioItemType  {    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 OptioItemType 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验证,需要高版本浏览器,以后我会慢慢完善