论坛首页 Java版 Spring

Acegi X.509双向认证 (添加验证码jcaptcha)

浏览 10384 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2007-09-11
准备知识:
1.SSL(Server Socket Layer)简介
在网络上信息在源-宿的传递过程中会经过其它的计算机。一般情况下,中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易的时候有可能被监视,从而导致个人隐私的泄露。由于Internet和Intranet体系结构的原因,总有某些人能够读取并替换用户发出的信息。随着网上支付的不断发展,人们对信息安全的要求越来越高。因此Netscape公司提出了SSL协议,旨在达到在开放网络(Internet)上安全保密地传输信息的目的,这种协议在WEB上获得了广泛的应用。之后IETF(www.ietf.org)对SSL作了标准化,即RFC2246,并将其称为TLS(Transport Layer Security),从技术上讲,TLS1.0与SSL3.0的差别非常微小。

2.SSL工作原理
SSL协议使用不对称加密技术实现会话双方之间信息的安全传递。可以实现信息传递的保密性、完整性,并且会话双方能鉴别对方身份。不同于常用的http协议,我们在与网站建立SSL安全连接时使用https协议,即采用https://ip:port/的方式来访问。当我们与一个网站建立https连接时,我们的浏览器与Web Server之间要经过一个握手的过程来完成身份鉴定与密钥交换,从而建立安全连接。具体过程如下:

用户浏览器将其SSL版本号、加密设置参数、与session有关的数据以及其它一些必要信息发送到服务器。
服务器将其SSL版本号、加密设置参数、与session有关的数据以及其它一些必要信息发送给浏览器,同时发给浏览器的还有服务器的证书。如果配置服务器的SSL需要验证用户身份,还要发出请求要求浏览器提供用户证书。
客户端检查服务器证书,如果检查失败,提示不能建立SSL连接。如果成功,那么继续。客户端浏览器为本次会话生成pre-master secret,并将其用服务器公钥加密后发送给服务器。如果服务器要求鉴别客户身份,客户端还要再对另外一些数据签名后并将其与客户端证书一起发送给服务器。
如果服务器要求鉴别客户身份,则检查签署客户证书的CA是否可信。如果不在信任列表中,结束本次会话。如果检查通过,服务器用自己的私钥解密收到的pre-master secret,并用它通过某些算法生成本次会话的master secret。
客户端与服务器均使用此master secret生成本次会话的会话密钥(对称密钥)。在双方SSL握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量低一个数量级以上,能够显著提高双方会话时的运算速度。
客户端通知服务器此后发送的消息都使用这个会话密钥进行加密。并通知服务器客户端已经完成本次SSL握手。
服务器通知客户端此后发送的消息都使用这个会话密钥进行加密。并通知客户端服务器已经完成本次SSL握手。
本次握手过程结束,会话已经建立。双方使用同一个会话密钥分别对发送以及接受的信息进行加、解密。




前提在apps目录下创建三个目录:root server client
创建root证书:
创建私钥 :C:\OpenSSL\apps>openssl genrsa -out root/root-key.pem 1024
创建证书请求 :C:\OpenSSL\apps>openssl req -new -out root/root-req.csr -key root/root-key.pem
自签署证书 :C:\OpenSSL\apps>openssl x509 -req -in root/root-req.csr -out root/root-cert.pem -signkey root/root-key.pem -days 3650
将证书导出成浏览器支持的.p12格式 :C:\OpenSSL\apps>openssl pkcs12 -export -clcerts -in root/root-cert.pem -inkey root/root-key.pem -out root/root.p12
打印自签证书 : C:\OpenSSL\apps>keytool -printcert -file root/root-cert.pem

创建server证书:
创建私钥 :C:\OpenSSL\apps>openssl genrsa -out server/server-key.pem 1024
创建证书请求 :C:\OpenSSL\apps>openssl req -new -out server/server-req.csr -key server/server-key.pem
自签署证书 :C:\OpenSSL\apps>openssl x509 -req -in server/server-req.csr -out server/server-cert.pem -signkey server/server-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650
将证书导出成浏览器支持的.p12格式 :C:\OpenSSL\apps>openssl pkcs12 -export -clcerts -in server/server-cert.pem -inkey server/server-key.pem -out server/server.p12
打印自签证书 : C:\OpenSSL\apps>keytool -printcert -file server/server-cert.pem


