關於BBS的一些功能性補充以及踩坑記錄(持續補充)

聲明:如下記錄了本人實驗性地探索過程,不表明正確,請謹慎食用。
也歡迎提出各類批評建議,幫助我改正錯誤。謝謝!javascript

1.註冊

註冊時在註冊的jsp頁面使用js函數進行合法性驗證(包括空值、兩次輸入密碼是否相同等),並設置爲onclick或onsubmit觸發。
具體觸發順序以下
1) onclick: Y();php

2) onsubmit: X();css

3) submit();html

第一種:onsubmit

在表單submit以前會調用onsubmit(),注意調用時爲onsubmit="return CheckPost();"若是直接寫"CheckPost()"則沒法生效。若是返回false則不會調用submit,返回true纔會執行到submit。前端

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
 <script language="javascript" type="text/javascript"> 
    function check()
    {
    if (document.sign.username.value==""){
        alert("請輸入登陸帳號!");
        return false;
    }
    if (document.sign.password1.value==""){
        alert("請輸入登陸密碼!");
        return false;
    }
    if (document.sign.password2.value==""){
        alert("請輸入重複密碼!");
        return false;
    }
    var pd1=document.sign.password1.value;
    var pd2=document.sign.password2.value;
    if (pd1!=pd2){
        alert("對不起!重複密碼不等於登陸密碼");
        return false;
    }
    return true;
    }
</script>  
<title>註冊</title>
</head>
<body>

    <form action="Signup" method="post" name ="sign" onSubmit="return check()">
    <input type="hidden" name="action" value="signup"/>
        用戶名:<input type="text" name="username" />
        密碼:<input type="password" name="password1" />
        確認密碼:<input type="password" name="password2" />
         <input type="submit" value="註冊"  />
    </form>

</body>
</html>

第二種:onclick

點擊提交按鈕時觸發,此時須要在函數中手動submit提交。java

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
 <script language="javascript" type="text/javascript"> 
    function check()
    {
    if (document.sign.username.value==""){
        alert("請輸入登陸帳號!");
        return false;
    }
    if (document.sign.password1.value==""){
        alert("請輸入登陸密碼!");
        return false;
    }
    if (document.sign.password2.value==""){
        alert("請輸入重複密碼!");
        return false;
    }
    var pd1=document.sign.password1.value;
    var pd2=document.sign.password2.value;
    if (pd1!=pd2){
        alert("對不起!重複密碼不等於登陸密碼");
        return false;
    }
    document.sign.submit();
    return true;
    }
</script>  
<title>註冊</title>
</head>
<body>

    <form action="Signup" method="post" name ="sign" >
    <input type="hidden" name="action" value="signup"/>
        用戶名:<input type="text" name="username" />
        密碼:<input type="password" name="password1" />
        確認密碼:<input type="password" name="password2" />
         <input type="button" value="註冊" onClick="check()" />
    </form>
</body>
</html>

2.加密

1.前端到後臺的安全性

在用戶登陸以及註冊時,有必要對數據進行加密。任何語言最終都會造成html,事實上前端也只能處理html,css,js代碼,其餘如java,php,c#都是在後端工做的,在html經過web服務器發送給訪問者的時候已經脫離了後端的控制。所以前端的惟一加密手段就是js,可是js是明文的,也就是說你的加密過程是透明的,天然徹底沒有破解難度。固然,md5之類的單向加密依然沒法破解,問題是後端拿到單向加密的數據徹底沒用,由於它推導不出原始數據是什麼。因此,要安全就用https。
設置Tomcat的HTTPS配置方法以下:
① keytool工具生成證書
打開 JDK 自帶的 keytool 目錄。mysql

clipboard.png

按住 Shift 鍵,同時右鍵點擊空白處。git

clipboard.png

此時,進入cmd窗口。輸入下面命令。web

keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "F:\tomcat.keystore"

接着會讓你填寫一些基本信息。算法

clipboard.png

下面簡要介紹一下。

密鑰庫口令:123456(這個密碼很是重要)
名字與姓氏:localhost(之後訪問的域名或IP地址,很是重要,證書和域名或IP綁定)
組織單位名稱:anything(隨便填)
組織名稱:anything(隨便填)
城市:anything(隨便填)
省市自治區:anything(隨便填)
國家地區代碼:anything(隨便填)

② 應用證書到Tomcat
打開 Tomcat 配置文件 confserver.xml。
取消註釋,並添加兩個屬性 keystoreFile,keystorePass。

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" keystoreFile="F:/tomcat.keystore" keystorePass="123456" />

2.後臺數據的加密

後臺得到數據(用戶名和密碼)後,須要對密碼數據進行加密。因爲username在mysql中被設置成了unique的,因此並不適合加密存入。這裏只對密碼進行加密。
加密方法爲:
加密工具類:

