转自: http://www.cnblogs.com/sunkaixuan/p/4550580.html
只用JavaScript验证安全不安全
谁都知道,答案是不安全,非常的不安全。因为在客户端进行的验证相当于“让用户自己验证自己”,很明显是不靠谱的。你不能避免一些恶意用户人为的修改自己的表单进行欺骗,也不能避免第三方对表单进行截获后进行篡改再提交。
所以说,从安全的角度来说,单纯的依靠js验证,是不安全的,任何健壮的系统都必须在后端进行验证。
双验证大大增加了工作量,如何解决?
方案1:笨方法,都写一遍
方案2:现有框架 ,比如MVC自带验证支持双向验证 ,不足点是要写 model加attrbute 也要有一定工作量
方案3:自已封装
我的选择方案:方案3
思路
page 加载时通过Key去存储表 form规则,通过form规则生成前台元素的绑定,完成前台验证。后台函数通过key在获取表单规则进行后台验证。(可以用缓存机质提高性能)
实现
后台代码:
通过GetInitScript存储form规则并且赋值给 ViewState["intisript"]去前台绑定

前台调用只要绑定 viewState["intiscript"] (其实什么都不要写,保证元素name和 viewstate中一致就可以了):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
<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>
<span style=
"color: #ff0000;"
> <%=ViewState[
"intiscript"
]%></span>
</body>
|
ViewState["intiscript"] 将生成一段脚本 给HTML元素添加 pattern、placeholder和requierd 等属性 ,有了这些属性可以很方便的使用JS等插件进行前端验证
下面是通过ViewState["intiscript"] 生成出来的HTML
1
|
|

后台使用 PostValidation函数进行验证
我们来看看效果:
提交成功验证通过了,下面我来改下前端元素采 用恶意参数 提交后台
前台验证通过:
后台还是要把你给揪出来
最后附上C#验证类代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
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验证,需要高版本浏览器,以后我会慢慢完善