Azure DocumentDB 参数化存储过程

Azure DocumentDB parameterized stored procedure

正在寻找参数化我的存储过程以避免注入攻击的正确方法。我可以以类似 "prefix" 的方式传递参数,但不确定在不执行 "id=" + id 之类的操作的情况下处理 @id 的正确性是什么,这又避免了注入攻击。

var sproc= 'dbs/{db}/colls/{col}/sprocs/GetDocument';
var  parameters = [
   {
            name: '@id',
            value: 'AndersenFamily'
   }
]

client.executeStoredProcedure(sproc,parameters , function (err, results, responseHeaders) {
            console.log('//////////////////////////////////');
            if (err) {
                console.log('// err');
                console.log(err);
            }
            if (responseHeaders) {
                console.log('// responseHeaders');
                console.log(responseHeaders);
            }
            if (results) {
                console.log('// results');
                console.log(results);
            }
            console.log('//////////////////////////////////');
});

// STORED PROCEDURE
function GetDocument(prefix) {
    var collection = getContext().getCollection();

    // Query documents and take 1st item.
    var isAccepted = collection.queryDocuments(
        collection.getSelfLink(),
        'SELECT * FROM root r WHERE r.id=@id',
        function (err, doc, options) {
            if (err) throw err;

            // Check the feed and if empty, set the body to 'no docs found', 
            // else take 1st element from feed
            if (!doc || !doc.length) getContext().getResponse().setBody('no doc found');
            else getContext().getResponse().setBody(prefix + JSON.stringify(doc[0]));
        });

    if (!isAccepted) throw new Error('The query was not accepted by the server.');
}

你很接近。一些事情:

  • 我认为您混淆了存储过程的参数和查询的参数化。
  • 如果 isAccepted 返回 false,则无需抛出错误或 return 错误字符串。在你得到一个 false 来结束你的存储过程之后有一些缓冲时间。很有可能,它会及时完成,如果它很接近,你可能会幸运地在它超时之前完成 return。如果强制超时,那么 DocuemntDB 无论如何都会 return 一个错误。

所以,你可以这样做:

var sprocLink = 'dbs/{db}/colls/{col}/sprocs/GetDocument';

client.executeStoredProcedure(sprokLink, "AndersenFamily" , function (err, results, responseHeaders) {
  console.log('//////////////////////////////////');
  if (err) {
    console.log('// err');
    console.log(err);
  }
  if (responseHeaders) {
    console.log('// responseHeaders');
    console.log(responseHeaders);
  }
  if (results) {
    console.log('// results');
    console.log(prefix + JSON.stringify(results));
  }
  console.log('//////////////////////////////////');
});

存储过程:

function GetDocument(family) {
  var collection = getContext().getCollection();

  // Query documents and take 1st item.
  var parameters = [{name: '@id',  value: family}];
  var query = 'SELECT * FROM root r WHERE r.id=@id';
  var querySpec = {query: query, parameters: parameters};
  var isAccepted = collection.queryDocuments(
    collection.getSelfLink(),
    querySpec,
    function (err, doc, options) {
      if (err) throw err;
      return getContext().getResponse().setBody(doc[0]);
    });
}

如果我理解你的意图,就没有理由将 prefix 传递到存储过程中。如上所示,当您从存储过程 returning 格式化输出时,您可以更有效地添加它。如果我误解了你的意图并且你确实想将它用于存储过程中的某些东西,你可以使用数组 ["AndersonFamily", "some prefix"] 或作为对象 {name: "AndersonFamily", prefix: "some prefix"} 代替我的 "AndersonFamily"在我上面的示例中显示。

我按原样保留了你的查询,因为它会以这种方式工作,但如果你真正想做的只是通过 id 获取一个文档,那么使用 readDocument() 可能更有效而不是 queryDocuments()。我会运行做个实验看看。如果您切换到该方法,您将需要使用基于 id 的路由,这意味着您需要将数据库和集合名称传递到存储过程中。

在这种情况下,使用如此高选择性的查询并不重要,但强大的存储过程会处理连续标记,甚至会重新启动存储过程执行。

请注意,我实际上 运行 上面的代码。我刚刚进行了文本编辑,所以很可能我的语法有误,但这个答案至少让你在概念上理解了这个问题。