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登陸時再包裝一層是用戶沒法繞過驗證碼的驗證,只不過本次需求不須要這麼高的安全性,能用好看就行...


   歡迎諸位大神拍磚。。。。

相關文章
相關標籤/搜索