Exchange邮箱登陆界面添加验证码功能完美解决方案

简介:

前言:

   昨天思路错误,白忙了一上午因为Exchange安装好之后是依附于IIS的所以我们看到登陆界面也是个.aspx页面 通过IIS找到的Exchange安装目录发现只有logon.aspx页面 没有也不可能有logon.aspx.cs页面,说白了就是微软给咱们写好了一个(一套)软件--Exchange邮件服务系统,对于用户,亲你只需要安装就行了。。。

后语:

   这意味着exchange走的也是IIS,也是asp.net那一套流程,ok 需求来了:

   上帝:我想要在邮箱登陆的时候加一个验证码的功能,这样不是会更安全嘛。

   开发者:额,好吧。。。(心说,尼玛坑爹呐,这是微软写好的我怎么给你加验证码呀!!)

儿子就算是在坑爹,那也是咱儿子啊,满足不了他到时候认贼作父就不好了。

   说了半天废话咱们奔主题吧。。。。。。。。

主题:

   既然我们能看到Exchange安装好部署后的页面能对于前端来讲我们还是可以改变的,思路有一下3种:

   1)网上案例:

   请看这位大神的示例代码,但因为时间有点久远了,相关Code下载不过来,不过有兴趣的还是可以看看的。

   2)前端验证

顾名思义,就是使用js来在前端动态生成验证功能,控制用户登录

       缺点:这只是表面的现象,一旦有高手察觉这个验证功能只是张纸那么薄,很容易捅破。

   demo:效果如下

133947902.png


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
< html  xmlns = "http://www.w3.org/1999/xhtml"  >
< head >
     < title >无标题页</ title >
     < style  type = "text/css" >
         .code
         {
             background-image:url(code.jpg);
             font-family:Arial;
             font-style:italic;
             color:Red;
             border:0;
             padding:2px 3px;
             letter-spacing:3px;
             font-weight:bolder;
         }
         .unchanged
         {
             border:0;
         }
     </ style >
     < script  language = "javascript"  type = "text/javascript" >
         var code; //在全局 定义验证码
         function createCode() {
             code = "";
             var codeLength = 6;//验证码的长度
             var checkCode = document.getElementById("checkCode");
             var selectChar = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');//所有候选组成验证码的字符,当然也可以用中文的
             for (var i = 0; i <  codeLength ; i++) {
                 var  charIndex  Math .floor(Math.random() * 36);
                 code += selectChar[charIndex];
             }
             //       alert(code);
             if (checkCode) {
                 checkCode.className  "code" ;
                 checkCode.value  code ;
             }
         }
         function validate() {
             var  inputCode  document .getElementById("input1").value;
             if (inputCode.length <= 0) {
                 alert("请输入验证码!");
             }
             else if (inputCode.toUpperCase() != code.toUpperCase()) {
                 alert("验证码输入错误!");
                 createCode();//刷新验证码
             }
             else {
                 alert("^-^ OK");
             }
         }
     </script>
</ head >
< body      <form   action = "#" >
         < table >
             < tr >< td >姓 名:</ td >< td >< input  type = "text"  style = "width: 160px;" /></ td ></ tr >
             < tr >< td >密 码:</ td >< td >< input  type = "password"  style = "width: 160px;" /></ td ></ tr >
             < tr >< td >验证码:</ td >< td >< input   type = "text"  style = "width: 160px;"   id = "input1"  />
         < input  type = "text"   readonly = "readonly"  id = "checkCode"  class = "unchanged"  style = "width: 80px"   /></ td ></ tr >
         < tr >< td ></ td >< td >< input  id = "Button1"    type = "button"  value = "确定"  />   </ td ></ tr >
         </ table >
                                                                                                                                                                                                                                                                                                                                               
     </ form >
</ body >
</ html >

虽然每次点击验证码的时候会发生变动,但是这个验证码不是图片,所以还是有程序可以注入的,比如下边这种也是134535101.png

亲你懂了吧~~~~~~~

   3)后端伪验证:

   哎,为什么要加个“伪”呐因为如果不是js你也没办法阻止表单的提交,而且表单提交后也没有什么验证,就是在验证用户登录的时候你是没办法拦截用户的登录信息提取验证码的

   缺点:类似前端js 验证

