MySQL查询的安全方案 - SQL 注入

121 阅读4分钟

一、背景

现象:直接使用普通的mysql select查询的时候,模糊匹配某些字段的时候,比如单引号',颜文字会出现报错,会出现语法错误的提示。

原因:是因为写了不正确的sql语句更改了查询的性质,这就是常见的 SQL 注入问题。

分析:对于特殊字符怎么能够sql查询正确呢?怎么减少 SQL 注入的风险?

二、方法

如果在 MySQL 中执行 SELECT SQL 查询时遇到导致语法不规范的字符,你可以尝试以下方法进行查询:

1、引号包裹字符串(一般不是这个问题)

如果查询中包含字符串,确保字符串被正确地引号包裹。在 MySQL 中,可以使用单引号或双引号将字符串括起来,例如:SELECT * FROM table WHERE name = 'John'

2、客户端预处理语句(参数化查询 PreparedStatement)

MySQL 客户端预处理语句是什么

在MySQL中,客户端预处理语句是一种在应用程序和MySQL服务器之间进行的通信协议,该协议可以在执行查询之前将查询参数发送到MySQL服务器。

客户端预处理语句通过以下两种方式实现:

  1. 客户端将SQL查询语句发送给MySQL服务器。
  2. MySQL服务器根据查询中的占位符将查询参数发送回客户端。

在执行查询之前,客户端将使用查询参数替换查询中的占位符。

客户端预处理语句的主要优点是可以大大提高应用程序的性能。因为在执行查询之前,查询参数已经预处理,并且MySQL服务器已经准备好接收这些参数。

参数化查询是主要解决 SQL 注入的问题,这种方法通过将变量作为参数传递到 SQL 语句中,而不直接将其值与 SQL 语句连接起来,从而防止 SQL 注入攻击。

在执行查询时,MySQL 驱动会自动处理参数的转义,确保输入的值被正确地转义并安全地插入到查询语句中。

const mysql = require('mysql');

// 创建数据库连接
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'your_username',
  password: 'your_password',
  database: 'your_database'
});

// 执行预处理语句
const sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
const values = ['admin', 'password123'];

connection.query(sql, values, function (error, results, fields) {
  if (error) throw error;
  console.log(results);
});

// 关闭数据库连接
connection.end();

使用场景:如果查询中的数据来自用户输入或其他动态来源,最好使用预处理语句来执行查询。预处理语句可以防止 SQL 注入攻击,并自动处理特殊字符的转义。如果你调用的api只能传递完整的sql,那这个方法就不适用了。

3、转义特殊字符(部分防止 SQL 注入)

在构建 SQL 查询时,对输入的字符串进行转义处理,以确保特殊字符被正确地转义。这可以防止恶意输入破坏 SQL 查询语句的结构。

特殊字符:如单引号(')、双引号(")和反斜杠(\),需要使用反斜杠(\)进行转义。

转义封装方法

  1. \
  2. mysql内置函数
  3. 正则表达式替换

4、输入验证和过滤(限制只能输入某些字符)

在构建 SQL 查询之前,对用户输入进行验证和过滤(前端表单,接口api)。确保只允许预期的字符和格式,并排除可能引起问题的特殊字符。

// 支持中文,英文大小写,数字,-_()()字符
const SQL_REGEXP =/^[\u4e00-\u9fa5a-zA-Z0-9-_()()]+$/

5、检查错误消息

如果查询语法错误,MySQL 数据库通常会返回相应的错误消息,其中可能包含有关错误的更多详细信息。检查错误消息以了解出现问题的具体部分,并进行相应的修正。为了安全性,可以自定义处理异常信息的方法返回,查询错误信息可以不要返回给用户, 将错误记录到日志中。

三、验证

使用上述方法进行开发后,可以使用正则表达式或其他验证方法来验证输入的有效性。