尝试在使用JPA动态引用Oracle包时阻止SQL注入
我走了一段路,遇到了一堵墙,想知道如何才能做到这一点 基本上,查询是使用JPA构造的,并传递给Oracle数据库。数据库上有一个包,用于生成引用,该包根据环境动态命名。此值可由用户编辑,并作为DB属性存储在应用程序中。我无法控制这个系统的架构 在JPA之前的阶段,使用包的引用值生成一个查询字符串,该值被设置为属性(同样,我不能改变它的设计方式)。我使用尝试在使用JPA动态引用Oracle包时阻止SQL注入,oracle,jpa,Oracle,Jpa,我走了一段路,遇到了一堵墙,想知道如何才能做到这一点 基本上,查询是使用JPA构造的,并传递给Oracle数据库。数据库上有一个包,用于生成引用,该包根据环境动态命名。此值可由用户编辑,并作为DB属性存储在应用程序中。我无法控制这个系统的架构 在JPA之前的阶段,使用包的引用值生成一个查询字符串,该值被设置为属性(同样,我不能改变它的设计方式)。我使用Query方法setParameter()设置了此项,如下所示: (伪代码替换聚焦上下文的不相关部分) 我这样做基本上是一种反射,只是意识到(在r
Query
方法setParameter()
设置了此项,如下所示:
(伪代码替换聚焦上下文的不相关部分)
我这样做基本上是一种反射,只是意识到(在retrospec中,很明显)这实际上不起作用,因为它正在逃逸不应该逃逸的元素
因此,当引用f=“DynamicallyNamedPackage.DoThisDynamicallyNamedThing”
时,上面的代码只会返回“DynamicallyNamedPackage.DoThisDynamicallyNamedThing”
,因为这显然是为了使其安全,这样做的目的在某种程度上是我尝试做的前提
有没有可能在不创建一整段额外代码的情况下实现这一点?作为替代方案,我目前所能想到的是查询匹配的所有包对象的dba_过程
,并使用该查询的结果来构造queryString
(因此使用任何用户可编辑的值进行绕行),但感觉它将是复杂的。这是替代方案,我正在使用它来代替改进:
final String verifyReference = "SELECT object_name FROM "
+ "dba_procedures WHERE object_type = 'PACKAGE' AND object_name =?1";
final Query refQuery = getEntityManager().createNativeQuery( verifyReference );
refQuery.setParameter( 1, referenceRef );
final String result = refQuery.getSingleResult();
final String queryString = "SELECT " + result + " FROM sys.dual";
final Query myQuery = getEntityManager().createNativeQuery( queryString );
return myQuery.getSingleResult();
它将根据现有包的列表查找用户可编辑属性引用,然后使用该查询的结果构建原始引用。它涉及更多的空检查等,并确实消除了漏洞,但感觉有点“未经修饰”
(正如评论中已经提到的,这种类型的数据库设计为需要SQL注入,但需要防止“SQL注入”作为不允许使用非预期值在设计之外操纵DB的定义。)Oracle dictionary视图包含当前用户可访问的所有过程的列表 特别是在视图中,有列
所有者、对象名称(=包名称)、过程名称
您可以使用此视图通过简单地添加EXISTS
子查询来清理配置的输入,例如:
select
?
from dual where exists (
select null from all_procedures
where
OWNER||'.'||OBJECT_NAME||'.'||PROCEDURE_NAME = upper(?) and
object_type = 'PACKAGE');
必须绑定两次相同的输入参数
如果没有具有给定名称的过程,查询将返回无数据
,因此您可能会引发异常
上面的查询需要一个完全限定的存储过程名称,即
owner.package.procedure
,如果允许使用非限定名称(没有owner
),则必须稍微调整它。您不想在这里阻止SQL注入。你想做SQL注入,不是吗?如果选择了这种设计,我想用户可以从dual中选择并存储要选择的对象的名称,并且用户或值已经过验证。所以就这样吧。我想答案是肯定的,这是基于SQL注入的概念,但“SQL注入”的概念并不是指未经授权/无意地劫持允许注入SQL(而不是引用对象)的查询。设计是一个问题,但不是我能控制的问题。谢谢-嵌套的EXISTS
语句对单个SELECT过程名有好处吗,其中PRODECURE\u NAME=?
,除了style?@ChrisJ之外,视图all\u过程
可以为一个过程包含多行(每过载一个)。使用EXISTS
返回最大一行。使用SELECT DISTINCT
也可以实现同样的效果。啊,好吧-我的描述可能过于简洁,但这可能会扩展为针对包内的特定函数,此时应该只有一行返回?一般情况下,打包的procedure可能有多个重载(即相同的过程名称,但不同的参数),因此您可以为单个所有者.PACKAGE\u name.procedure\u name
获取更多行。这很有意义-我使用了一个修订版本,但查询非常有用;谢谢!
select
?
from dual where exists (
select null from all_procedures
where
OWNER||'.'||OBJECT_NAME||'.'||PROCEDURE_NAME = upper(?) and
object_type = 'PACKAGE');