demo:先上效果图:

135115470.png

废话不多说了,贴出流程:

在IIS中找到Exchange登录界面页面的物理路径,找到页面logon.aspx,添加如下代码:


1
2
3
4
5
<!----------------------------------------------------------- start 验证码 --------------------------------------------------------------------->
< tr >< td  nowrap>< label  for = "yzm" >验证码:</ label ></ td >< td  class = "txtpad" >< input  type = 'text'  class = 'txt'  maxlength = "4"  style = "width:220px;"  id = 'yzm'  />
< img  src = 'GetImg.aspx'    alt = "点击切换验证码"  title = "点击切换验证码"  style = " margin-top:2px; vertical-align:top;cursor:pointer;"   'GetImg.aspx');return false;" /></ td >
</ tr >
     <!----------------------------------------------------------- end 验证码 --------------------------------------------------------------------->

你懂得,具体位置有你定,然后加入以下js代码(这个位置随意):

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
<!------------------------------------------ 验证码 脚本 ------------------------------------------------------------>
<script type= "text/javascript"   src= "jquery-1.7.1.min.js" ></script>
<script type= "text/javascript" >
function  ToggleCode(obj, codeurl) {
     $(obj).attr( "src" , codeurl +  "?time="  + Math.random());
}
var  bo= false ;
$(document).ready( function (){
     $( ".btn" ).before( "<label id='spanMsg' style='color:red;padding-right:50px;'> </label>" );
     $( ".btn" ).click( function (){
        if (bo){
           return  true ;
        } else {
         var  codeVaule=$( "#yzm" ).val();
         if (codeVaule== "" ){
             $( "#spanMsg" ).html( "*验证码不能为空!" );
             return  false ;
         } else  if (codeVaule.length!=4){
             $( "#spanMsg" ).html( "*验证码位数不够!" );
             return  false ;
         } else {
             $.get( "VerifyCode.aspx?yzmc=" +codeVaule,{}, function (data){
                 if (data== "ok" ){
                     $( "#spanMsg" ).html( "*验证码正确!" );
                     $( ".btn" ).click();
                     bo= true ;
                 } else {
                     $( "#spanMsg" ).html( "*验证码错误!" );
                 }
             });
         }
         return  bo;
         }
                                                                                                                                                                                           
     });
});
</script>
<!------------------------------------------- end 验证码 脚本 ----------------------------------------------------------->