创建client证书:
创建私钥 :C:\OpenSSL\apps>openssl genrsa -out client/client-key.pem 1024
创建证书请求 :C:\OpenSSL\apps>openssl req -new -out client/client-req.csr -key client/client-key.pem
自签署证书 :C:\OpenSSL\apps>openssl x509 -req -in client/client-req.csr -out client/client-cert.pem -signkey client/client-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650
将证书导出成浏览器支持的.p12格式 :C:\OpenSSL\apps>openssl pkcs12 -export -clcerts -in client/client-cert.pem -inkey client/client-key.pem -out client/client.p12
打印自签证书 : C:\OpenSSL\apps>keytool -printcert -file client/client-cert.pem


这一步是可选的,根据root证书生成JKS文件
生成JKS文件 :
 C:\OpenSSL\apps\root>keytool -import -v -trustcacerts -storepass password -alias root -file root-cert.pem -keystore root.jks


把root.jks,root.p12,server.p12三个文件复制到C:\tomcat\conf目录去

启动tomcat SSL的配置,在server.xml中更改配置为:
<Connector port="8443" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" disableUploadTimeout="true"
               acceptCount="100" scheme="https" secure="true"
               sslProtocol="TLS"
               clientAuth="true" keystoreFile="C:/tomcat/conf/server.p12"
               keystoreType="PKCS12" keystorePass="password"
               truststoreFile="C:/tomcat/conf/root.jks"
               truststoreType="JKS" truststorePass="password" />


经过以上步骤后,Tomcat服务器身份和根证书就算搞定了,但是客户身份换没有搞定。我们要把client.p12和root.p12导入到浏览器中去。
操作步骤为:打开IE->Internet选项->内容->证书
client.p12导入如图片client.gif
root.p12导入如图片root.gif


完成以上步骤后,可以访问https://localhost:8443/ 了,不出意外就能看到你想要的结果

下一步就是在http://www.javaeye.com/topic/88209 的基础上实现X.509认证,请关注!
  • 342b9f01-efd7-4127-b601-b3e2516df92e-thumb
  • 描述:
  • 大小: 17.9 KB
  • 7d30aad7-f708-4a0e-ad38-e5f327aa6a9a-thumb
  • 描述:
  • 大小: 23.1 KB
   
最后更新时间:2007-06-10
1:要想启用acegi X.509双向认证,就需要配置X509ProcessingFilter过滤器。
<bean id="x509ProcessingFilter" class="org.acegisecurity.ui.x509.X509ProcessingFilter">
		<property name="authenticationManager" ref="authenticationManager" />
</bean>

从doFilter()方法中可以看到,先从HttpServletRequest中获取java.security.cert.X509Certificate证书。
并把它构建成一个X509AuthenticationToken认证对象,
X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
最后认证管理器会认证这一个X509AuthenticationToken对象。
authResult = authenticationManager.authenticate(authRequest);
认证成功后,进一步处理下一个过滤器

2:配置X509AuthenticationProvider认证提供者。并把它添加大authenticationManager认证管理器中
	<bean id="x509AuthenticationProvider" class="org.acegisecurity.providers.x509.X509AuthenticationProvider">
		<property name="x509AuthoritiesPopulator"><ref local="x509AuthoritiesPopulator"/></property>
    <property name="x509UserCache"><ref local="x509UserCache"/></property>
	</bean>

<!-- 从数据库中获取x.509CA证书对应用户的其他详细信息 -->
	<bean id="x509AuthoritiesPopulator" class="org.acegisecurity.providers.x509.populator.DaoX509AuthoritiesPopulator">
		<!--<property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>-->
		<property name="userDetailsService" ref="jdbcDaoImpl"/>
	</bean>


