如果破解一个系统的代价比系统本来内容的价值还要高,则系统就是安全的。
1口令加密存储 相同的密码在数据库中显示的值不一定相同,这就是加盐的效果。
知识补充:
1)JAVA密码架构(JCA)是由java.security包和子包中的一系列类组成。
这些类提供了像消息摘要(MessageDigest)和数字签名(Signature)这样的
API函数。
2)加密服务提供者(provider)不同算法的集合。Sun提供者包含如下一些算法的实现:
MD5消息摘要,SHA-1消息摘要,随机数的产生,DSA数字签名的签署和证书,DSA密钥
对的产生,DSA密钥的转换,DSA算法的参数,DSA算法参数的产生,等等
3)图解:
MessageDigest->MessageDigestSPI->提供者1 MD5,提供者2 SHA-1
这里的MessageDigestSPI程序开发者不需要关心它,国为只有提供者才会用到它。
例:
MessageDigest md=MessageDigest.getInstance("MD5");
消息摘要和口令认证(看书p543两图解)
*权限管理应用的口令加密示例如下:
1)数据库中口令类型为varbinary型。
2)Person.java中 private byte[] password;
映射文件中 <property name="password" type="byte[]">
<column name="password" length="50" not-null="true" />
</property>
3)加密码方法madeBytes(..),口令验证方法validPwd(..) (可重用的方法 使用消息摘要,盐等知识)
详细见附
4)写到数据库
注册用户
用户输入密码password
byte[] pwdBytes=null;
pwdBytes=madeBytes(password); //调用加密方法
person.setPssword(pwdBytes);
5)从数据库取出
用户的登录
String valid=validPwd(password,person.getPassword);//第一个值是输入的值,第二个值是从数据库取出的值
...异常省略
if("match".equals(valid)){登录成功};
2防止用户绕过登录的方法
isLogin.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%
if(((String)session.getAttribute("userId"))==null){
%>
<jsp:forward page="/login.faces"/>
<%
}
%>
其他页中引用<%@ include file="isLogin.jsp" %>
附
//取得用户的口令加密byte[]
private byte[] madeBytes(String str)throws
NoSuchAlgorithmException, UnsupportedEncodingException{
//随机数生成器
SecureRandom random=new SecureRandom();
//声明盐数组变量
byte[] salt=new byte[12];
//声明加密后的口令数组变量
byte[] pwd=null;
//将随机数放入盐变量中
random.nextBytes(salt);
//声明消息摘要对象
MessageDigest md=null;
//创建消息摘要
md = MessageDigest.getInstance("MD5");
//将盐的数据传给消息摘要对象
md.update(salt);
//将口令的数据传给消息摘要对象
md.update(str.getBytes("UTF-8"));
//获得消息摘要的字节数组
byte[] digest=md.digest();
//因为要在口令的字节数组中存放盐,因此加上盐的字节长度
pwd=new byte[digest.length+12];
//将盐的字节拷贝到生成后的口令字节数组的前12个字节
//以便在验证口令时会将盐取出
System.arraycopy(salt,0,pwd,0,12);
//将消息摘要拷贝到口令数组的从第13个字节开始的字节
System.arraycopy(digest,0,pwd,12,digest.length);
//返回生成的口令字节
return pwd;
}
//检验口令是否相等
private String validPwd(String str,byte[] pwdInDb) throws
NoSuchAlgorithmException, UnsupportedEncodingException{
//声明是否匹配的字符串变量
String validated="";
//声明盐变量
byte[] salt=new byte[12];
//将盐从数据库中保存的口令字节数组中拷贝出来
System.arraycopy(pwdInDb,0,salt,0,12);
//创建消息摘要对象
MessageDigest md=MessageDigest.getInstance("MD5");
//将盐的数据传给消息摘要对象
md.update(salt);
//将口令数据传给消息摘要对象
md.update(str.getBytes("UTF-8"));
//生成输入口令的消息摘要
byte[] digest=md.digest();
//声明一个保存数据库中口令消息摘要的变量
byte[] digestInDb=new byte[pwdInDb.length-12];
//取得数据库中口令的消息摘要
System.arraycopy(pwdInDb,12,digestInDb,0,pwdInDb.length-12);
//比较数组中的值是否相等
if(Arrays.equals(digest, digestInDb))
{
//口令正确返回口令匹配信息
validated = "match";
return validated;
}
else
{
//口令不正确返回口令不匹配信息
return validated;
}
}
//处理用户注册
public Person register(String personId, String password,
String pwd,String personName,Departments department,
String email,String telephone)
throws UserException {
//构建一个新用户
Person person=new Person();
try {
//判断口令
if(password.equals(pwd)){
//设置用户属性
person.setPersonId(personId);
byte[] pwdBytes=null;
try{
//将口令从字符串转换为字节数组
pwdBytes=madeBytes(password);
}
catch(NoSuchAlgorithmException ne){
//处理加密方法的异常
ne.printStackTrace();
}
catch(UnsupportedEncodingException ue){
//处理加密方法的错误
ue.printStackTrace();
}
person.setPassword(pwdBytes);
person.setPersonName(personName);
person.setDepartment(department);
person.setEmail(email);
person.setTelephone(telephone);
//用dao在数据库表中创建一个用户记录
userDao.create(person);
}
else{
//表示欲注册的用户名不合乎要求,不能返回用户对象
person=null;
}
//返回用户对象
return person;
}
//处理数据库访问异常
catch(DataAccessException daoe){
//判断是否是因为该用户名已经注册过
try{
userDao.find(personId);
}
catch(DataAccessException daoe1){
throw new DbException(daoe.getMessage());
}
daoe.printStackTrace();
//如果该用户名已经注册,则抛出重复的用户异常
throw new DuplicateUserException(personId);
}
}
//处理用户登录
public Person login(String personId, String password) throws UserException {
//构建一个新用户
Person person=new Person();
try {
//调用DAO查找用户
person=userDao.find(personId);
if(person!=null){
//判断口令是否匹配
String valid="";
try{
valid=validPwd(password,person.getPassword());
}
catch(NoSuchAlgorithmException ne){
//处理加密方法的异常
ne.printStackTrace();
}
catch(UnsupportedEncodingException ue){
//处理加密方法的错误
ue.printStackTrace();
}
if("match".equals(valid)){
//加入所有部门列表
List departments=findAllDepartments();
person.setDepartments(departments);
//加入登录用户的权限
List permissions=findPermission(personId);
person.setPermissions(permissions);
}
else{
//表示用户名和口令合乎要求的用户不存在
person=null;
}
}
else{
//如果数据库中找不到用户记录抛出异常
throw new DataNotFoundException(personId);
}
//如果通过验证,返回与该人员标识对应的人员对象
return person;
}
//处理数据访问异常
catch(DataNotFoundException ue){
ue.printStackTrace();
throw new UserNotExistException(personId);
}
catch(DataAccessException daoe){
daoe.printStackTrace();
throw new DbException(daoe.getMessage());
}
}