关于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>
相关文章
相关标签/搜索