防sql注入

388 阅读3分钟

什么是 SQL 注入?为什么我们要防止它?

在开发网站或 App 时,用户常常需要输入一些信息,比如账号、密码、昵称、评论等。如果这些输入没有被好好处理,就可能会被黑客利用,进行一种叫做 SQL 注入(SQL Injection) 的攻击。

SQL 注入是一种常见的网络攻击方式,攻击者通过在输入框中输入一些恶意的 SQL 语句,试图绕过程序的正常逻辑,从而窃取、篡改或删除数据库中的数据

举个例子:

假设你正在开发一个注册页面,用户输入账号和密码,程序会把这些信息保存到数据库里。

正常情况下,用户输入的账号是:zhangsan

但攻击者可能输入这样的账号:

zhangsan'); DROP TABLE users; --

如果你的程序没有做好防护,这段输入就可能被当作 SQL 命令执行,导致整个用户表被删除!

SQL 注入的危害

  1. 数据泄露:黑客可以获取用户的敏感信息,比如密码、手机号。
  2. 数据被篡改:黑客可以修改你的数据库内容,比如把某个用户的余额改成100万。
  3. 数据被删除:黑客可以删除整个数据库,让你的网站瘫痪。
  4. 服务器被控制:极端情况下,黑客甚至可以控制你的服务器。

所以,SQL 注入是非常危险的,我们必须防止它!


如何防止 SQL 注入?

防止 SQL 注入的核心思想是:永远不要相信用户的输入!

下面是几种常用的防护方法:


✅ 方法一:使用参数化查询(推荐)

这是最安全、最常用的方法。

举个例子:

如果这样写 SQL:

let query = "SELECT * FROM users WHERE username = '" + username + "'";

这种写法存在SQL注入风险。如果用户输入的username值是 ' OR '1'='1,最终SQL会变成:

SELECT * FROM users WHERE username = '' OR '1'='1'

这将返回所有用户数据,导致严重的安全漏洞。攻击者可以利用这种方式绕过认证、窃取数据甚至破坏数据库。

参数化查询(以 Node.js + MySQL 为例)

  1. 这里的?是一个占位符,数据库知道这里将有一个参数。
  2. 参数绑定:随后传入的参数值会被严格作为数据处理,不会被解释为SQL代码
let query = "SELECT * FROM users WHERE username = ?";
connection.query(query, [username], function (error, results) {
  // 处理结果
});

这样即使用户输入的是 SQL 语句,也会被当作普通字符串处理,不会被执行。


✅ 方法二:对输入进行转义(防 HTML/JS 注入)

有时候用户输入的内容会被显示在网页上,比如评论、昵称等。如果用户输入了恶意的 HTML 或 JavaScript 代码,可能会导致页面弹窗、跳转等危险行为。

比如用户输入:

<script>alert('你已中奖');</script>

如果你直接显示在网页上,所有看到这条评论的用户都会弹出一个“你已中奖”的窗口,这就是一种叫做 XSS(跨站脚本攻击) 的攻击。

解决方法:对输入内容进行转义

我们可以写一个函数,把 <>&"' 这些特殊字符转义成 HTML 实体:

// 防止 HTML/JS 注入
export function escapeHtml(str) {
  return str.replace(/[<>&"']/g, function (match) {
    return {
      '<': '&lt;',
      '>': '&gt;',
      '&': '&amp;',
      '"': '&quot;',
      "'": '&#039;'
    }[match];
  });
}

image.png

然后在使用用户输入的地方调用它:

username = escapeHtml(username);
password = escapeHtml(password);
nickname = escapeHtml(nickname);

查询数据库,我们发现'<'被转义成了&lt,别的也被进行了不同的处理。这样这个数据就安全啦。 image.png


✅ 方法三:对输入进行校验(白名单过滤)

比如用户输入账号时,你可以规定:

  • 只能使用字母、数字、下划线
  • 长度限制在 6-20 个字符

这样可以提前阻止很多非法输入。


✅ 方法四:使用 ORM 框架(如 Sequelize、TypeORM)

ORM(对象关系映射)框架会自动帮你处理 SQL 注入问题,比如你只需要写:

User.findOne({ where: { username: username } });

底层会自动使用参数化查询,帮你安全地操作数据库。