如果没有查询生成器或 ORM,如何避免 SQL 注入漏洞?

How do you avoid an SQL injection vulnerability without a query builder or an ORM?

假设我有一个如下所示的函数(忽略此处的任何语法错误,除非它们与问题相关,我是 SQL 的新手):

// This function updates the database using the command passed as a parameter
const execute = async (command) => {
    open({
        filename: "test.db",
        driver: sqlite3.Database,
    }).then((db) => {
        db.exec(command);
    });
};

// Takes the user ID and their input and adds it to the database
const createBlogPost = async (userId, text) => {
    await execute(`INSERT INTO posts (user_id, post) VALUES ("${userId}", "${text}");`)
}

没有什么可以阻止用户将他们自己的 SQL 注入博客 post 文本字段。只要语法正确,他们就不能执行他们想要的任何命令吗?我想知道您是否应该做一些额外的事情来防止这种情况发生,或者最好的做法是只使用 ORM 而不是构建自己的 SQL 语句。

非常感谢。

使用parameters防止SQL注入。

function openDb() {
    return open({
        filename: "test.db",
        driver: sqlite3.cached.Database,
    });
};

const createBlogPost = (userId, text) => {
    return openDb().then(db => db.run("INSERT INTO posts (user_id, post) VALUES (?, ?);", [userId, text]));
};

备注:

  • 除了 return await ... 什么都不做的 async function 是 anti-pattern。在这种情况下删除 async/await,函数将完全相同。

  • 运行 直接在数据库对象上查询非常容易;尝试将其抽象为一个单独的 execute() 函数实际上是在让您的生活变得更加艰难。那是因为数据库对象比 运行ning 查询提供了更多的东西,并且在长 运行 中您将需要更多的包装函数,这是不必要的复杂性。我创建了openDb(),直接returns一个数据库对象就够了

  • 我为此使用了 open() with caching,以防止不必要地向同一数据库发送多个连接。这样可以多次调用OpenDb,现有连接为re-used.

  • 对于 inserting/updating rows,您应该使用 .run() 而不是 .exec()

  • 通常:Return API 来自您自己函数的承诺。在这里,open() 给你一个承诺,openDb() returns 它,createBlogPost() 接受它,然后 returns 它给调用者。这样 createBlogPost() 可以在调用代码中被 await 编辑,并且错误处理也能正常工作:

    async function test_createBlogPost() {
        try {
            const result = await createBlogPost(1, 'Hello World');
            console.log(result);
        } catch (err) {
            console.log("createBlogPost failed", err);
        }
    }