3:为了提高性能,减少频繁加载用户信息,配置一个缓存
4:最后要提供X509ProcessingFilterEntryPoint,并添加到ExceptionTranslationFilter中
	<bean id="x509ProcessingFilterEntryPoint" class="org.acegisecurity.ui.x509.X509ProcessingFilterEntryPoint">
	</bean>

5:注意要把x509ProcessingFilter放在logoutFilter后面
6:启用双向通道,以后单独详细道来!
7:用附件中的文件替换http://www.javaeye.com/topic/88209中工程的applicationContext-acegi-security.xml即可运行
8:表单认证没有去掉。这时不再需要了。
9:ssl认证也不是非常的安全,有人就用木马盗用认证文件
  • 19991172-c9bb-4966-af10-d4f1d899a8a3-thumb
  • 描述: 运行的结果
  • 大小: 30.6 KB
   
0 请登录后投票
最后更新时间:2007-06-11
在以前的工程的基础上添加了验证码功能(jcaptcha)。如果与登入验证结合,acegi实现的比较复杂,主是提供了好多其他的功能,我是通过改了AuthenticationProcessingFilter实现的。
在JcaptchaAuthenticationProcessingFilter.java中
之添加了下面的代码:
        //验证验证码
        AuthenticationException lastException = null;
        String captchaResponse = request.getParameter(ACEGI_SECURITY_FORM_JCAPTCHA_KEY);
        if ((request != null) && request instanceof HttpServletRequest && (captchaResponse != null)) {
            logger.debug("captcha validation parameter found");
            // validate the request against CaptchaServiceProxy
            boolean valid = false;
            logger.debug("try to validate");
            //get session
            HttpSession session = ((HttpServletRequest) request).getSession();
            if (session != null) {
                String id = session.getId();
                valid = this.captchaService.validateReponseForId(id, captchaResponse);
                logger.debug("captchaServiceProxy says : request is valid = " + valid);
                if (valid) {
                    logger.debug("update the context");
                } else {
                	lastException = new JcaptchaNullException("输入的验证码不正确......");
                    logger.debug("captcha test failed");
                }
            } else {
                logger.debug("no session found, user don't even ask a captcha challenge");
            }
        } else {
            logger.debug("captcha validation parameter not found, do nothing");
        }
        if (lastException != null) {
        	throw lastException;
        }
  • 86c56790-d0f7-4bbb-8c73-2d43dd3d14aa-thumb
  • 描述:
  • 大小: 8.6 KB
  • AcegiExample.rar (419.8 KB)
  • 描述: 只要添加jar包和建立数据库就可以运行
  • 下载次数: 201
   
0 请登录后投票
最后更新时间:2007-06-11
不知道在手机上面(WAP)支不支持证书认证?
   
0 请登录后投票
最后更新时间:2007-06-19
一直以来acegi默认时 users表与其他表直接的关联都是通过username字段进行关联的,这样在实际应用中很不符合要求,都是通过id进行关联的,如果要改动在基本的功能中还是好改的。但到了ACL部分就比较麻烦了,要重写JdbcMutableAclService。唉!只能慢慢改了。
   
0 请登录后投票
最后更新时间:2007-06-19
我用debug跟踪org.acegisecurity.ui.x509.X509ProcessingFilter类的方法,
private X509Certificate extractClientCertificate(HttpServletRequest request)

X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate")
certs总是null,导致认证失败,为什么?

有什么地方需要注意的吗?
   
0 请登录后投票
最后更新时间:2007-06-19
“6:启用双向通道,以后单独详细道来! ”
怎样启用双向通道? 我这边一直是单通道。
   
0 请登录后投票
最后更新时间:2007-06-19
你的服务器端没有配置成功。你按我上面的配置去做
   
0 请登录后投票
最后更新时间:2007-06-19
Arden 写道
不知道在手机上面(WAP)支不支持证书认证?


acegi是基于http协议的,所以,手机上是没法使用这套安全机制的
   
0 请登录后投票
最后更新时间:2007-06-20
我现问一下,我也试了一个https的验证,有点问题,就是不管验证成功还是不成功,都进入成功页面,melin你认为哪有错?谢谢!
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