应该在用户名框中输入什么才能对以下代码执行 SQLInjection 攻击,我应该如何降低这种风险?

What should be entered into the username box to execute a SQLInjection attack on the following code and how should I mitigate that risk?

提问人:BHughes 提问时间:4/6/2023 更新时间:4/10/2023 访问量:76

问:

我知道我需要对哈希进行加盐,我只是好奇如何对此执行SQLInjection攻击,我想降低风险

if (username && password) {
    db.get(`SELECT * FROM users WHERE username = ? AND password = ?`, [username, hashString], (err, row) => {
      if (err) {
        console.error(err);
      } else {
        if (row) {
          console.log('Login sucessful');
          console.log('username input: ' + username + ' password input: ' + password + ' hash of password: ' + hashString);
          console.log(row);
          response.redirect('/index.html');
        } else {
          console.log('username input: ' + username + ' password input: ' + password + ' hash of password: ' + hashString);
          console.log(row);
          console.log('Invalid username or password');
          
          response.redirect('/login.html');
          response.end();
        }
      }
    });
  } else {
    response.send('Please enter a username and password!');
    response.end();
  }
});

我尝试在用户名和密码槽中添加一些sql命令。密码框中没有任何反应,因为它在插入 sql 命令之前正在进行哈希处理

JavaScript 节点.js sqlite sql注入

评论

2赞 Barmar 4/6/2023
由于 SQL 使用参数,因此除非连接器库中存在 bug,否则不应执行 SQL 注入。

答:

0赞 Y. Gherbi 4/6/2023 #1

该代码似乎使用了参数化查询,这有助于防止 SQL 注入攻击。但是,代码中的一个潜在风险是该参数未在提供的代码片段中定义,因此不清楚该参数是如何生成的。如果它以不安全的方式生成,则攻击者可能会操纵它来执行 SQL 注入攻击。hashString

可以通过输入用户名和密码组合来尝试 SQL 注入攻击,该组合将 SQL 代码作为输入的一部分。例如,攻击者可以输入以下输入作为密码:

password' OR 1=1 --

此输入将导致 SQL 查询按如下方式计算:

SELECT * FROM users WHERE username = 'username' AND password = 'password' OR 1=1 --'

输入末尾的双破折号是 SQL 中的注释标记,这会导致忽略查询的其余部分。OR 1=1 条件始终为 true,这意味着查询将返回 users 表中的所有行,从而允许攻击者在没有有效密码的情况下登录。

迁移此风险

为了降低这种风险,建议确保在使用 SQL 查询中使用的任何输入参数之前都经过适当的清理和验证。此外,建议将参数化查询与预准备语句一起使用,以防止 SQL 注入攻击。

根据关于的评论进行更新hashString

使用 SHA-512 对密码进行哈希处理不会直接增加 SQL 注入攻击的风险。

但是,与专用密码哈希算法(如 、 或 )相比,使用 SHA-512 进行密码哈希的安全性较低。它没有提供足够的保护来抵御暴力攻击,并且没有为每个用户提供唯一的盐,因此容易受到预先计算的哈希密码表(如彩虹表)的攻击。bcryptscryptArgon2

它与您的原始问题无关,但需要注意,因此这里有一个简单的示例。如果它对你很重要,我建议你弄清楚如何在你的代码库中实现它。

const bcrypt = require('bcrypt'); const saltRounds = 10;此值决定了哈希算法的“成本”。值越高,意味着需要更多的计算能力来散列和验证密码,这通常更安全。您可以根据需要调整此值。

npm install bcrypt
# or
yarn add bcrypt
// Hash a password (saltRounds is kind of the "cost" or "work factor")
bcrypt.hash(password, saltRounds, (err, hash) => {
  if (err) {
    console.error(err);
  } else {
    // Save the hashed password to the database
  }
});

// Verify a password
bcrypt.compare(password, hash, (err, result) => {
  if (err) {
    console.error(err);
  } else {
    // If 'result' is true, the password is correct.
  }
});

评论

0赞 BHughes 4/6/2023
hashString 是使用“var hashString = CryptoJS.SHA512(password).toString()”制作的
0赞 Y. Gherbi 4/6/2023
我调整了答案,以帮助您解决与密码散列方式相关的其他一些风险。如果它回答了您的问题,请选择 is 作为正确答案
0赞 morpheuslord 4/10/2023 #2

概念

这个概念很简单,这一切都归结为核心 SQL 查询。 这些是要记住的事情:

  • '--' 表示注释。
  • '是必不可少的,这取决于你把它放在哪里。

现在回答这个问题:

    SELECT * FROM users WHERE username =? AND password =?

以上是 SQL 查询,问号是输入的端点。 而且没有进行消毒。 因此,对于要操作的服务器,我们必须注释掉检查功能,并且查询必须返回 true。

'-- :在用户名部分注入时的意志

这将是结果:

    SELECT * FROM users WHERE username =''-- AND password =?

结果就像密码部分将被注释,检查将被忽略。

让我们稍微改变一下,并将有效负载设置为:'1=1--

现在,这将是最后一个查询:SELECT * FROM users WHERE username =''1=1 -- AND password =?

现在 1=1 是 True,这是通用的,所以 '' 将不返回任何内容,1=1 将返回 True,密码部分被忽略,登录成功被绕过。

预防

对于预防,有两种方法可以很好地协同工作,它们是:

  • 消毒
  • WAF系列

在正常应用程序上完成时,使用 WAF 是不合适的,但使用清理是有效的。一旦检测到此类攻击,WAF 就会通过阻止此类攻击来运行,但清理严格禁止某些输入。

Python 中的基本清理代码:

    import re
    
    def s_u(username):
        # Remove any characters that are not letters, numbers, or underscores
        sanitized_username = re.sub(r'[^\w]', '', username)
        # Remove any leading or trailing spaces
        sanitized_username = sanitized_username.strip()
        return sanitized_username
    
    
    def s_p(password):
        # Remove any characters that are not letters, numbers, or underscores
        sanitized_username = re.sub(r'[^\w]', '', username)
        # Remove any leading or trailing spaces
        sanitized_password = password.strip()
        return sanitized_password

上面的代码会阻止诸如 etc 之类的字符,因为这些是注入此类攻击的一些最常用的代码。根据您的使用情况,您可以操纵它以使用额外的字符或不使用额外的字符,但清理得越多越好。',-[]