轉自: 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驗證,需要高版本瀏覽器,以后我會慢慢完善