我已经走了一段路,撞到了一堵墙,上面写着这是怎么可能实现的。
基本上,查询是使用JPA构造的,并传递给Oracle数据库。在数据库上有一个包,用于生成引用,它是基于环境动态命名的。该值是用户可编辑的,并在应用程序中存储为db属性。我对这个体系结构没有任何控制权。
在pre-jpa阶段,使用包的引用值生成一个查询字符串,该值被设置为一个属性(同样,我不能更改这种设计方式)。我用
Query
方法
setParameter()
,像这样:
(伪代码为重点上下文替换无关部分)
String referenceRef = [ reference is fetched from DB properties ];
String queryString = "SELECT ?1 FROM sys.dual";
final Query myQuery = getEntityManager().createNativeQuery( queryString );
myQuery.setParameter( 1, referenceRef );
return myQuery.getSingleResult();
我做这件事几乎是作为一种反射,只是为了认识到(在逆行规范中,很明显)这实际上不会起作用,因为它是在逃避不应该逃避的元素…
所以,在哪里
referenceRef = "DynamicallyNamedPackage.DoThisDynamicallyNamedThing"
,以上代码将返回
"DynamicallyNamedPackage.DoThisDynamicallyNamedThing"
很明显,这是为了确保安全,而这样做的意义在某种程度上是我所要做的事情的前提。
是否可以在不创建整个附加代码块的情况下实现这一点?作为一种选择,我现在能想到的就是
dba_procedures
对于所有匹配的Package对象,并使用该查询的结果构造
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注入”,定义为不允许使用意外的值在设计之外对数据库进行操作。)