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

前言:javascript

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

后语:html

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

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

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

儿子就算是在坑爹,那也是咱儿子啊,知足不了他到时候认贼做父就很差了。c#

   说了半天废话我们奔主题吧。。。。。。。。
后端

主题:安全

   既然咱们能看到Exchange安装好部署后的页面能对于前端来说咱们仍是能够改变的,思路有一下3种:
session

   1)网上案例:

   请看这位大神的示例代码,但由于时间有点久远了,相关Code下载不过来,不过有兴趣的仍是能够看看的。

   2)前端验证

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

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

   demo:效果以下


<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>无标题页</title>
    <style type="text/css">
        .code
        {
            background-p_w_picpath: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>

虽然每次点击验证码的时候会发生变更,可是这个验证码不是图片,因此仍是有程序能够注入的,好比下边这种也是

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

   3)后端伪验证:

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

   缺点:相似前端js 验证

demo:先上效果图:

废话很少说了,贴出流程:

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


<!----------------------------------------------------------- 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代码(这个位置随意):

<!------------------------------------------ 验证码 脚本 ------------------------------------------------------------>
<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文件代码以下:

<%@ 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 = "p_w_picpath/Png";
            Response.BinaryWrite(ms.ToArray());
        }
        finally
        {
            bmp.Dispose();
            g.Dispose();
        }
    }
</script>

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

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

<%@ 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登陆时再包装一层是用户没法绕过验证码的验证,只不过本次需求不须要这么高的安全性,能用好看就行...


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

相关文章
相关标签/搜索