使用客户端凭据从Tomcat连接到SQL Server

时间:2015-03-10 09:21:08

标签: java sql-server tomcat jdbc windows-authentication

我正在开发一个Web应用程序,最好使用客户端凭据(Windows用户)连接到SQL Server。

这样做的原因是每个用户都要对数据库访问进行审核,最好是基于AD来避免多次登录,并使管理变得容易。

应用程序在Tomcat 7.0.57上运行并设置了SpnegoHttpFilter,我可以从请求中获取用户名和用户主体。我可以使用Tomcat的Window用户连接到SQL服务器。

但是如何使用客户端用户凭据连接到SQL Server(当然只是用户名不够用)?

是否会从DelegateServiceRequest帮助中获取委派的凭据(目前尚未设置)?我没有找到任何支持在Microsoft JDBC驱动程序中使用GSSCredential(一些搜索表明Progress DataDirect JDBC驱动程序支持使用GSSCredential但我还没有找到有关如何执行此操作的任何文档,我更愿意使用免费解决方案,如果有的话)。

我已经搜索了这个问题的答案,但到目前为止,我还没有找到任何有关如何进行的好线索,有什么想法吗?

注意:这是在公司环境中,这意味着所有用户都通过AD进行管理,包括访问数据库和Windows登录。

注2:以下解决方案似乎有效

连接字符串如下所示:

jdbc:sqlserver://<host>:<port>;databaseName=<bdname>;integratedSecurity=true;authenticationScheme=JavaKerberos;

创建连接时,代码如下所示:

DelegateServletRequest dsr = (DelegateServletRequest)HttpServletRequest();
GSSCredential cred = dsr.getDelegatedCredential();

try
{
    Subject s = GSSUtil.createSubject(cred.getName(), cred);
    return (Connection) Subject.doAs(s,
            new PrivilegedExceptionAction<Object>()
            {
                @Override
                public Object run() throws Exception
                {
                    Connection c = null;
                    c = DriverManager.getConnection(url);
                    return c;
                }
            });
}
catch (PrivilegedActionException e)
{
    throw new DAOException(e);
}
catch (GSSException e)
{
    throw new DAOException(e);
}

2 个答案:

答案 0 :(得分:3)

这不是最佳做法。在Web应用程序数据库中,连接不应取决于Web应用程序用户的登录。使用应用程序用户登录作为数据库登录会导致多个问题:

  • 如果您的Web应用程序有10000个用户,则必须在数据库中创建所有这10000个用户。如果您的Web应用程序具有用户创建功能,则应用程序应使用数据库管理员凭据运行,以便能够将用户添加到数据库。使用数据库管理员凭据运行Web应用程序是一个主要的安全风险。
  • 为每个Web应用程序用户创建数据库用户将在大多数商业数据库中提高您的数据库许可证成本,因为他们向您收取用户许可证(除了他们可能用于计算许可证成本的其他标准)。
  • 您无法配置连接池,因为池配置是预配置,不依赖于当前登录的Web应用程序用户。没有连接池会严重降低Web应用程序的性能。

摘要是 - 使用应用程序用户凭据连接数据库是一个坏主意。

还有其他审核数据库访问的方法。大多数数据库允许您为此目的在数据库连接上设置某种会话信息。您可以在审计日志代码中访问该日志代码,以记录哪个应用程序用户对数据库执行了哪些操作。例如:

  • 在postgresql中,您可以使用GUC变量来标识作用于数据库的Web应用程序用户。在审计日志中记录该变量,以了解哪个Web应用程序用户对数据库执行了哪些操作。
  • 在Oracle中,您可以使用所谓的客户端标识符。谷歌了解更多信息。

其他数据库应该有相同的东西。请谷歌。

答案 1 :(得分:1)

在阅读评论后,看起来@Rico对这种方法很顽固(这可能会在将来引起很多痛苦)。相信你知道你在做什么这是一种方式(也可能有其他方式)你如何&#34;可以&#34;做到这一点。如果您在阅读完整个故事后想要这样做,请随意执行:

  • 您应该使用AD凭据进行Web应用程序身份验证。到目前为止,我的印象是这种情况 - 您使用AD凭据进行Web应用程序身份验证。您必须稍后缓存这些凭据以进行数据库身份验证。以下几点将告诉您如何做到这一点。
  • 如果您使用Web身份验证框架进行身份验证,请确定身份验证框架或Web应用程序框架是否允许您使用挂钩进入身份验证机制以获取AD凭据并将其缓存以验证数据库连接。例如 - 一个好的身份验证框架应该有前后身份验证挂钩/回调/侦听器,允许您访问凭据。如果无法做到这一点,您可以使用Web过滤器拦截身份验证请求以缓存已发布的凭据。找出最适合你的方法。
    • 如果您无法挂钩身份验证框架或无法使用任何其他方法拦截身份验证请求,则必须更改身份验证机制并自行进行身份验证。如果您自己进行身份验证,则可以直接获取凭据,并且可以对其进行缓存。但请记住 - 身份验证不是一项非常简单的活动。在编写自己的身份验证代码时,请注意它的所有安全隐患。
  • 成功验证后,在服务器端会话(javax.servlet.http.HttpSession)中缓存凭据,以便每个请求都可以访问它。这有安全隐患。可以通过错误或设计攻击者向攻击者/黑客透露此缓存凭据。
  • 从问题看,您建立数据库连接的位置可以访问HttpServletRequest。在请求对象上调用HttpServletRequest.getSession方法以获取会话并从中检索凭据。使用检索的凭据建立数据库连接
    • 您的应用程序看起来不使用连接池。这是非常低效的,因为建立新的数据库连接是非常昂贵的过程。这种新方法对该部门没有任何影响。它将继续像您在问题中提到的代码一样低效。

从问题看来,您的应用程序中不存在以下情况。如果它们中任何一个存在,这就是你必须要做的事情:

  • 如果您的应用程序使用连接池提高效率:您必须丢弃连接池,因为预先配置的池连接在您从池请求连接时无法更改凭据。每次需要连接时,都必须使用HttpSession中缓存的凭据建立新连接。这将是非常低效的,但这是你所讨论的。
  • 如果您的应用程序使用ORM(对象关系映射)工具:通常,ORM使用预配置的连接池来提高效率。确定是否可以为每个HTTP请求向ORM注入新连接。如果ORM也不允许抛出ORM。准备好自己处理所有数据库交互。

Duh ..你还觉得值得吗?