任务:
了解
1.了解网站安全的基础知识
2.基于代码级的JAAS认证和授权
理解
1.Web开发中的安全编码
2.数据加密
3.基于角色的认证和授权
运用
1.防止SQL注入
2.使用Java实现数据加密
--------------------------------------------------------------------------------------------------------
安全的基础知识
网站安全的重要性
网站安全的应用场合
电子商务网站[淘宝、诈骗]
电子政务网站[机密、形象]
票务系统网站
公司内部系统[OA系统、越权访问]
常见网站安全问题
拒绝服务(Dos Denial fo service)
现象:大规模无效访问,造成网络阻塞,用户无法连接
非法登录
获得网站用户的密码,在网站上为所欲为
数据库级别入侵
任意改变数据库数据
出售数据库数据
获得网站管理员权限,权限突破
网站管理混乱
无基本保护
基本的安全属性
机密性(保密性)
机密性就是保护数据避免被未授权用户访问的方法,简单地说只有合法的用户才能理解和接收正确的消息
完整性
确保合法用户最终获取的信息完整,未经篡改
可用性
可靠性
提供的服务不随时间地点的影响能够正常使用
不可否认性
网站入侵的攻击方法和原理
暴力破解
对登录的口令密码进行破解
利用工具反复性的试探攻击
缩小海量级试探次数的方法
字典档
规则破解[生日组合扩展]
常用攻击方法
远程通讯法
1.确定攻击目标(web/pop/telnet?)
2.建立多进程的Socket通信
3.通过字典当或规则生成密码
4.发送密码试探
本地文件破解
1.截取机密后的密码
2.通过字典或规则生成密码明文
3.将密码铭文按加密算法加密
4.将生成的密文和截取密文比较
sql注入
攻击原理
在Web表单或查询字符串中输入特殊的sql命令
实现欺骗服务器或绕过登录验证
例如登录:
密码:'aa' or 1=1 --
select * from userswhere uname='zhangsan' and upass='aa' or 1=1 --'
上传漏洞
攻击原理
利用上传漏洞直接得到webshell
网站服务器的安全漏洞
原因:
.字符串过滤不严格
.文件类型没有检测
.上传未加权取[未进行权限验证]
XSS跨站点攻击【XSS-Cross Site Scripting】
攻击原理
恶意用户在网页中插入HTML或JS脚本
引诱用户点击或输入用户隐私数据
黑客获取用户账号、Cookie等隐私数据
常见攻击方式:
js方式
<ahref="http://知名站点url?变量名= <script>document.location='http://localhost:8080/XSS_Attack/hack.jsp';alert(document.cookie);</script>">
钓鱼邮件图片或网站引诱图片等
</a>
iframe方式
<form id="shit"action="..." method="post"target="myframe"/>...
</form>
<iframe style="display:none"name="myframe"></iframe>
ajax方式
<script language="jscript">
v = newActiveXObject("MSXML2.XMLHTTP.3.0");
v.open("GET","url...");
v.send();
alert(v.statusText);
通过以上三种方式衍生出常用的攻击方式:
1.钓鱼邮件【邮件内容是知名网站的邀请等】
2.引诱图片链接
</script>
Cookie诈骗
原理:
Cookie是存放在客户端的用户数据
黑客可以通过修改本地Cookie来冒充管理员或用户
Dos攻击(拒绝服务攻击)
目前更流行DDos - 分布式拒绝服务攻击
攻击原理和过程:
1.黑客寻找攻击目标
2.黑客想傀儡控制机发出命令
3.傀儡控制机向傀儡攻击机发出命令
4.傀儡攻击机并发向目标发给攻击,引起正常访问失败。
解决方案(网络管理员关心范畴):
加装报警器
加装防火墙
加强路由设置
Web安全的防御思路
增加防御物
1.防火墙、VPN、内外网物理隔离
2.加密(传输内容)
3.确认身份--[认证]
4.控制访问资源--[授权]
5.跟踪操作--审计和日志
开发人员在进行Web开发是如何处理安全问题
概述:
严格验证用户输入数据:SQL注入、XSS安全漏洞
Web编程安全方面的经验法则主要有:
输入验证
验证内容
经典的安全法则:永远不要相信用户提交的数据,用户提交的数据永远都需要验证的
用户名、密码等格式
验证长度防止数据库溢出错误
邮件、手机、邮编等格式
验证输入的方法
客户端
写js脚本验证,过滤用户输入
服务器端:
检测用户输入的合法性
强制转换用户输入
数据入库约束验证
防止SQL注入的解决思路
客户端:
.过滤或转义危险字符
.使用正则表达式限制输入
服务器端:
.控制数据库的访问权限
.分步验证用户名和密码
.对账号做加密处理
实践
SQL注入示范:
客户端使用正则表达式验证:
<script>
function stripscript(s){
var pattern = newRegExp("!@#$%^&*()'?/-+=\\[\\].<>~%");
var rs ="";
for(vari=0;i<s.length;i++){
rs =rs+s.substr(i,1).replace(pattern,"");
}
return rs;
}
functioncheckAllTextValid(form){
//记录不含引号的文本框数量
var resultTag = 0;
//记录所有text文本框数量
var flag=0;
for(vari=0;i<form.elements.length;i++){
if(form.elemengts[i].type=="text"){
flag = ++;
if(/^['\-"'<>]*$/).test(form.elements[i].value)
resultTag++;
else
form.elements[i].select();
}
}
if(resultTag==flag)
return true;
else{
alert("文本框中不能包含:\n\n1 单引号\n 2 双引号 \3 竖线\n\n请重新检查输入内容");
return false;
}
}
</script>
服务器端使用正则表达式验证:
public class SpecialTokenFilter{
public static StringstringFilter(String str){
//清除掉所有特殊字符
String regEx ="[!@#$%^&*()'?/-+=\\[\\].<>~%]";
Pattern p =Pattern.compile(regEx);
Matcher m =p.matcher(str);
returnm.replaceAll("").trim();
}
}
图片验证码
目的:避免暴利攻击
验证码的原理:
1.随机生成验证码图片
2.发送图片,同时存入Session
3.提交输入的验证码及表单数据
4.读取Session,和用户的输入逇验证码比较
5.根据比较结果确定是否执行DB操作
防范跨站脚本XSS攻击
解决思路:
实行严格的输入验证
实现Session标记等
进行HTML的格式化
示范:
数据加密
概述:
Java中默认情况是关闭了沙箱功能的,如果运行中开启了沙箱后又没有进行任何授权,那么程序进行一个操作的时候会报错,因为当前操作没有被授权,Java安全体系结构中最基本的思路:所有的操作都要经过认证和授权才能进行操作
Java提供的安全模型和API
Java语言本身的安全性
自动内存管理
自动数组溢出检查等
字节代码的验证机制
独特的安全类加载
Java加密体系
JCA和JCE是两个重要的框架
JCA:Java Crytography Architecture[Java加密的基本框架]
数字签名
信息摘要
JCE:Java Crytography Extension[Java加密扩展框架]
MD5(消息摘要算法)
SHA(安全散列算法)
DES(数据加密算法)
自从JDK1.4之后JCE和JDK已经捆绑发行了
这两个框架都遵守“算法和实现的独立”特点,它们都通过额外的框架提供服务,使用时不需要关心具体的加密细节,Java平台已经帮助您实现了加密算法,您只管调用相应类就可以了
Java的认证和授权
Java平台在认证和授权方面有一套独立的框架JAS,对于开发中间件来说用JAS比较多,什么是中间件呢?简单地说就是给开发商开发人员用的软件,比如tomcat、jboss、weblogic,他们是比较通用的东西,不面向具体客户,对于具体客户(终端用户),比如银行、电信,JAS使用就比较少,在面向终端用户进行开发的时候,对于安全方面一般都会采用配置文件方式进行认证和授权。
基于配置文件的认证和授权
特点:
只需配置配置文件,方便修改
应用场合:一般适用于B/S开发
安全控制粒度:一般只能到某个页面(不能控制到代码方法,但是大多数网站只需控制到Web层就可以了)
如果想将控制粒度提高到代码级别,那么就需要基于源代码的认证和授权
基于源代码的认证和授权
特点:
安全控制粒度:可以控制到某个类甚至方法
应用场合:C/S或B/S开发均可
JAAS: Java Authentication and AuthorizationService
解决了传统的访问控制安全问题(传统的访问控制只能看代码从哪里来,谁签的名,很容易代码黑客攻击,还应该判断谁在执行代码,JAAS解决了这个问题)
JAAS通过可插拔方式在应用中嵌入安全的认证和授权模块,安全控制起来很方便,另外客户端不管是一个应用还是一个application还是一个Bean还是一个Servlet
安全通信
概述:
当信用卡用户密码私有信息通过网络传输时,这些信息可能被他人窃取,我们需要确保这些通讯的安全,Java提供了对标准安全通信协议的实现API
Java提供了对标准安全通信协议的实现API
SSL Secure Socket Layer(安全套接层协议)
TLS Transport LayerSecurity(安全传入层协议),这是SSL的升级版本
Kerberos(一种网络认证协议)
当然这些协议的实现是以牺牲性能为代价的。
PKI体系
Public Key Infrastructure,主要用于“基于公钥体系”的信息安全交换
Java的PKI规范提供了管理Key和证书的API
实现协议
X.509(最常用)
CRL(证书撤销列表)
PKCS等
PKI的核心是数字证书
提供Certifficate数字证书对象等
管理证书的工具
keytool
jarSignner
加密基础知识
加密算法分为两类:
对称加密(私钥体系)
特点:
单钥,用同一把钥匙加密和解密
加密/解密速度快,安全性取决于私钥的保管
是一种可逆算法
典型算法:
DES(数据加密算法,58位,安全性不够高)
AES(高级加密标准,128位,常用)
非对称加密(公钥体系)
特点:
加密用公钥,解密用私钥
安全性较高,加密/解密慢,适用于分布式网络
典型应用:数字证书
典型算法:
RSA算法
DSA算法
单向散列函数
h = H(m)返回长度为m的散列值h,H是算法,生成的h值不可逆
例如:
goodday ==> (MD%单向散列函数h=H(m))==> 0CF21CE35322D2E56D745E319B933470
使用单向散列函数对明文进行加密是目前各大网站使用最多的算法,因为生成的密码文不可逆。
特点:
加密快、不可逆、破解困难
典型算法:
MD5(128位,安全性不够高,目前已被中国人通过碰撞法破解)
SHA或SHA1(160)
非对称加密和单向散列函数加密有什么区别呢?
非对称加密用的是公钥加密私钥解密,但是单向散列函数只对既定信息用固定算法加密,但是不存在解密这么一个过程,是一个不可逆加密过程
使用Java实现加密
示范,使用MD5实现加密[散列加密,生成密码不可逆]:
/*
*散列加密MD5算法
*MD5生成的密码不可逆
*使用MD5步骤:
* 1.生成MD5算法的对象
* 2.使用MD5算法加密明文
* 3.获取MD5摘要,返回一个字节数组(散列值)
* 4.将字节数组生成为加密后的密码字符串
* MD5目前还是很对企业对于密码保护的主要措施
*/
public class MD5{
public void gernerateMD5(stringtext) throws NoSuchAlgorithmExcpetion{
//第一步
MessageDigestmd5 = MessageDigest.getInstance("MD5");
//第二步
md5.update(text.getBytes());
//第三步
byte[]hashcode = md5.digest();
//第四步
StringBuffer md5_str = newStringBuffer(hashcode.length<<1);
for(inti=0;i<hashcode.length;i++){
md5_str.append(Character.forDigit((hashcode[i]>>4)&0xf,16));
}
System.out.println(md5_str.toString());
}
}
示范,使用对称加密给文本加密
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.Scanner;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
class SymmetricEncoder{
/*
*加密过程
*1.构造密钥生成器
*2.根据encodeRules初始化密钥生成器
*3.产生密钥
*4.创建和初始化密码器
*5.内容加密
*6.返回字符串
*/
public static String AESEncode(StringencodeRules,String content){
try {
//1.构造密钥生成器,指定AES算法
KeyGeneratorkeygen= KeyGenerator.getInstance("AES");
//2.初始化密钥生成器
keygen.init(128,newSecureRandom(encodeRules.getBytes()));
//3.产生原始对称密钥
SecretKeyoriginal_key = keygen.generateKey();
//4.获得原始对称密钥字节数组
byte[] raw =original_key.getEncoded();
//5.生成密钥
SecretKeySpeckey = new SecretKeySpec(raw,"AES");
//6.根据指定算法AES创建密码器
Ciphercipher = Cipher.getInstance("AES");
//7.初始化密码器
cipher.init(Cipher.ENCRYPT_MODE,key);
//8.获取加密内容字节数组
byte[] byte_encode =content.getBytes();
//9.根据密码器初始化的方式加密:将数据加密
byte[] byte_AES =cipher.doFinal(byte_encode);
//10.将加密后的数据转换为字符串
StringAES_encode = new String(newBASE64Encoder().encode(byte_AES));
return AES_encode;
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
/*
*解密过程
*1.构造密钥生成器
*2.根据encodeRules初始化密钥生成器
*3.产生密钥
*4.创建和初始化密码器
*5.将加密后的字符串反编码成byte[]数组
*6.将加密内容解密
*/
public static String AESDEncode(StringencodeRules,String content){
try {
//1.构造密钥生成器,指定AES算法
KeyGeneratorkeygen= KeyGenerator.getInstance("AES");
//2.初始化密钥生成器
keygen.init(128,newSecureRandom(encodeRules.getBytes()));
//3.产生原始对称密钥
SecretKeyoriginal_key = keygen.generateKey();
//4.获得原始对称密钥字节数组
byte[] raw =original_key.getEncoded();
//5.生成密钥
SecretKeySpeckey = new SecretKeySpec(raw,"AES");
//6.根据指定算法AES创建密码器
Ciphercipher = Cipher.getInstance("AES");
//7.初始化密码器
cipher.init(Cipher.DECRYPT_MODE,key);
//8.将加密并编码后的内容解码成字节数组
byte[] byte_content = newBASE64Decoder().decodeBuffer(content);
//9.解密content
byte[] byte_decode =cipher.doFinal(byte_content);
StringAES_encode = new String(byte_decode,"utf8");
return AES_encode;
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
}
public static void main(String[] args) {
Stringdecode = SymmetricEncoder.AESEncode("jiang","accp");
System.out.println("accp加密后:"+decode);
System.out.println(decode+"解密后:"+SymmetricEncoder.AESDEncode("jiang",decode));
}
基于页面级的认证和授权
Servlet规范规定的认证方式
Servlet规范中基于角色控制的实现思路:
域(realm) 用户的集合[类似于用户组的概念]
用户(user)
密码(password)
所属角色(role)
对于遵守Servlet规范的服务器来说,比如tomcat,它就包含了一个域,这个域在conf/tomcat-users.xml中进行配置的,如下:
<tomcat-users>
<rolerolename="tomcat"/>
<rolerolename="role1"/>
<userusername="tomcat" password="tomcat"roles="tomcat"/>
<userusername="both" password="tomcat"roles="tomcat,role1"/>
<userusername="role1" password="tomcat"roles="role1"/>
</tomcat-users>
它配置了用户名密码、角色这些信息,但不包含权限信息。某个页面或文件要被哪些角色角色权访问的权限信息要在web.xml文件中进行配置,如下图:
用户、角色:
tomcat-users.xml
访问权
Web.xml
Servlet规范的四种认证方式:
Basic验证
概述:
浏览器弹出登录窗体要求输入用户名和密码信息
特点:
明文传送口令,安全性低。
Digest验证
概述:采用消息摘要加密的方式传送口令,安全性较高
特点:消息摘要方式传送、安全性较高。常见的MD5或者SHA加密都属于这类
实现步骤:
1、 配置tomcat-users.xml文件(也可配置在各应用下)
a) 指定用于的角色名、用户、用户密码、所属角色,例如:
i. <role rolename=”角色名”/>
ii. <user username=”用户名” password=”加密后的密码” roles=”所属角色名”/>
b) 然后密码使用digest命令加密
2、 之后配置Server.xml,设为Digest验证方式
a) <realm className=”…..” digest=”md5”/>
3、 然后再配置具体应用的Web.xml
代码示范:
1. 在WebRoot下创建一目录protected,将受保护的jsp文件放入
2. 配置当前项目的web.xml
<security-constraint>
<web-resource-collection>
<url-pattern>/protected/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>DIGEST</auth-method>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
3.在tomcat的tomcat-users.xml文件里面添加自己的角色admin和用户manager
<tomcat-users>
<rolerolename="tomcat"/>
<rolerolename="role1"/>
<rolerolename="admin"/>
<userusername="manager" password="manager"roles="admin"/>
<userusername="tomcat" password="tomcat"roles="tomcat"/>
<userusername="both" password="tomcat"roles="tomcat,role1"/>
<userusername="role1" password="tomcat"roles="role1"/>
</tomcat-users>
Tomcat是如何找到tomcat-user.xml并进行验证的呢?
当使用Digest认证的时候,Tomcat会找Server.xml下面的这个域<RealmclassName="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>,“org.apache.catalina.realm.UserDatabaseRealm”这个类就会去查找tomcat-users.xml
Form验证
概述:常见的表单验证,和Basic验证一样采用明文方式传送口令,安全性低。
特点:安全性低,但可以自定义页面。
实现步骤:
1.配置当前项目的web.xml
<security-constraint>
<web-resource-collection>
<url-pattern>/protected/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/security_lgoin.jsp</form-login-page>
<form- error -page>/error.jsp</form-error-page>
</fogm-login-config>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
2.创建security_lgoin.jsp页面
<form action="j_security_check"method="post">
<p>账户:<input type="text" name="j_username"/></p>
<p>密码:<input type="password" name="j_password"/></p>
<p><input type="submit" value="login"/></p>
</form>
3.在目录protected下创建保护页面archivelist.jsp
<body>
<h3>正确访问档案信息</h3>
</body>
4.创建错误页面
5.在tomcat-users.xml文件中配置角色和用户
<tomcat-users>
<role rolename="tomcat"/>
<rolerolename="admin"/>
<role rolename="role1"/>
<user username="both"password="tomcat" roles="tomcat,role1"/>
<user username="tomcat"password="tomcat" roles="tomcat"/>
<userusername="jiang" password="jiang"roles="admin"/>
<user username="role1"password="tomcat" roles="role1"/>
</tomcat-users>
红颜色是添加的角色和用户
6、部署并启动项目
7、浏览器地址栏输入要访问的保护页面地址,自动出现登录页面正确即进入保护页面,用户名密码不正确进入错误页面,用户名密码正确但未通过授权则显示:
HTTP Status 403 - Access to the requestedresource has been denied
注意正确的用户名和密码是jiang/jiang,tomcat/tomcat也是可以通过认证的用户名和密码但是不能通过授权,会出现403错误
如何将用户角色信息放入数据库
1. 创建用户表和角色表
a) 用户表(userName、password)
b) 角色表(userName、roleName)
2. 更改Context.xml文件,设置数据库驱动等信息
<Context>
<RealmclassName="org.apache.catalina.realm.JDBCRealm"
driverName="驱动程序名称" connectionURL="URL"
userTable="用户表名" userNameCol="用户字段名"
userCredCol="密码字段名" userRoleTable="角色表名"
roleNameCol="角色字段名" />
</Context>
注意:将驱动程序的jar文件放入到tomcat的common的lib下
2. 到数据库创建相应的表
3. 修改Server.xml文件
<RealmclassName="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<!-- Comment out the old realm but leave here for now in case we
need to go back quickly -->
<!--
<RealmclassName="org.apache.catalina.realm.MemoryRealm" />
-->
<!-- Replace the above Realm with one ofthe following to get a Realm
stored in a database and accessedvia JDBC -->
<!--
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="org.gjt.mm.mysql.Driver"
connectionURL="jdbc:mysql://localhost/authority"
connectionName="test"connectionPassword="test"
userTable="users"userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles"roleNameCol="role_name" />
-->
<!--
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="oracle.jdbc.driver.OracleDriver"
connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
connectionName="scott"connectionPassword="tiger"
userTable="users"userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles"roleNameCol="role_name" />
-->
将蓝色的部分代码注释掉,然后根据您使用的数据库用一段红色的代码替换。绿色的部分就是告诉我们可以用下面的域去替换上面的域。
注意:将驱动程序的jar文件放入到tomcat的common的lib下
Client-Cert验证
概述:采用数字证书验证方式加密,安全性较高。
特点:采用数字证书方式,一般和SSL配合(要开启SSL)
为什么需要数字证书?
数字证书就是在数字签名的基础上应运而生的。
数字签名的原理
数字签名:公钥+私钥的一种应用
常用的数字签名算法有RSA和DSA算法
流程:
发送方对发送消息物理签名,接收方法验证签名,发送方利用软件生成公钥和密钥对,将公钥告知信任的人,私钥自己保管
1.发送方对发送内容产生一个消息摘要,该摘要是唯一的,只要发送内容被篡改,摘要将会变化。
2. 发送方对消息摘要使用私钥进行加密,连同发送内容一同发送给接收方。
3. 接收方接收到内容后利用发送者的公钥解开加密后的消息摘要值,如果发送方的公钥无法解开消息摘要值,那么说明这个消息不是发送方发送的消息,从而证实当前的信息来源是否真实。
4. 接收方法对接收内容重新产生消息摘要值,并比较这个摘要值是否和第3步中解密的消息摘要值相等,如果不相等,说明发送的消息被篡改过。如果相等说明没有被篡改过,是完整的信息。
数字证书的原理
概述:数字签名的安全性已经较高了,但是涉及到网上交易,比如淘宝、支付宝。因为在交易时数字签名还不能确定对方的合法性,它需要第三方机构来证明。这个时候就要采用数字证书,它是通过第三方机构(比如银行)颁发的证书来证明你的身份,从而保证您的身份是唯一的。在网上交易时,商务交易双方都信任第三方,即CA(CertificateAuthority)证书颁发机构,这个第三方机构负责发放、管理、验证数字证书。它是电子商务中的关键环节。和身份证一样,首先由第三方证书发布机构向申请者发布证书,类似于由公安机关给申请者发放身份证一样。身份证是你的唯一标识,身份证除了你的基本信息外,还有公安机关的章。数字证书也有相应机构的章,数字证书的内容:申请者的信息、申请者的公钥、CA(CertificateAuthority)证书颁发机构的数字签名。
数字证书的原理:
1.数字证书是数字签名的运用。采用公钥+私钥加密方式,私钥自己保管,用于解密和签名。
2.公钥由用户供发给自己信任的人用于加密和验证签名。发布方用接收方的公钥加密,接收方用自己的私钥解密。和数字签名的道理一样。因为有第三方机构的参与,所以还能够证实对方的合法性
3.为了交易更加安全,从而保证数据的真实性、完整性、合法性外还需要对发送的所有内容进行加密传送,以避免数据被黑客窃取,所以数字证书需要结合SSL使用,数字证书是一个双向验证过程,而SSL是双向认证通道。所以数字证书一般都需要和SSL这个通道结合使用。
事例说明如下:
例如:比如有两个用户Alice和Bob,Alice想把一段明文通过双钥加密的技术发送给Bob,Bob有一对公钥和私钥,那么加密解密的过程如下:
Bob将他的公开密钥传送给Alice.
Alice用Bob的公开密钥加密她的消息,然后传送给Bob。
Bob用他的私人密钥解密Alice的消息。
那么Bob怎么可以辨认Alice是不是真人还是冒充的。我们只要和上面的例子方法相反就可以了。
Alice用她的私人密钥对文件加密,从而对文件签名。
Alice将签名的文件传送给Bob.
Bob用Alice的公钥解密文件,从而验证签名。
Java中数字证书的实现思路
在jdk中可以实现数字证书的发布,步骤如下:
1.使用keytool等工具生成服务器端密钥仓库
2.在tomcat中配置启用SSL
3.导出服务器端证书
4.生成客户端密钥仓库
5.在客户端导入服务器端证书
示范:
为服务器生成证书
为客户端生成证书
导出cer文件
让服务器可以信任客户端证书
查看服务器证书信息(看是否成功导入客户端证书信息)
keytool-list -keystore tomcat.keystore
配置tomcat
步骤一:打开服务器Server.xml文件
步骤二:开启SSL通道
开启以下节点并进行配置:
步骤三:将证书导入到浏览器中
双击证书client.p12:
接下来启动tomcat
打开浏览器输入:https://localhost:8443,如过出现安全警告选择继续浏览网站即可。
基于代码级的认证和授权JAAS(Java AuthenticationAnd Authorization Service)
JAAS的特点
JAAS是对JCE安全框架的重要补充
提供基于用户认证和授权的动态安全解决方案
可插拔(Pluggable)的方式,Java程序和底层认证分开。只需通过配置既可以了。
JAAS的架构,如下图:
![](http://hi.csdn.net/attachment/201202/18/0_132956245573ww.gif)
说明:
.应用程序只需要和LoginContext登录上下文进行交互
.在LoginContext下是一组可配置的LoginModules对象,这些对象是通过配置文件进行配置的。
.针对LoginModules提供了各种实现类,如LDAP\RDBMS….
JAAS认证:
JAAS提供了先认证后授权思路的相应的API。
认证方面的常用类和接口:
LoginModule:登录模块(确认用户的合法性,确认用户名密码的合法性)
LoginContext:登录上下文(应用程序只和这个模块打交道,为了实现用户鉴别鉴定相应的环境,从配置文件从读取出安全验证需要哪些LoginModule)
CallbackHandler:回调处理器(验证的时候和用户的交互采用该接口完成,比如需要的用户名密码、验证结果等)
Subject:验证实体/主体(就是表示当前要验证的东西,有可能是一个用户、有可能是一个WebService、有可能是一个Bean)
Principal:身份/标识(表示具有某种访问权限的一个实体,可以看做是要执行某种操作所需要的一个身份证件,Subject能执行什么操作是什么身份就由Principal这个类来体现)
下面用一个图示来理解以上类和接口的关系:
描述:
1. 军事院校校方LoginModule要根据学生(Subject)的入学通知来确定其合法性
2. 校方将具体工作交由门卫兵(CallbackHandler)来执行
3. 门卫和学生交流要求出示入学通知书
4. 门卫将入学通知的确认结果告知校方领导,并作出相应处理。
5. 校方根据学生身份发给相应的身份证件(比如士官身份证件或者将军身份证件)
6. 学生(Subject)根据自己的身份证件(Principal)的级别可以访问学校的不同的资源。如果是士官级别只能访问士官级别的资源,如果是将军级别只能访问将军级别资源。
7. 当然一个学生可以有多个军衔(既是将军又是校长)
JAAS认证原理
设置JAAS配置文件
初始化loginContext对象,根据配置文件加载一个或多个LoginModule
通过调用LoginContext的login方法,最终将调用每个LoginModule的login方法来验证
JAAS认证的Java实现
n 编写主程序验证代码(客户端代码)
n 自定义登录模块(实现LoginModule接口)
l 主要实现以下5个方法:
n abort();
n commit();
n initialize();
n login();
n loginout();
n 创建用户信息管理类(实现CallbackHandler接口)
n 实现身份标识类(实现Principal接口)
n 配置认证策略文件(*.config)
示范:
自定义登录模块(实现LoginModule接口)下login()方法的实现:
创建用户信息管理类(实现CallbackHandler接口):
handle(Callbacck[]callbacks)
常见的callback类别
NameCallback
PasswordCallback
实现身份标识类(实现Principal接口)
Equal()
getName()
hashCode()
toString()
配置认证策略文件(*.config)
Required(必须)
Optional(可选)
Requisite(必须)
Sufficient(充分)
4.执行时指定配置文件
a) Java –Djava.security.auth.login.config=login.conf
JAAS授权的实现
用户已经通过认证(已经确认你是谁)
配置基于Principal的授权策略文件
用Subject的doAs/doAsPrivileged(执行敏感资源的访问)
JAAS授权的Java实现
实现授权的主程序代码
//...身份验证【调用login()方法后,被验证实体subject将填充表示能访问敏感资源的一个或多个Principal】
loginContext.login();
//...通过身份认证后
Subject mysubject=loginContext.getSubject();//获得通过验证后的subject
PrivilegedAction action = newCheckAccountAction();//创建访问敏感资源的特权动作action在run方法中具体实现
Subject.doAdPrivileged(mysubject,action,null);// 以subject的身份来执行特权动作(访问敏感资源)
实现敏感资源访问类(实现PrivilegedAction接口)
public classCheckAccountAction implements PrivilegedAction{
//@Override
public Object run() {
// TODOAuto-generated method stub
AccessController.checkPermission(newSimplePermission("operate"));
System.out.println("允许用户操作账户");
return new Integer(0);
}
}
配置授权策略文件jaas.policy
语法:
grant <signer(s)签名者>,<codeBase代码源url>
<Principal表示类>{
permission权限类名"target_name","action";
...
permission权限类名"target_name","action"
};
根据具体操作选择Permisson实现类:
以指定的身份执行特权动作来访问敏感资源
Subject.doAs(subject,action)
Subject.doAdPrivileged(subject,action,指定的访问控制上下文对象)