ORA-01036: 非法变量 name/number 当 运行 通过 nodejs 查询时
ORA-01036: illegal variable name/number when running query through nodejs
我运行这个简单的查询'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
}
});
}
感谢帮助
这里有几个问题:
SQL 字符串中缺少空格,因此它的各个部分 运行 在一起。
在任何情况下,语法就是 ALTER USER hr IDENTIFIED BY secret
,正如您在介绍中所说;我认为 WHERE
子句不会有任何效果。
你 can't use bind variables 用于 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
);
}
)
}
正如 Matthew 指出的那样,您必须使用字符串连接并防止 SQL 注入。
在某种程度上,我质疑这样做的必要性。我知道您已经意识到这一点 post:
https://jsao.io/2015/06/authentication-with-node-js-jwts-and-oracle-database/
因为该解决方案使用 table 来存储用户凭据,而不是依赖于数据库用户,所以可以安全地绑定值,而不必担心 SQL 注入。为什么不改用这种方法?
使用具有动态 SQL 的数据库用户要求密码中不允许使用单引号 (')。坦率地说,我讨厌这些限制。应该存在密码规则以提高安全性(必须包含的内容),而不是确保代码可以安全执行(不允许的内容)。这不是自定义 table.
的问题
但是,为了让您拥有一个,这里有一个基于 promises 的示例解决方案,展示了如何使用 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
我运行这个简单的查询'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
}
});
}
感谢帮助
这里有几个问题:
SQL 字符串中缺少空格,因此它的各个部分 运行 在一起。
在任何情况下,语法就是
ALTER USER hr IDENTIFIED BY secret
,正如您在介绍中所说;我认为WHERE
子句不会有任何效果。你 can't use bind variables 用于
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
);
}
)
}
正如 Matthew 指出的那样,您必须使用字符串连接并防止 SQL 注入。
在某种程度上,我质疑这样做的必要性。我知道您已经意识到这一点 post: https://jsao.io/2015/06/authentication-with-node-js-jwts-and-oracle-database/
因为该解决方案使用 table 来存储用户凭据,而不是依赖于数据库用户,所以可以安全地绑定值,而不必担心 SQL 注入。为什么不改用这种方法?
使用具有动态 SQL 的数据库用户要求密码中不允许使用单引号 (')。坦率地说,我讨厌这些限制。应该存在密码规则以提高安全性(必须包含的内容),而不是确保代码可以安全执行(不允许的内容)。这不是自定义 table.
的问题但是,为了让您拥有一个,这里有一个基于 promises 的示例解决方案,展示了如何使用 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