然后在logon.aspx同一目录下添加jquery-1.7.1.min.js文件具体是什么版本的jquery你可以任意选择,应该都能兼容。注意js代码的引用名称一致。然后添加GetImg.aspx文件代码如下:

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
<%@ Page Language= "C#"  AutoEventWireup= "true"   %>
<%@ Import Namespace= "System.Drawing"  %>
<%@ Import Namespace= "System.Drawing.Imaging"  %>
<%@ Import Namespace= "System.IO"  %>
<%@ Import Namespace= "System.Security.Cryptography"  %>
<script runat= "server" >
     public  static  string Encrypt(string Text)
     {
         string sKey =  "nysoftland.com.cn" ;
         DESCryptoServiceProvider des =  new  DESCryptoServiceProvider();
         byte[] inputByteArray;
         inputByteArray = Encoding.Default.GetBytes(Text);
         des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring( 0 8 ));
         des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring( 0 8 ));
         System.IO.MemoryStream ms =  new  System.IO.MemoryStream();
         CryptoStream cs =  new  CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
         cs.Write(inputByteArray,  0 , inputByteArray.Length);
         cs.FlushFinalBlock();
         StringBuilder ret =  new  StringBuilder();
         foreach (byte b  in  ms.ToArray())
         {
             ret.AppendFormat( "{0:X2}" , b);
         }
         return  ret.ToString();
     }
     public  static  string Decrypt(string Text)
     {
         string sKey =  "Exchange" ;
         DESCryptoServiceProvider des =  new  DESCryptoServiceProvider();
         int  len;
         len = Text.Length /  2 ;
         byte[] inputByteArray =  new  byte[len];
         int  x, i;
         for  (x =  0 ; x < len; x++)
         {
             i = Convert.ToInt32(Text.Substring(x *  2 2 ),  16 );
             inputByteArray[x] = (byte)i;
         }
         des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring( 0 8 ));
         des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring( 0 8 ));
         System.IO.MemoryStream ms =  new  System.IO.MemoryStream();
         CryptoStream cs =  new  CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
         cs.Write(inputByteArray,  0 , inputByteArray.Length);
         cs.FlushFinalBlock();
         return  Encoding.Default.GetString(ms.ToArray());
     }
     protected  void  Page_Load(object sender, EventArgs e)
     {
         int  codeW =  80 ;
         int  codeH =  22 ;
         int  fontSize =  16 ;
         string chkCode = string.Empty;
         Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };
         string[] font = {  "Times New Roman" "Verdana" "Arial" "Gungsuh" "Impact"  };
         char[] character = {  '2' '3' '4' '5' '6' '8' '9' 'a' 'b' 'd' 'e' 'f' 'h' 'k' 'm' 'n' 'r' 'x' 'y' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'J' 'K' 'L' 'M' 'N' 'P' 'R' 'S' 'T' 'W' 'X' 'Y'  };
         Random rnd =  new  Random();
         for  ( int  i =  0 ; i <  4 ; i++)
         {
             chkCode += character[rnd.Next(character.Length)];
         }
         //Session["yzmCode"] = chkCode;
         HttpCookie cook =  new  HttpCookie( "yzmCode" , Encrypt(chkCode));
         cook.Expires = DateTime.Now.AddMinutes( 20 );
         Response.Cookies.Add(cook);
         Bitmap bmp =  new  Bitmap(codeW, codeH);
         Graphics g = Graphics.FromImage(bmp);
         g.Clear(Color.White);
         for  ( int  i =  0 ; i <  1 ; i++)
         {
             int  x1 = rnd.Next(codeW);
             int  y1 = rnd.Next(codeH);
             int  x2 = rnd.Next(codeW);
             int  y2 = rnd.Next(codeH);
             Color clr = color[rnd.Next(color.Length)];
             g.DrawLine( new  Pen(clr), x1, y1, x2, y2);
         }
         for  ( int  i =  0 ; i < chkCode.Length; i++)
         {
             string fnt = font[rnd.Next(font.Length)];
             Font ft =  new  Font(fnt, fontSize);
             Color clr = color[rnd.Next(color.Length)];
             g.DrawString(chkCode[i].ToString(), ft,  new  SolidBrush(clr), (float)i *  18  2 , (float) 0 );
         }
         for  ( int  i =  0 ; i <  100 ; i++)
         {
             int  x = rnd.Next(bmp.Width);
             int  y = rnd.Next(bmp.Height);
             Color clr = color[rnd.Next(color.Length)];
             bmp.SetPixel(x, y, clr);
         }
         Response.Buffer =  true ;
         Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds( 0 );
         Response.Expires =  0 ;
         Response.CacheControl =  "no-cache" ;
         Response.AppendHeader( "Pragma" "No-Cache" );
         MemoryStream ms =  new  MemoryStream();
         try
         {
             bmp.Save(ms, ImageFormat.Png);
             Response.ClearContent();
             Response.ContentType =  "image/Png" ;
             Response.BinaryWrite(ms.ToArray());
         }
         finally
         {
             bmp.Dispose();
             g.Dispose();
         }
     }
</script>

在第72行的时候不适用session验证,因为Exchange安装后使用的不是Session验证机制,所以我们在73~75行采用Cookies验证机制。以上代码用于生成验证码。

