JavaJspSsh 2019-06-26
声明:以下记录了本人实验性地探索过程,不代表正确,请谨慎食用。
也欢迎提出各种批评建议,帮助我改正错误。谢谢!
注册时在注册的jsp页面使用js函数进行合法性验证(包括空值、两次输入密码是否相同等),并设置为onclick或onsubmit触发。
具体触发顺序如下
1) onclick: Y();
2) onsubmit: X();
3) submit();
在表单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>
点击提交按钮时触发,此时需要在函数中手动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; } 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>
在用户登录以及注册时,有必要对数据进行加密。任何语言最终都会形成html,事实上前端也只能处理html,css,js代码,其他如java,php,c#都是在后端工作的,在html通过web服务器发送给访问者的时候已经脱离了后端的控制。因此前端的唯一加密手段就是js,但是js是明文的,也就是说你的加密过程是透明的,自然完全没有破解难度。当然,md5之类的单向加密依然无法破解,问题是后端拿到单向加密的数据完全没用,因为它推导不出原始数据是什么。所以,要安全就用https。
设置Tomcat的HTTPS配置方法如下:
① keytool工具生成证书
打开 JDK 自带的 keytool 目录。
按住 Shift 键,同时右键点击空白处。
此时,进入cmd窗口。输入下面命令。
keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "F:\tomcat.keystore"
接着会让你填写一些基本信息。
下面简要介绍一下。
密钥库口令: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" />
后台获得数据(用户名和密码)后,需要对密码数据进行加密。由于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与用户信息存在一起,防止数据库被黑后黑客可以轻易破解用户密码。
存储结果如下:
可以看到密码已经被加密。
如果你的SQL语句是类似where id={$id}这种形式,数据库里所有的id都是数字,那么就应该在SQL被执行前,检查确保变量id是int类型;如果是接受邮箱,那就应该检查并严格确保变量一定是邮箱的格式,其他的类型比如日期、时间等也是一个道理。总结起来:只要是有固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。
使用PreparedStatement代替Statement是最有效也是最简单的防止SQL注入的方式。
正如上面所说,对用户数据进行加密是一个必要的手段。虽说不能完全防止SQL注入攻击,但是能增大黑客暴力破解的难度。
1、不要随意开启生产环境中Webserver的错误显示(避免1=1 1=2刺探漏洞以及爆字段)
2、永远不要信任来自用户端的变量输入,有固定格式的变量一定要严格检查对应的格式,没有固定格式的变量需要对引号等特殊字符进行必要的过滤转义。
3、使用预编译绑定变量的SQL语句。
4、做好数据库帐号权限管理。
5、严格加密处理用户的机密信息。
原来是用户表用MyISAM 帖子表用InnoDB提高并发性。
我们将用户id、用户名、密码存在一张表上,同时要确保id和用户名是唯一的,这里我将id作为主键索引,用户名作为唯一索引。选择MyISAM存储引擎,有以下原因:
理论上也可以把用户名作为主键。但不推荐,理由大概有:
主题帖包括以下字段:
id(主键索引) title(标题) cont(内容) pdata(发帖时间) user(作者)isleaf
回复贴包括以下字段:
id pid(父贴) rootid(主题帖id,建立索引) title cont(内容) pdata(发帖时间) user(作者)isleaf
主题帖存储引擎使用MyISAM,有以下原因:
回复帖存储引擎使用InnoDB,有以下原因:
<script type="text/javascript"> var url = "<%=url%>"; delayURL(url); </script>
<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>