0

我正在 'ALTER USER hr IDENTIFIED BY secret'使用 oracledb nodejs 包运行这个简单的查询。不知道为什么我收到非法变量名错误。如果可以,我可以做这样的事情,"ALTER USER :user IDENTIFIED BY :password";那么对我来说正确的语法是什么

function get(req, res, next) {
    oracledb.getConnection(
        config.database,
        function(err, connection){
            if (err) {
                return next(err);
            }

            connection.execute(
                'ALTER USER :user IDENTIFIED BY :password'+

            {
                user: req.body.user
            },
            {
                password: req.body.password
            },

                {
                    outFormat: oracledb.OBJECT
                }


          });
        }

谢谢您的帮助

4

2 回答 2

2

这里有几个问题:

  1. SQL 字符串中缺少空格,因此它的各个部分一起运行。

  2. 无论如何,语法只是ALTER USER hr IDENTIFIED BY secret,正如您在介绍中所说的那样;我认为该WHERE条款不会产生任何影响。

  3. 不能将绑定变量用于ALTER语句中的用户名等内容。相反,您必须通过连接字符串来构造命令,并仔细检查组件是否格式正确且不能用于 SQL 注入攻击

像这样的东西应该可以工作(但我还没有测试过):

function get(req, res, next) {
    oracledb.getConnection(
        config.database,
        function(err, connection) {
            if (err) {
                return next(err);
            }

            user = req.body.user.toLowerCase();
            password = req.body.password.toLowerCase();

            // TODO make sure user and password are safe from SQL injections here
            // in particular, that they don't contain single quotation characters (')
            // or spaces

            connection.execute(
                'ALTER USER ' + user + ' IDENTIFIED BY ' + password
            );
        }
    )
}
于 2017-09-01T21:08:36.920 回答
2

正如 Matthew 所指出的,您必须使用字符串连接并防止 SQL 注入。

在某种程度上,我质疑这样做的必要性。我知道您已经知道这篇文章: https ://jsao.io/2015/06/authentication-with-node-js-jwts-and-oracle-database/

因为该解决方案使用表来存储用户凭据,而不是依赖于数据库用户,所以可以安全地绑定这些值,而不必担心 SQL 注入。为什么不使用这种方法呢?

使用具有动态 SQL 的数据库用户要求密码中不允许使用单引号 (')。坦率地说,我讨厌这些限制。应该存在密码规则以提高安全性(必须包含的内容),而不是确保代码可以安全执行(不允许的内容)。这不会是自定义表的问题。

但是,只要你有一个,这里有一个基于 Promise 的示例解决方案,它展示了如何使用 dbms_assert 来清理传入的值:

const oracledb = require('oracledb');
const config = require('./dbConfig.js');

function get(req, res, next) {
  let conn;
  const user = req.body.user;
  const password = req.body.password; // Do not change case

  oracledb.getConnection(config)
    .then((c) => {
      conn = c;

      return conn.execute(
       `declare

          -- Use dbms_assert to sanitize values coming in to avoid SQL injection.
          l_user      varchar2(30) := dbms_assert.simple_sql_name(:user);
          l_password  varchar2(30) := dbms_assert.enquote_literal(:password);
          l_statement varchar2(100);

        begin

          -- Replace single quotes added by enquote_literal to left and right sides with double quotes
          l_password := '"' || substr(substr(l_password, 2, length(l_password)), 1, length(l_password) - 2) || '"';

          l_statement := 'alter user ' || l_user || ' identified by ' || l_password;

          execute immediate l_statement;

        end;`,
        {
          user: user,
          password: password
        }
      );
    })
    .then(result => {
      console.log('Password changed');

      // write to res
    })
    .catch(err => {
      console.log('Error changing password', err);

      next(err);
    })
    .then(() => {
      if (conn) { // conn assignment worked, need to close
        return conn.close();
      }
    })
    .catch(err => {
      console.log('Error during close', err);
    });
}

// Simulate run of 'get' function
get(
  {
    body: {
      user: 'movie_budget',
      password: 'N0rm@l-P@sswOrd!' // This value will throw an error: '\'\; drop table users;'
    }
  }, 
  {},
  function() {}
);

最后,将数据库逻辑与控制器逻辑结合起来可能会导致代码难以维护。看看这段录音,了解一些更好地组织事情的技巧:https ://www.youtube.com/watch?v=hQgw2WmyuFM

于 2017-09-05T17:29:05.463 回答