使用客户端凭据从 Tomcat 连接到 SQL Server
Posted
技术标签:
【中文标题】使用客户端凭据从 Tomcat 连接到 SQL Server【英文标题】:Connecting to SQL Server from Tomcat using client credentials 【发布时间】:2015-03-10 09:21:08 【问题描述】:我正在开发一个 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);
【问题讨论】:
【参考方案1】:这不是最佳做法。在 Web 应用程序中,数据库连接不应依赖于 Web 应用程序用户的登录。使用应用程序用户登录作为数据库登录会导致多个问题:
如果您的 Web 应用程序有 10000 个用户,您必须在数据库中创建所有这 10000 个用户。如果您的 Web 应用程序具有用户创建功能,则应用程序应使用数据库管理员凭据运行,以便能够将用户添加到数据库。使用数据库管理员凭据运行 Web 应用程序存在重大安全风险。 在大多数商业数据库中,为每个 Web 应用程序用户创建一个数据库用户会增加您的数据库许可成本,因为它们按用户许可向您收费(除了计算许可成本时可能有的其他标准)。李> 您无法配置连接池,因为池配置是不依赖于当前登录的 Web 应用程序用户的预配置。没有连接池会显着降低您的 Web 应用程序性能。总结是 - 使用应用程序用户凭据连接到数据库是个坏主意。
还有其他审计数据库访问的方法。大多数数据库允许您为此目的在数据库连接上设置某种会话信息。您可以在审计日志代码中访问它以记录哪个应用程序用户对数据库执行了哪些操作。例如:
在 postgresql 中,您可以使用 GUC 变量来识别对数据库进行操作的 Web 应用程序用户。在审核日志中记录该变量,以了解哪个 Web 应用程序用户对数据库执行了哪些操作。 在 Oracle 中,您可以使用所谓的客户端标识符。谷歌了解更多信息。其他数据库应该有类似的东西。请谷歌。
【讨论】:
不错的答案。 +1 连接池 这是在企业环境中,活动目录用于所有用户管理(包括对 SQL Server 的数据库访问和计算机登录)。这意味着无需在数据库中为此应用程序创建用户。我同意连接池的问题,这是一个问题。但除此之外,我看不到如何在不使用 Web 应用程序用户登录的情况下实现单点登录解决方案。 为什么需要使用单点登录来连接数据库?您可以尝试消除尽可能多的不利因素,并说服自己剩下的不利因素并不是什么大问题。但是这样做有什么好处呢? 活动目录用于用户管理,既可用于windows登录,也可用于UN*X登录和各种认证/授权设置。对于这个特定的项目,选择 SQL Server 作为数据库使用有几个原因,其中之一是它可以使用 Windows 身份验证来登录和访问数据库中的权限,这使得用户管理更容易和统一。使用单点登录可以让用户轻松(无需额外登录),并且用户管理统一且集中。 单点登录 (SSO) 和应用程序的数据库身份验证凭据是非常不同的东西。我不明白你为什么要把它们绑在一起。请记住 - DBA 管理数据库用户,系统管理员管理系统用户。捆绑它们将如何简化用户管理?在用户很少的环境中,它可能看起来很简单。随着用户数量的增长,这将是一场噩梦。您应该认真考虑改变方法。【参考方案2】:阅读 cmets 后,@Rico 似乎对这种方法很固执(这可能会在未来招致很多痛苦)。相信你知道你在做什么这是一种方式(也可以有其他方式)你如何“可以”做到这一点。如果您在阅读整个故事后仍想这样做,请随时继续执行:
您应该使用 AD 凭据进行 Web 应用程序身份验证。到目前为止,我的印象是,您正在使用 AD 凭据进行 Web 应用程序身份验证。您必须缓存这些凭据以供以后进行数据库身份验证。以下几点将告诉您如何做到这一点。 如果您使用 Web 身份验证框架进行身份验证,请确定身份验证框架或 Web 应用程序框架是否允许您在身份验证机制中添加挂钩以获取 AD 凭据并将其缓存以验证数据库连接。例如 - 一个好的身份验证框架应该具有允许您访问凭据的前后身份验证挂钩/回调/侦听器。如果这不可能,您可以使用 Web 过滤器拦截身份验证请求以缓存已发布的凭据。找出最适合您的方法。 如果您无法连接到身份验证框架或无法使用任何其他方式拦截身份验证请求,您将不得不更改身份验证机制并自行进行身份验证。如果您自己进行身份验证,则可以直接获取凭据并且可以缓存它。但请记住 - 身份验证不是一项非常微不足道的活动。当您编写自己的身份验证代码时,请注意它的所有安全隐患。 在成功的身份验证后缓存服务器端会话中的凭据 (javax.servlet.http.HttpSession
),以便每个请求都可以访问它。这有安全隐患。这种缓存的凭据可能会因错误或攻击者的设计而泄露给攻击者/黑客。
从问题看来,您建立数据库连接的地方可以访问HttpServletRequest
。在请求对象上调用HttpServletRequest.getSession
方法以获取会话并从中检索凭据。使用检索到的凭据建立数据库连接。
您的应用程序似乎没有使用连接池。这是非常低效的,因为建立一个新的数据库连接是一个非常昂贵的过程。这种新方法对该部门没有任何影响。它将继续像您在问题中提到的代码一样低效。
从问题看来,您的应用程序中不存在以下情况。如果它们中的任何一个存在,这就是你必须做的:
如果您的应用程序使用连接池来提高效率:您将不得不丢弃连接池,因为当您从池中请求连接时,预配置的池连接无法更改凭据。每次需要连接时,您都必须使用缓存在HttpSession
中的凭据建立新连接。这将是非常低效的,但这是你讨价还价的。
如果您的应用程序使用 ORM(对象关系映射)工具:通常 ORM 使用预先配置的连接池来提高效率。弄清楚你是否可以为每个 HTTP 请求注入一个新的连接到 ORM 中。如果 ORM 不允许那也扔掉 ORM。准备好自己处理所有数据库交互。
呃..你还觉得值得吗?
【讨论】:
正如您在我的代码示例中看到的那样,我直接从请求中获取凭据(使用 SPNEGO 和委托凭据),因此我不需要将凭据存储在会话中,至少不是为了这个特定的目的。与 SQL 服务器的连接(使用显示的连接字符串)将使用这些凭据来验证(和授权)使用 AD 访问数据库的用户。注意到您关于连接池的观点并且是有效的观点,但是在这个应用程序中,我认为它是可管理的(用户很少,数据库访问不是很频繁)。以上是关于使用客户端凭据从 Tomcat 连接到 SQL Server的主要内容,如果未能解决你的问题,请参考以下文章
使用 AutoIT 连接到远程 SQL Server 时出现问题
使用 JDBC 将自己制作的 Windows 凭据传递给 SQL Server