下边采用jquery异步验证机制验证 验证码填写是否正确,同样添加VerifyCode.aspx文件代码如下:

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
<%@ Page Language= "C#"  AutoEventWireup= "true"  %>
<%@ Import Namespace= "System.Security.Cryptography"  %>
<script runat= "server" >
     protected  void  Page_Load( object  sender, EventArgs e)
     {
         if  (Request.Cookies[ "yzmCode" ] !=  null &&Request.QueryString[ "yzmc" ]!= null )
         {
             string  code = Decrypt(Request.Cookies[ "yzmCode" ].Value).ToUpper();
             string  ucode = Request.QueryString[ "yzmc" ].ToUpper();
             if  (code == ucode)
             {
                 Response.Write( "ok" );
                 Response.End();
             }
             else
             {
                 Response.Write( "error" );
                 Response.End();
             }
         }
         else
         {
             Response.Write( "error2" );
             Response.End();
         }
     }
     public  static  string  Decrypt( string  Text)
     {
         string  sKey =  "Exchange" ;
         DESCryptoServiceProvider des =  new  DESCryptoServiceProvider();
         int  len;
         len = Text.Length / 2;
         byte [] inputByteArray =  new  byte [len];
         int  x, i;
         for  (x = 0; x < len; x++)
         {
             i = Convert.ToInt32(Text.Substring(x * 2, 2), 16);
             inputByteArray[x] = ( byte )i;
         }
         des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring(0, 8));
         des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey,  "md5" ).Substring(0, 8));
         System.IO.MemoryStream ms =  new  System.IO.MemoryStream();
         CryptoStream cs =  new  CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
         cs.Write(inputByteArray, 0, inputByteArray.Length);
         cs.FlushFinalBlock();
         return  Encoding.Default.GetString(ms.ToArray());
     }
</script>

到此我们的代码就已经填写完毕了


总结:

   有很好的asp.net底层基础遇到问题还是能解决的挺顺手的。不过说白了这些都是表面现象,你无法重写Exchange编译好的dll,也就是说想绕过你的验证还是很容易的,这些都只是忽悠用户拔了,如果想更安全就要修改IIS,在Exchange登录时再包装一层是用户无法绕过验证码的验证,只不过本次需求不需要这么高的安全性,能用好看就行...


   欢迎诸位大神拍砖。。。。






本文转自 tongling_zzu 51CTO博客,原文链接:http://blog.51cto.com/tongling/1295069

相关文章
|
JavaScript 前端开发
原生JS实现移动端短信验证码功能
原生JS实现移动端短信验证码功能
213 0
原生JS实现移动端短信验证码功能
JavaWeb用户信息管理系统-在登录中添加验证码功能
JavaWeb用户信息管理系统-在登录中添加验证码功能
70 0
|
16天前
|
存储 JSON 前端开发
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
本文介绍了在Node.js中使用token实现前端验证码和登录功能的详细流程,包括生成验证码、账号密码验证以及token验证和过期处理。
25 0
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
|
2月前
|
SQL 前端开发 NoSQL
SpringBoot+Vue 实现图片验证码功能需求
这篇文章介绍了如何在SpringBoot+Vue项目中实现图片验证码功能,包括后端生成与校验验证码的方法以及前端展示验证码的实现步骤。
SpringBoot+Vue 实现图片验证码功能需求
|
2月前
|
NoSQL JavaScript Java
SpringBoot+Vue+Redis实现验证码功能、一个小时只允许发三次验证码。一次验证码有效期二分钟。SpringBoot整合Redis
这篇文章介绍了如何使用SpringBoot结合Vue和Redis实现验证码功能,包括验证码的有效期控制和一小时内发送次数的限制。
|
11月前
|
前端开发 JavaScript Java
淘东电商项目(24) -获取验证码功能
淘东电商项目(24) -获取验证码功能
55 0
|
5月前
|
存储 安全 JavaScript
使用Python的Flask框架开发验证码登录功能
使用Python的Flask框架开发验证码登录功能
129 0
|
安全 机器人 Java
JavaSwing实现验证码功能
在Web应用程序开发中,验证码(CAPTCHA)是一种常见的安全措施,用于防止自动化机器人和恶意软件对网站进行攻击。本文将介绍如何使用JavaSwing来实现验证码功能,以帮助您加强Web应用程序的安全性。
92 0
|
5月前
|
缓存 NoSQL 前端开发
一文搞懂Go整合captcha实现验证码功能
一文搞懂Go整合captcha实现验证码功能
78 0
|
5月前
|
JSON 开发工具 数据格式
App Inventor 2 接入阿里云短信服务,实现短信验证码功能
App Inventor 2 接入阿里云短信服务,实现短信验证码功能:发送短信验证码功能一般都是基于短信平台提供的sdk进行调用,这里是基于阿里云短信平台进行的开发。
188 1