我正在golang中编写一个半外部的Web服务,它允许用户查询有关其帐户的信息,这些信息分布在多个内部遗留服务中.

我的服务将用户输入字符串传递到多个后端RESTful API,后者根据字符串执行MySQL查找以生成结果,这些结果将传递回我的服务以提供给用户.

从历史上看,这些传统的后端服务还没有暴露给用户输入,所以我不确定他们是否有针对SQL注入的适当防护.

通常我会阻止使用Prepared Statements的SQL注入来防止数据库引擎将用户字符串视为可解析,但在这种情况下我不控制数据库调用 – 它们是远在下游的,所有审计它们都是不切实际的.马上.

我可以在golang代码中做些什么来尽可能地清理用户输入,以最大限度地降低SQL注入的风险?这最终是一个权宜之计,直到所有下游数据库调用都可以进行注入安全审核.

编辑:用户输入可以用于所有实际目的是一个任意字符串,但它不应该是可执行代码.我的服务需要用户的字段值,而不是代码.

最佳答案:

在过去的工作中,我为我们的服务维护了一个允许临时查询的工具.它允许管理员在不必等待数周的代码部署的情况下请求报告(在部署需要数周的古怪时期).

我们不支持临时报表查询,方法是让服务接受任意字符串作为输入,并将它们作为SQL执行.这是非常不安全的,因为我相信你知道.

它的工作方式是报告查询存储在数据库中,以及所需的查询参数数量.

CREATE TABLE ManagerQueries (
id INT PRIMARY KEY,
query TEXT NOT NULL,
description TEXT NOT NULL,
num_params TINYINT UNSIGNED NOT NULL DEFAULT 0
);
INSERT INTO ManagerQueries
SET query = 'SELECT COUNT(*) FROM logins WHERE user_id = {0} AND created_at > {1}',
description = 'Count a given user logins since a date',
num_params = 2;

管理器前端可以通过其主键请求查询,而不是通过在Web请求中指定任意SQL字符串.

只有DBA以及可能知道如何编写安全查询的其他开发人员或经理才允许向此存储库添加新查询,因此可以确保查询经过测试和审查.

通过UI请求报表查询时,它强制用户提供查询参数的值.在我们的例子中,它从数据库中读取SQL,执行prepare()然后绑定execute()的值.所以SQL注入防御很满意.

在您的情况下,您的代码可能无法直接访问旧服务的数据库,因此您无法执行准备/执行并使用绑定参数.您必须提交具有集成值的静态查询.

在其他语言中,您可以通过转义使任何字符串值安全插入到SQL查询中.请参阅MySQL C API函数mysql_real_escape_string().

数字值更容易.你不必逃避任何事情,你只需要确保数值是真正的数字.将动态值转换为数字后,可以安全地插入到任何SQL字符串中.

不幸的是,我不认为golang SQL包支持任何转义函数.这已被要求作为一项功能,但据我所知,目前还没有支持的实现.见这里的讨论:https://github.com/golang/go/issues/18478

请注意,它比使用正则表达式替换有点棘手,因为您需要考虑多字节字符集.