处理Neo4j Injection以获得动态标签和关系

时间:2017-10-07 00:39:58

标签: c# stored-procedures neo4j neo4jclient neo4j-apoc

我一直在使用带有neo4j客户端的WithParams用于c#,但是例如,forParams不适用于标签或关系类型。

我想到的另一种选择是将我想要基于某个标签作为参数形成的字符串连接起来然后构造cypher查询。那就是:

string optionalMatchString = $"p =(n1)-[{relationshipsString}]-(n2)";
graphClient.Cypher.Match("(n1)")
           .Where((Node n1) => n1.Identifier == identifier)
           .OptionalMatch(optionalMatchString)

你可以猜到,relationshipsString是传递给我的参数。如果我使用WithParams,查询将不会替换参数,所以现在我连接字符串,但这很容易受到攻击......(是吗?)

我了解了APOC并看到this issue

这是我看到this的一个例子:

CALL db.labels() yield label
call apoc.cypher.run("MATCH (n:`"+label+"`) RETURN keys(n) as keys LIMIT 1",{}) yield value as row
RETURN label, row.keys as keys

显然,有一个名为cypher.run的APOC程序,我可以将我的标签(或关系)作为变量(来自参数),但从我看到的,它们只是连接一个字符串。 ..那和我一直在做的一样吗?或APOC以某种方式在查询之上执行其他操作? APOC程序对注射是否“安全”?

2 个答案:

答案 0 :(得分:1)

如果您的数据库中有一组预定义的关系,您可以将关系类型列入白名单,即检查它是否是可能的关系类型的成员。

如果由于某种原因这不起作用,您仍然可以将标签作为参数传递,并使用Cypher中的labels方法。但是,这会对性能产生不利影响,因为数据库将查询所有节点并使用过滤操作检查其类型。

我知道这是一个C#问题,但让我分享一些Java代码来重现这个问题:

GraphDatabaseService gds = new TestGraphDatabaseFactory()
    .newImpermanentDatabaseBuilder().newGraphDatabase();
ApocHelper.registerProcedure(gds, Cypher.class);
gds.execute("CREATE (:MyLabel {attr1: 'hello'})");
Result result = gds.execute(
    "CALL apoc.cypher.run(" +
        "'MATCH (n) WHERE $label1 IN labels(n) RETURN keys(n) as keys LIMIT 1', " +
        "{label1: $label2}" +
    ") " +
    "YIELD value AS row " +
    "RETURN row",
    ImmutableMap.of("label2", "MyLabel")
);
System.out.println(result.next());

返回:

{row={keys=[attr1]}}

但同样,这是一个学术解决方案,我真的不能想到一个最好的用例。

(与此问题并行的是,APOC issue也有讨论。)

答案 1 :(得分:1)

修改

存在数据库被擦除的风险(请参阅以下来自@Gabor的评论),但我仍然会沿着Enum的路线走下去解决这个问题。然而,Gabor的答案在那个pov中更好。

APOC正在做同样的事情,因此使用它不会带来任何好处。我认为关键是要考虑您需要的保护级别。

接受你的询问,(我已经猜到了RETURN位)归结为:

MATCH (n) WHERE n.Id = {p0} OPTIONAL MATCH (n)-[:{injectionPoint}]->(n1) RETURN n, n1

让我们看看我们可以从中得到什么,假设攻击者知道以下信息:

  • 您要返回的格式(即您从nn1获得的信息)
  • 您的查询的结构如何,即知道您正在返回名为n1
  • 的节点

他们可以尝试添加另一个查询,即注入类似的内容:

"ORIGINAL]->(n1) RETURN n1; MATCH (n) RETURN labels(n);"

但是这不会有两个原因,一个是您调用的Cypher端点,一次只能接受一个查询,另外两个,MATCH (n) RETURN labels(n)的响应与之不匹配你目前得到的回应,错误也是如此。

你面临的最大风险是,有人能够通过传递不同的关系类型来制定你的模型,直到他们得到答案 - 这可能需要很长时间,所以可能不是这样的问题。

攻击者确实 知道上面的信息,但是如果没有这个,他们就会在黑暗中刺伤。如果他们拥有该信息 - 那么他们可能已经知道他们可以从您的数据库中获得什么。

如果你正在做你正在做的事情并把它放到SQL上下文中,你会要求来自任何表的东西,带有一个ID,然后提供一个表名,看起来对于任何连接的东西。你会在SQL中做到这一点吗?此外 - 没有标签,您正在扫描整个数据库以获取此信息,这将非常慢。

我认为你最好将至少添加到其中一个节点,如果不是两个节点,并使用类似Enum的东西来表示你允许的关系 - 我很欣赏这样做是不切实际的。大数。