You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket.io执行SQL查询遇SQLITE_RANGE错误,无法获取用户密码

问题:SQLite查询用户密码时出现SQLITE_RANGE: column index out of range错误

问题现象

  • 基于Socket.io开发时,根据用户输入的用户名查询对应密码,触发数据库错误
  • 错误信息:Database {} error looking up if user exists Error: SQLITE_RANGE: column index out of range
  • 可以正常生成哈希密码hashedPassword,但无法通过getPassword语句获取数据库中的密码
  • 即使将socket.username替换为数据库中存在的测试用户名,错误依然发生,排查后锁定问题在数据库查询环节

相关代码

app.js

// we store the username in the socket session for this client
    socket.username = validator.escape(username);
    socket.password = validator.escape(password);
       
    const salt = 'Some salt for the hash';
  
   const hashedPassword = crypto.pbkdf2Sync(socket.password, salt, 1000, 64, 'sha512').toString('hex');

   
    db.serialize(function() {
      
      var checkIfUserExists = "select count(*) from users where username = '" + socket.username +"'";
      var getPassword = `SELECT password FROM users WHERE username = "${socket.username}"`
     console.log(db.get(getPassword))
      db.get(checkIfUserExists, getPassword, function(err, row) {
        if (err) {
          console.error('error looking up if user exists', err);
          return;
        }
        if (row['count(*)'] === 0) {
          // console.log("user doesn't exist!");
          socket.emit('alertuserdoesntexists');
        } 
      
        if (getPassword === hashedPassword) {
          console.log("virker")
          
        
          socket.emit('redirect');
}})

chat.js

var $usernameInput = $('.usernameInput'); // Input for username

      username = $usernameInput.val();
      password = $passwordInput.val();

      // Tell the server your username
      socket.emit('existing user', username, password)
    });

问题分析

  1. db.get()调用错误:你把getPassword这个SQL语句作为第二个参数传给db.get(checkIfUserExists, ...),但db.get()的第二个参数应该是当前查询的参数值数组,不是另一条SQL,这直接导致SQLite解析参数时索引越界,触发SQLITE_RANGE错误。
  2. SQL注入风险:直接将用户名拼接进SQL语句,不仅可能因为特殊字符导致语法错误,还存在严重的SQL注入漏洞。
  3. 密码对比逻辑错误:你试图把SQL语句字符串getPassword和哈希密码hashedPassword对比,这完全是逻辑错误,应该用数据库查询到的密码哈希值和生成的哈希值对比。

修复后的代码(app.js)

// 存储用户名到socket会话
socket.username = validator.escape(username);
socket.password = validator.escape(password);

const salt = 'Some salt for the hash';
const hashedPassword = crypto.pbkdf2Sync(socket.password, salt, 1000, 64, 'sha512').toString('hex');

db.serialize(function() {
  // 参数化查询:用?作为占位符,避免SQL注入
  const checkIfUserExists = "SELECT count(*) as userCount FROM users WHERE username = ?";
  
  // 第一步:检查用户是否存在
  db.get(checkIfUserExists, [socket.username], function(err, row) {
    if (err) {
      console.error('查询用户是否存在时出错', err);
      return;
    }

    if (row.userCount === 0) {
      socket.emit('alertuserdoesntexists');
      return;
    }

    // 第二步:用户存在,查询对应的密码哈希
    const getPassword = "SELECT password FROM users WHERE username = ?";
    db.get(getPassword, [socket.username], function(err, passwordRow) {
      if (err) {
        console.error('查询用户密码时出错', err);
        return;
      }

      // 对比数据库中的哈希值和生成的哈希值
      if (passwordRow.password === hashedPassword) {
        console.log("验证通过");
        socket.emit('redirect');
      } else {
        // 可选:添加密码不匹配的提示
        socket.emit('alertpasswordincorrect');
      }
    });
  });
});

修复说明

  • 修正db.get()调用方式:每个查询单独调用db.get(),参数用数组传递,解决参数索引越界问题
  • 使用参数化查询:用?占位符替代直接字符串拼接,彻底避免SQL注入
  • 修复密码对比逻辑:从数据库获取真实的密码哈希值后,再和生成的hashedPassword对比
  • 拆分查询逻辑:先确认用户存在,再查询密码,代码逻辑更清晰易维护

内容的提问来源于stack exchange,提问作者Wager2000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:25:19