【问题标题】:How to minimize risk of SQL injection in downstream services in a golang service?golang服务中如何最小化下游服务中SQL注入的风险?
【发布时间】:2019-07-13 09:50:46
【问题描述】:

我正在用 golang 编写一个半面向外部的 Web 服务,让用户可以查询有关其帐户的信息,这些信息分布在多个内部遗留服务中。

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

从历史上看,这些遗留后端服务并未暴露给用户输入,因此我不确定它们是否有适当的防范措施来防止 SQL 注入。

通常我会使用Prepared Statements 阻止 SQL 注入,以防止数据库引擎将用户字符串视为可解析的,但在这种情况下,我不控制数据库调用——它们位于下游,而且不是现在可以对它们进行实际审核。

我可以在我的 golang 代码中做些什么来尽可能地清理用户输入,从而将 SQL 注入漏掉的风险降到最低?这最终是一种权宜之计,直到可以审计所有下游数据库调用的注入安全性。

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

【问题讨论】:

  • 如果遗留服务会愉快地执行任意输入字符串作为SQL,它们不适合接受用户输入,句号。

标签: mysql go sql-injection


【解决方案1】:

在过去的工作中,我为我们的服务维护了一个允许临时查询的设施。它允许管理人员请求报告,而无需等待数周的代码部署(在部署需要数周时间的古怪日子)。

我们不通过让服务接受任意字符串作为输入并将它们作为 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

因此您可能必须实现自己的转义功能。例如,您可以在官方 MySQL C 实现之后对其进行建模:https://github.com/mysql/mysql-server/blob/8.0/mysys/charset.cc#L716

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

【讨论】:

    【解决方案2】:

    添加到比尔的回答中,涵盖数据输入。为了确保输出数据的卫生,比如网络服务,请查看html/template

    包模板 (html/template) 实现了数据驱动的模板 生成对代码注入安全的 HTML 输出。

    【讨论】:

      猜你喜欢
      • 2019-08-16
      • 2014-12-19
      • 2017-04-22
      • 1970-01-01
      • 2017-08-08
      • 2016-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多