让 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;

/// <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验证,需要高版本浏览器,以后我会慢慢完善
时间: 2024-12-28 10:52:20

让 ASP.NET JS验证和服务端的 双验证 更简单的相关文章

jQuery结合Ajax实现简单的前端验证和服务端查询

上篇文章写了简单的前端验证由传统的JavaScript转向流畅的jQuery滑动验证,现在拓展一下,使用Ajax实现用户体验比较好的异步查询,同样还是从建立一个简单的表单开始 1 <form name="form2"> 2 <label class="style1">请输入要查询的内容:</label> 3 <br /> 4 <br /> 5 <input name="neirong&quo

ASP.NET MVC如何实现自定义验证(服务端验证+客户端验证)

ASP.NET MVC通过Model验证帮助我们很容易的实现对数据的验证,在默认的情况下,基于ValidationAttribute的声明是验证被使用,我们只需 要将相应的ValidationAttribute应用到Model的类型或者属性上即可.对于自定义验证,我们也只需要定义相应的Validation 就可以了,不过服务端验证比较简单,而客户端验证就要稍微复杂一些,本文提供一个简单的实例说明在ASP.NET MVC中实现自定义验证的基本步骤.[源代码从这里下载] 一.AgeRangeAttr

ASP.NET MVC+EF在服务端分页使用jqGrid以及jquery Datatables的注意事项

引言: 本人想自己个博客网站出来,技术路线是用ASN.NET MVC5+EF6(Code First)+ZUI+各种Jquery插件,有了这个想法之后就开始选择UI,看了好多bootstrap的模板之后,发现即使你用了bootstrap还是要自己写css样式,都是自学的,前端真的很垃圾,在网上找了很多UI,以下是各种UI的地址,需要的可以去看看: H-ui:http://www.h-ui.net/H-ui.admin.shtml ,是一个前端大牛弄得,模仿bootstrap,做适合中国网上的UI

dubbo和shiro的整合,在服务端做权限验证

基于dobbo做服务开发后通常会遇上这样一些问题,举个例子:用户的笔记,涉及到CRUD 4个接口,是每一个接口中都要把用户传进去么?比如:删除接口定义为 noteService.deleteById(Long noteId)还是 noteService.deleteById(Long userId, Long noteId)如果是前者,这个时候如果不验证用户对资源是否有权限直接删除是否合理,尤其是这种可能被用户猜到的ID很容易被恶意调用.如果选第二种的话,那么有很多接口都要这样定义,感觉不够美观

Asp.net 中,在服务端向客户端写脚本的常用方法

在Asp.net 服务端处理脚本,一般都用 ClientScriptManager ,即web窗体服务端的this.ClientScript.该对象比较常用的方法: 1.RegisterArrayDeclaration:在服务端,向客户端生成一个数组定义 服务端代码:   this.ClientScript.RegisterArrayDeclaration("aAry", "1,2,3"); 客户端“源文件”呈现 <script type="text

使用 PHP 来做 Vue.js 的 SSR 服务端渲染

对于客户端应用来说,服务端渲染是一个热门话题.然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说. 我发布了两个库让 PHP 从服务端渲染成为可能.spatie/server-side-rendering 和 spatie/laravel-server-side-rendering适配 laravel 应用. 让我们一起来仔细研究一些服务端渲染的概念,权衡优缺点,然后遵循第一法则用 PHP 建立一个服务端渲染. 什么是服务端渲染 一个单页应用(通常也叫做 SPA

js与C#服务端 json数据交互

1.1 服务端返回给前端 返回的数据都放入对象中(根据需求:单个对象,集合,键值对),然后JSON序列化返回给前端.这里可以引用JSON.NET 库,也可以用.NET自带的类库: JavaScriptSerializer().Serialize(obj) ; JSON序列化后的结果是一个键和值都用双引号括起的字符串:  "{"msg" : "成功 文件大小为:16397",   "imgurl":"/head.jpg"

model验证——remote服务端验证

项目中做的项目使用的mvc的model验证,感觉最难的一个是remote验证,其它的比较简单就不说了: remote验证例子: /// <summary> /// ErrorMessage 表示验证不通过时显示的消息 ///AdditionalFields 表示验证的时候用哪个字段作为参数来传递(通常用于编辑页面的时候验证) /// </summary> [Remote("actionName", "controllerName", Erro

用java做thrift服务端,php做thrift客户端简单例子

注意: 1).需要的包以及路径问题要注意修改为自己本地的 2)详细情况见  http://pan.baidu.com/s/1qW8xI0k 这里以Hello.thrift为例 namespace java hellodemo namespace php hellodemo service Hello{ string helloString(1:string para) i32 helloInt(1:i32 para) bool helloBoolean(1:bool para) void hel