【问题标题】:How to Pass Input Value into Cypher Query?如何将输入值传递给 Cypher 查询?
【发布时间】:2021-02-05 19:16:24
【问题描述】:

我正在运行 nodejs 并从 ejs 页面,我试图将输入值发送到 Cypher 查询中,这将导致图形的 vis.js 显示。 注意:所有的 javascript 动作都发生在 ejs 页面上,在这种情况下没有服务器联系。

运行查询时,我可以毫无问题地渲染 Neo4j 图表而无需尝试添加输入值。

这有效点击此按钮...

    <input type="submit" onclick="displayGraph()" value='Display Graph' class="button">

...运行此函数,其中包含 Cypher 查询(此查询中没有输入)并按预期呈现 Neo4j 图。

    function displayGraph() {
        // Create the authorization header for the ajax request.
        AUTHORIZATION = "Basic " + btoa("abc"+":"+"123");

        // Post Cypher query to return node and relations and return results as graph.
        restPost({
            "statements": [
                {
                    "statement": `MATCH (bry:Brewery)-[r:BREWS]->(b:Beer {name: 'Pliny the Elder'})-[r2:IS_A]->(bt:BeerType)
                                    Optional Match (b)-[r3:BREWED_WITH]->(h:Hop) 
                                    Return bry,r,b,r2,bt,r3,h`,
                    "resultDataContents": ["graph"]
                }
            ]
        }).done(function (data) {
            
            // Parse results and convert it to vis.js compatible data.
            var graphData = parseGraphResultData(data);
            var nodes = convertNodes(graphData.nodes);
            var edges = convertEdges(graphData.edges);
            var visData = {
                nodes: nodes,
                edges: edges
            };
            displayVisJsData(visData);
        });
    }

这不起作用如果我使用输入字段来捕获啤酒的名称...

<label>
    Beer Name:<input name="inputbeer" id="inputbeer" type="text">
</label>

...然后单击相同的按钮...

<input type="submit" onclick="displayGraph()" value='Display Graph' class="button">

...我运行了类似的函数,但是尝试了多种将输入值传递给 Cypher 查询的变体(一切都与上面看到的函数相同,只是修改了 Cypher 查询)...

MATCH (bry:Brewery)-[r:BREWS]->(b:Beer {name: '$inputbeer'})-[r2:IS_A]->(bt:BeerType)
                                    Optional Match (b)-[r3:BREWED_WITH]->(h:Hop) 
                                    Return bry,r,b,r2,bt,r3,h

...这个和其他变体不起作用。我试过 {name: {inputbeer}}... {name: {$inputbeer}}... {name: $inputbeer}... 有很多可能性。 我猜这是一个简单的格式问题,但我不知所措。

感谢您的帮助!

【问题讨论】:

  • 您应该真的对您的数据库进行某种形式的抽象或信息隐藏。我的意思是,直接公开你的数据库有什么意义呢?如果您的用户具有适当的访问权限并且可以使用官方工具,您会更好。在我看来,这是个坏主意。

标签: javascript forms neo4j cypher ejs


【解决方案1】:

您正在尝试使用Javascript template literals。您正在寻找的语法是

const injectedString = 'containing a variable';
const templateString = `This is a string ${injectedString}`;
console.log(templateString);
//logs "This is a string containing a variable";

但是,

不要那样做

这会使您容易受到注入攻击,例如inputthebeer 的输入值 'aBeerName'}) DETACH DELETE bry // 将删除多个节点

使用参数

如果您使用的是 REST API

使用params传递参数,让Neo4j安全地逃逸并注入到查询中。

{
  "query" : "MATCH (bry:Brewery)-[r:BREWS]->(b:Beer {name: {inputthebeer}})-[r2:IS_A]->(bt:BeerType) Return bry,r,b,r2,bt,r3,h",
  "params" : {
    "inputthebeer" : "aBeerName",
  }
}

尚不清楚您的restPost() 是如何工作的,但请参阅REST API documentation 以获取示例。 重要的部分是您的查询字符串应该包含{name: {inputthebeer}},并且您应该添加inputthebeer 作为参数。

使用 Javascript 驱动程序

更好的解决方案可能是使用Neo4j Javascript Driver

npm安装它

npm install neo4j-driver

或者,如果您不使用 npm 或捆绑您的源代码,请将其包含在您的 HTML 中

<script src="https://unpkg.com/neo4j-driver@X.Y.Z/lib/browser/neo4j-web.min.js"></script>

您需要初始化驱动程序并打开一个会话,然后

session
  .run(
    'MATCH (bry:Brewery)-[r:BREWS]->(b:Beer {name: $inputthebeer})-[r2:IS_A]->bt:BeerType) Return bry,r,b,r2,bt,r3,h',
    {
      inputthebeer: 'aBeerName'
    }
  )

在此示例中要注意的重要一点是,这 不是 Javascript 模板文字。 $inputthebeer 的值在字符串中,驱动正在传递参数,Neo4j 安全地转义变量(防止注入攻击)

警告

看起来 Neo4j REST API 可能会公开 - 如果是这种情况,上面的注入攻击可能没有实际意义,因为攻击者可以通过直接向 REST API 发送请求来直接执行任何查询

【讨论】:

    【解决方案2】:

    经过更多试验,我能够将输入值传递给我的 Cypher 查询。

    需要进行 2 处修改:

    1. 我需要在我的函数中添加一个 var 来捕获输入的值:
    var inputthebeer = document.getElementById("inputbeer").value;
    
    1. 我必须更新我的 Cypher 查询以允许我插入该 var:
    `
    MATCH (bry:Brewery)-[r:BREWS]->(b:Beer {name: '`+inputthebeer+`'})-[r2:IS_A]->(bt:BeerType) 
    Optional Match (b)-[r3:BREWED_WITH]->(h:Hop) 
    Return bry,r,b,r2,bt,r3,h
    `
    

    【讨论】:

    • 这会让您面临注入攻击。
    • 感谢@Codebling,我已将输入从字段输入更改为下拉选择...&lt;select class="form-control" type="text" name="inputbeer" id="inputbeer"&gt; &lt;% beer.forEach(function(beer){ %&gt; &lt;option&gt;&lt;%= beer.name %&gt;&lt;/option&gt; &lt;% }) %&gt; &lt;/select&gt; ...但请理解您在上面分享的答案是最好的方法它。因此,我将把我的文章留在这里,作为对其他人的“警示故事”。
    • 我对此进行了更多思考——我意识到,如果 REST 端点向世界公开,任何人都可以在您的 Neo4j 服务器上执行任意 Cypher。记在心上!不过,很高兴您找到了一些可行的解决方案!
    猜你喜欢
    • 2015-05-10
    • 2022-12-02
    • 2019-01-04
    • 2017-08-16
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    相关资源
    最近更新 更多