`
longgangbai
  • 浏览: 7325773 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SSO单点登录解决方案

阅读更多

实现SSO的技术主要有:
(1)基于cookies实现,需要注意如下几点:如果是基于两个域名之间传递sessionid的方法可能
在windows中成立,在unix&linux中可能会出现问题;可以基于数据库实现;在安全性方面可能会
作更多的考虑。另外,关于跨域问题,虽然cookies本身不跨域,但可以利用它实现跨域的SSO。
(2)Broker-based(基于经纪人),例如Kerberos等;
这种技术的特点就是,有一个集中的认证和用户帐号管理的服务器。经纪人给被用于进一步请求
的电子的身份存取。中央数据库的使用减少了管理的代价,并为认证提供一个公共和独立的"第三方"。
例如Kerberos,Sesame,IBM KryptoKnight(凭证库思想)等。Kerberos是由麻省理工大学发明的安全
认证服务,当前版本V5,已经被UNIX和Windows作为默认的安全认证服务集成进操作系统。
(3)Agent-based(基于代理人)
在这种解决方案中,有一个自动地为不同的应用程序认证用户身份的代理程序。这个代理程序
需要设计有不同的功能。比如, 它可以使用口令表或加密密钥来自动地将认证的负担从用户移开。
代理人被放在服务器上面,在服务器的认证系统和客户端认证方法之间充当一个"翻译"。例如SSH等。
(4)Token-based,例如SecurID,WebID,
现在被广泛使用的口令认证,比如FTP,邮件服务器的登录认证,这是一种简单易用的方式,实现一个口令
在多种应用当中使用。
(5)基于网关
Agent and Broker-based,这里不作介绍。
(6)基于安全断言标记语言(SAML)实现,SAML(Security Assertion Markup Language,安全断言标记语言)
的出现大大简化了SSO,并被OASIS批准为SSO的执行标准。开源组织OpenSAML 实现了 SAML 规范,
可参考http://www.opensaml.org/
CAS由耶鲁大学开发的单点登录系统(SSO,single sign-on),应用广泛,具有独立于平台的,易于理解,
支持代理功能。

一般来说,Web应用需要SSO的功能,应该通过以下的交互过程来调用身份认证服务的提供的认证服务:

  Web应用中每一个需要安全保护的URL在访问以前,都需要进行安全检查,如果发现没有登录(没有发现认证之后所带的cookie),就重新定向到SSOAuth中的login.jsp进行登录。

  登录成功后,系统会自动给你的浏览器设置cookie,证明你已经登录过了。

  当你再访问这个应用的需要保护的URL的时候,系统还是要进行安全检查的,但是这次系统能够发现相应的cookie。

  有了这个cookie,还不能证明你就一定有权限访问。因为有可能你已经logout,或者cookie已经过期了,或者身份认证服务重起过,这些情况下,你的cookie都可能无效。应用系统拿到这个cookie,还需要调用身份认证的服务,来判断cookie时候真的有效,以及当前的cookie对应的用户是谁。

  如果cookie效验成功,就允许用户访问当前请求的资源。

  以上这些功能,可以用很多方法来实现:

  在每个被访问的资源中(JSP或Servlet)中都加入身份认证的服务,来获得cookie,并且判断当前用户是否登录过。不过这个笨方法没有人会用:-)。

  可以通过一个controller,将所有的功能都写到一个servlet中,然后在URL映射的时候,映射到所有需要保护的URL集合中(例如*.jsp,/security/*等)。这个方法可以使用,不过,它的缺点是不能重用。在每个应用中都要部署一个相同的servlet。

  Filter是比较好的方法。符合Servlet2.3以上的J2EE容器就具有部署filter的功能。(Filter的使用可以参考JavaWolrd的文章http://www.javaworld.com/javaworld/jw-06-2001/jw-0622-filters.html)Filter是一个具有很好的模块化,可重用的编程API,用在SSO正合适不过。本样例就是使用一个filter来完成以上的功能。

 

package SSO;

 

import java.io.*;

import java.net.*;

import java.util.*;

import java.text.*;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.servlet.*;

import org.apache.commons.httpclient.*;

import org.apache.commons.httpclient.methods.GetMethod;

public class SSOFilter implements Filter {

    private FilterConfig filterConfig = null;

    private String cookieName="WangYuDesktopSSOID";

    private String SSOServiceURL=  "http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth";

    private String SSOLoginPage= "http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp";

    

    public void init(FilterConfig filterConfig) {

        this.filterConfig = filterConfig;

        if (filterConfig != null) {

            if (debug) {

                log("SSOFilter:Initializing filter");

            }

        }        

        cookieName = filterConfig.getInitParameter("cookieName");

        SSOServiceURL = filterConfig.getInitParameter("SSOServiceURL");

        SSOLoginPage = filterConfig.getInitParameter("SSOLoginPage");

    }  

.....

.....

 

  以上的初始化的源代码有两点需要说明:一是有两个需要配置的参数 SSOServiceURL和 SSOLoginPage。因为当前的Web应用很可能和身份认证服务(SSOAuth)不在同一台机器上,所以需要让这个filter知道身份认证服务部署的URL,这样才能去调用它的服务。另外一点就是由于身份认证的服务调用是要通过http协议来调用的(在本样例中是这样设计的,读者完全可以设计自己的身份服务,使用别的调用协议,如RMI或SOAP等等),所有笔者引用了apache的commons工具包(详细信息情访问apache 的网站http://jakarta.apache.org/commons/index.html),其中的“httpclient”可以大大简化http调用的编程。

  下面看看filter的主体方法doFilter():

 

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

 

        if (debug) log("SSOFilter:doFilter()");

        HttpServletRequest request = (HttpServletRequest) req;

        HttpServletResponse response = (HttpServletResponse) res;

        String result="failed";

        String url = request.getRequestURL().toString();

        String qstring = request.getQueryString();

        if (qstring == null) qstring ="";

        //检查http请求的head是否有需要的cookie

        String cookieValue ="";

        javax.servlet.http.Cookie[] diskCookies = request.getCookies();

        if (diskCookies != null) {

            for (int i = 0; i < diskCookies.length; i++) {

                if(diskCookies[i].getName().equals(cookieName)){

                    cookieValue = diskCookies[i].getValue();

                    //如果找到了相应的cookie则效验其有效性

                    result = SSOService(cookieValue);

                    if (debug) log("found cookies!");

                }

            }

        }

        if (result.equals("failed")) { //效验失败或没有找到cookie,则需要登录

            response.sendRedirect(SSOLoginPage+"?goto="+url);

        } else if (qstring.indexOf("logout") > 1) {//logout服务

            if (debug) log("logout action!");

            logoutService(cookieValue);

            response.sendRedirect(SSOLoginPage+"?goto="+url);

        }  else {//效验成功

            request.setAttribute("SSOUser",result);

            Throwable problem = null;

            try {

                chain.doFilter(req, res);

            } catch(Throwable t) {

                problem = t;

                t.printStackTrace();

            }       

            if (problem != null) {

                if (problem instanceof ServletException) throw (ServletException)problem;

                if (problem instanceof IOException) throw (IOException)problem;

                sendProcessingError(problem, res);

            }

        }   

    } 

 

  doFilter()方法的逻辑也是非常简单的,在接收到请求的时候,先去查找是否存在期望的cookie值,如果找到了,就会调用SSOService(cookieValue)去效验这个cookie的有效性。如果cookie效验不成功或者cookie根本不存在,就会直接转到登录界面让用户登录;如果cookie效验成功,就不会做任何阻拦,让此请求进行下去。在配置文件中,有下面的一个节点表示了此filter的URL映射关系:只拦截所有的jsp请求。

 

<filter-mapping>

 

<filter-name>SSOFilter</filter-name>

<url-pattern>*.jsp</url-pattern>

</filter-mapping>

 

  下面还有几个主要的函数需要说明:

 

 

private String SSOService(String cookievalue) throws IOException {

 

        String authAction = "?action=authcookie&cookiename=";

        HttpClient httpclient = new HttpClient();

        GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);

        try {  

            httpclient.executeMethod(httpget);

            String result = httpget.getResponseBodyAsString();

            return result;

        } finally {

            httpget.releaseConnection();

        }

    }

    

    private void logoutService(String cookievalue) throws IOException {

        String authAction = "?action=logout&cookiename=";

        HttpClient httpclient = new HttpClient();

        GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);

        try {

            httpclient.executeMethod(httpget);

            httpget.getResponseBodyAsString();

        } finally {

            httpget.releaseConnection();

        }

    } 

 

  这两个函数主要是利用apache中的httpclient访问SSOAuth提供的认证服务来完成效验cookie和logout的功能。

  其他的函数都很简单,有很多都是我的IDE(NetBeans)替我自动生成的。

  4 当前方案的安全局限性

  当前这个WEB-SSO的方案是一个比较简单的雏形,主要是用来演示SSO的概念和说明SSO技术的实现方式。有很多方面还需要完善,其中安全性是非常重要的一个方面。

  我们说过,采用SSO技术的主要目的之一就是加强安全性,降低安全风险。因为采用了SSO,在网络上传递密码的次数减少,风险降低是显然的,但是当前的方案却有其他的安全风险。由于cookie是一个用户登录的唯一凭据,对cookie的保护措施是系统安全的重要环节:

  cookie的长度和复杂度

  在本方案中,cookie是有一个固定的字符串(我的姓名)加上当前的时间戳。这样的cookie很容易被伪造和猜测。怀有恶意的用户如果猜测到合法的cookie就可以被当作已经登录的用户,任意访问权限范围内的资源

  cookie的效验和保护

  在本方案中,虽然密码只要传输一次就够了,可cookie在网络中是经常传来传去。一些网络探测工具(如sniff, snoop,tcpdump等)可以很容易捕获到cookie的数值。在本方案中,并没有考虑cookie在传输时候的保护。另外对cookie的效验也过于简单,并不去检查发送cookie的来源究竟是不是cookie最初的拥有者,也就是说无法区分正常的用户和仿造cookie的用户。

  当其中一个应用的安全性不好,其他所有的应用都会受到安全威胁

因为有SSO,所以当某个处于 SSO的应用被黒客攻破,那么很容易攻破其他处于同一个SSO保护的应用。

  这些安全漏洞在商业的SSO解决方案中都会有所考虑,提供相关的安全措施和保护手段,例如Sun公司的Access Manager,cookie的复杂读和对cookie的保护都做得非常好。另外在OpneSSO (https://opensso.dev.java.net)的架构指南中也给出了部分安全措施的解决方案。

  5 当前方案的功能和性能局限性

  除了安全性,当前方案在功能和性能上都需要很多的改进:

  当前所提供的登录认证模式只有一种:用户名和密码,而且为了简单,将用户名和密码放在内存当中。事实上,用户身份信息的来源应该是多种多样的,可以是来自数据库中,LDAP中,甚至于来自操作系统自身的用户列表。还有很多其他的认证模式都是商务应用不可缺少的,因此SSO的解决方案应该包括各种认证的模式,包括数字证书,Radius, SafeWord ,MemberShip,SecurID等多种方式。最为灵活的方式应该允许可插入的JAAS框架来扩展身份认证的接口

  我们编写的Filter只能用于J2EE的应用,而对于大量非Java的Web应用,却无法提供SSO服务。

  在将Filter应用到Web应用的时候,需要对容器上的每一个应用都要做相应的修改,重新部署。而更加流行的做法是Agent机制:为每一个应用服务器安装一个agent,就可以将SSO功能应用到这个应用服务器中的所有应用。

  当前的方案不能支持分别位于不同domain的Web应用进行SSO。这是因为浏览器在访问Web服务器的时候,仅仅会带上和当前web服务器具有相同domain名称的那些cookie。要提供跨域的SSO的解决方案有很多其他的方法,在这里就不多说了。Sun的Access Manager就具有跨域的SSO的功能。

  另外,Filter的性能问题也是需要重视的方面。因为Filter会截获每一个符合URL映射规则的请求,获得cookie,验证其有效性。这一系列任务是比较消耗资源的,特别是验证cookie有效性是一个远程的http的调用,来访问SSOAuth的认证服务,有一定的延时。因此在性能上需要做进一步的提高。例如在本样例中,如果将URL映射从“.jsp”改成“/*”,也就是说filter对所有的请求都起作用,整个应用会变得非常慢。这是因为,页面当中包含了各种静态元素如gif图片,css样式文件,和其他html静态页面,这些页面的访问都要通过filter去验证。而事实上,这些静态元素没有什么安全上的需求,应该在filter中进行判断,不去效验这些请求,性能会好很多。另外,如果在filter中加上一定的cache,而不需要每一个cookie效验请求都去远端的身份认证服务中执行,性能也能大幅度提高。

  另外系统还需要很多其他的服务,如在内存中定时删除无用的cookie映射等等,都是一个严肃的解决方案需要考虑的问题。

分享到:
评论

相关推荐

    SSO 单点登录解决方案 设计流程图

    SSO 单点登录解决方案 设计流程图 SSO(Single Sign-On)单点登录解决方案是当前企业应用系统中最常用的身份验证机制之一。该解决方案的设计流程图将会详细介绍 SSO 的实现机制、时序图、数据库设计、程序实现和...

    SSO单点登录解决方案.doc

    SSO(Single Sign-On)单点登录是一种身份验证机制,允许...总的来说,SSO单点登录解决方案是现代企业IT环境中必不可少的组件,它提升了用户便利性,降低了管理成本,加强了安全性,并适应了SOA环境下的服务安全需求。

    SSO单点登陆解决方案

    SSO单点登录解决方案 SSO(Single Sign-On)单点登录解决方案旨在提供一个统一的身份验证入口,满足集团多个成员网站的身份验证需求。该方案的主要目标是实现单点登录,提高用户体验,降低成员网站的登录负载,并...

    CAS jasig SSO单点登录解决方案完整版

    cas-client-core-3.2.1.jar LoginImpl.java LoginServlet.java SSOClientFilter.java web.xml 电子政务平台单点登录集成手册v4.0-2017年2月9日.docx

    cas 单点登录 解决方案.

    cas 单点登录解决方案 cas 单点登录解决方案是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。随着企业的发展,业务系统的数量...

    统一认证单点登录系统SSO解决方案.doc

    单点登录(Single Sign-On,简称SSO)是一种网络...综上所述,统一认证单点登录系统SSO解决方案是一种高效、安全、灵活的方法,能够有效应对企业环境中多系统登录的挑战,提升用户满意度,同时便于系统的管理和扩展。

    关于SSO单点登录的简单实现

    SSO(Single Sign-On)单点登录...总之,SSO单点登录为用户提供了便捷的访问体验,同时降低了管理多系统登录的复杂性。通过理解其原理和实现方式,我们可以根据具体需求选择合适的技术方案,构建高效且安全的SSO系统。

    SSO单点登录实现方案

    单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 本示例简单的实现了SSO认证系统,...

    sso单点登录源代码

    在“sso单点登录源代码”中,我们可以看到以下几个关键组成部分: 1. **SSOLab.sln**:这是一个Visual Studio解决方案文件,包含了整个SSO项目的所有组件。通过这个文件,开发者可以打开并管理整个项目,包括各个子...

    单点登录SSO解决方案之SpringSecurity+JWT实现.docx

    ### 单点登录SSO解决方案之SpringSecurity+JWT实现 #### 一、单点登录(SSO)概述 单点登录(Single Sign-On,简称SSO)是一种认证机制,允许用户仅通过一次登录就能访问同一域下的多个应用程序和服务。这种机制...

Global site tag (gtag.js) - Google Analytics