import java.security.MessageDigest;
public class MD5Util {
    public final static String MD5(String s) {
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};       
        try {
            byte[] btInput = s.getBytes();
            // 得到MD5摘要算法的 MessageDigest 對象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字節更新摘要
            mdInst.update(btInput);
            // 得到密文
            byte[] md = mdInst.digest();
            // 把密文轉換成十六進制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

加密過程:

String salt =  MD5Util.MD5(username);
if(username.length()%2==0)
    password = password+salt;
else password = salt+password;
password = MD5Util.MD5(password);

經過unique的username經過MD5加密做爲每一個user獨有的salt,再將password與salt鏈接後再MD5加密。MD5算法hash碰撞的可能性很小,所以基本能夠保證salt和password加密後都是獨一無二的,防止黑客用彩虹表爆表。
不建議將salt與用戶信息存在一塊兒,防止數據庫被黑後黑客能夠輕易破解用戶密碼。

存儲結果以下:

clipboard.png

能夠看到密碼已經被加密。

3.防止SQL注入

一、檢查變量數據類型和格式

若是你的SQL語句是相似where id={$id}這種形式,數據庫裏全部的id都是數字,那麼就應該在SQL被執行前,檢查確保變量id是int類型;若是是接受郵箱,那就應該檢查並嚴格確保變量必定是郵箱的格式,其餘的類型好比日期、時間等也是一個道理。總結起來:只要是有固定格式的變量,在SQL語句執行前,應該嚴格按照固定格式去檢查,確保變量是咱們預想的格式,這樣很大程度上能夠避免SQL注入攻擊。

二、綁定變量,使用預編譯語句

使用PreparedStatement代替Statement是最有效也是最簡單的防止SQL注入的方式。

三、用戶數據加密

正如上面所說,對用戶數據進行加密是一個必要的手段。雖然說不能徹底防止SQL注入攻擊,可是能增大黑客暴力破解的難度。

總之

一、不要隨意開啓生產環境中Webserver的錯誤顯示(避免1=1 1=2刺探漏洞以及爆字段)
二、永遠不要信任來自用戶端的變量輸入,有固定格式的變量必定要嚴格檢查對應的格式,沒有固定格式的變量須要對引號等特殊字符進行必要的過濾轉義。
三、使用預編譯綁定變量的SQL語句。
四、作好數據庫賬號權限管理。
五、嚴格加密處理用戶的機密信息。

4.數據庫表的結構選擇(存疑)

原來是用戶表用MyISAM 帖子表用InnoDB提升併發性。

一、用戶信息

咱們將用戶id、用戶名、密碼存在一張表上,同時要確保id和用戶名是惟一的,這裏我將id做爲主鍵索引,用戶名做爲惟一索引。選擇MyISAM存儲引擎,有如下緣由:

  1. 對MyISAM表的讀操做(登陸、註冊前驗證),不會阻塞其餘用戶對同一表的讀請求(其餘用戶依然能夠登陸),但會阻塞對同一表的寫(註冊)請求,對 MyISAM表的寫操做,則會阻塞其餘用戶對同一表的讀和寫操做(註冊完成前,其餘用戶不能進行註冊驗證,不然會重複註冊);
  2. 雖然MyISAM寫的優先度比較高,可是註冊的頻率遠遠小於登陸和驗證的頻率,因此不會出現用戶讀操做的飢餓狀態。
  3. 實現簡單

理論上也能夠把用戶名做爲主鍵。但不推薦,理由大概有:

  1. 用戶名能夠是千奇百怪的字符串,而用ID(通常用guid或自增int)是比較規則字母數字序列,這可能致使性能上有所差異
  2. 假如以用戶名做爲主鍵並與其餘表關聯,當刪除用戶時,再建立一個同名的用戶,可能致使這些關聯紊亂。而絕對惟一的ID則不會。
  3. 後期可能會容許修改用戶名,若是以用戶名爲主鍵,將帶來不少麻煩。而若是以ID爲主鍵進行關聯,則沒有此問題。

二、帖子信息

主題帖包括如下字段:
id(主鍵索引) title(標題) cont(內容) pdata(發帖時間) user(做者)isleaf
回覆貼包括如下字段:
id pid(父貼) rootid(主題帖id,創建索引) title cont(內容) pdata(發帖時間) user(做者)isleaf

主題帖存儲引擎使用MyISAM,有如下緣由:

  1. 只須要在主頁上顯示,讀多寫少,對併發要求低。
  2. 實現簡單,非聚簇索引佔用空間小

回覆帖存儲引擎使用InnoDB,有如下緣由:

  1. 全部主題帖的回覆都存儲在這一張表上,對併發要求高,儘管聚簇索引會佔用大量空間,可是爲了併發性能必須有所取捨。
  2. InnoDB會在insert delete update語句默認加排它鎖,可是select不加鎖。此時也不須要手動給select加共享鎖或排它鎖。
  3. 不能用MyISAM的另外一個緣由是,MyISAM的寫會阻塞全部的讀操做,不適用於大量寫的狀況,容易下降性能

5.細節問題

一、在JS代碼中調用jsp的變量

<script type="text/javascript">
    var url = "<%=url%>";
    delayURL(url);
</script>

二、設置操做成功後N秒後跳轉

<span id="time" style="background:red">3</span>秒鐘後跳轉,或者點擊下面跳轉。

<script language="javascript" type="text/javascript">
function delayURL(url){//每隔一秒遞歸調用一次該函數,刷新秒數,直到秒數小於0跳轉
    var delay = document.getElementById("time").innerHTML;//得到目前秒數
    if (delay>0){
        delay--;
        document.getElementById("time").innerHTML = delay
    }else{
        window.top.location.href= url;
    }
    setTimeout("delayURL('"+url+"')",1000);//每隔一秒,調用一次delayURL
}
</script>
相關文章
相關標籤/搜索