我可以让 Ecto 记录原始 SQL 吗?
Can I get Ecto to log raw SQL?
我正在构建这样的 Ecto 查询:
from item in query,
where: like(item.description, ^"%#{text}%")
我担心这允许 SQL 在 text
中注入。在尝试解决这个问题之前,我想看看查询实际上是如何发送到数据库的。
如果我 或查看记录的内容,我会看到一些 SQL,但它无效。
例如,检查查询显示如下:
{"SELECT i0.\"id\", i0.\"store_id\", i0.\"title\", i0.\"description\"
FROM \"items\" AS i0 WHERE (i0.\"description\" LIKE )",
["%foo%"]}
当我将此查询传递给 Repo.all
时,它记录如下:
SELECT i0."id", i0."store_id", i0."title", i0."description"
FROM "items" AS i0 WHERE (i0."description" LIKE ) ["%foo%"]
但是如果我将其复制并粘贴到 psql
,PostgreSQL 会给我一个错误:
ERROR: 42P02: there is no parameter
似乎 Ecto 实际上可能在做 parameterized query,像这样:
PREPARE bydesc(text) AS SELECT i0."id",
i0."store_id", i0."title", i0."description"
FROM "items" AS i0 WHERE (i0."description" LIKE );
EXECUTE bydesc('foo');
如果是这样,我认为这将阻止 SQL 注入。但我只是猜测这就是 Ecto 所做的。
如何查看 Ecto 正在执行的实际 SQL?
Ecto 仅使用准备好的语句。使用 ecto 查询语法时,无法引入 SQL 注入。查询语法在编译时验证没有 SQL 注入是可能的。
由于以下几个原因,准确显示执行的查询可能很困难:
- Postgrex(以及 Ecto)使用 postgresql 二进制协议(而不是最常见但效率较低的文本协议),因此
PREPARE
查询实际上从未作为字符串存在。
- 在大多数情况下,您只会看到一个首字母
PREPARE 64237612638712636123(...) AS ...
,然后是很多 EXECUTE 64237612638712636123(...)
,这没什么用。试图将一个与另一个联系起来会很可怕。
根据我对大多数此类软件的经验,使用准备语句并记录它们而不是原始查询,因为它更有助于理解系统的行为。
是的,这正是 Ecto 正在执行的 SQL(它在内部通过 db_connection 包使用准备好的查询)并且在该代码中不可能有 SQL 注入.这可以通过在 postgresql.conf
:
中将 log_statement
更改为 all
来打开所有已执行的 SQL 查询的日志记录来验证
...
log_statement = 'all'
...
然后重新启动 PostgreSQL 和 运行 查询。对于以下查询:
Repo.get(Post, 1)
Repo.get(Post, 2)
已记录:
LOG: execute ecto_818: SELECT p0."id", p0."title", p0."user_id", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."id" = )
DETAIL: parameters: = '1'
LOG: execute ecto_818: SELECT p0."id", p0."title", p0."user_id", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."id" = )
DETAIL: parameters: = '2'
我正在构建这样的 Ecto 查询:
from item in query,
where: like(item.description, ^"%#{text}%")
我担心这允许 SQL 在 text
中注入。在尝试解决这个问题之前,我想看看查询实际上是如何发送到数据库的。
如果我
例如,检查查询显示如下:
{"SELECT i0.\"id\", i0.\"store_id\", i0.\"title\", i0.\"description\"
FROM \"items\" AS i0 WHERE (i0.\"description\" LIKE )",
["%foo%"]}
当我将此查询传递给 Repo.all
时,它记录如下:
SELECT i0."id", i0."store_id", i0."title", i0."description"
FROM "items" AS i0 WHERE (i0."description" LIKE ) ["%foo%"]
但是如果我将其复制并粘贴到 psql
,PostgreSQL 会给我一个错误:
ERROR: 42P02: there is no parameter
似乎 Ecto 实际上可能在做 parameterized query,像这样:
PREPARE bydesc(text) AS SELECT i0."id",
i0."store_id", i0."title", i0."description"
FROM "items" AS i0 WHERE (i0."description" LIKE );
EXECUTE bydesc('foo');
如果是这样,我认为这将阻止 SQL 注入。但我只是猜测这就是 Ecto 所做的。
如何查看 Ecto 正在执行的实际 SQL?
Ecto 仅使用准备好的语句。使用 ecto 查询语法时,无法引入 SQL 注入。查询语法在编译时验证没有 SQL 注入是可能的。
由于以下几个原因,准确显示执行的查询可能很困难:
- Postgrex(以及 Ecto)使用 postgresql 二进制协议(而不是最常见但效率较低的文本协议),因此
PREPARE
查询实际上从未作为字符串存在。 - 在大多数情况下,您只会看到一个首字母
PREPARE 64237612638712636123(...) AS ...
,然后是很多EXECUTE 64237612638712636123(...)
,这没什么用。试图将一个与另一个联系起来会很可怕。
根据我对大多数此类软件的经验,使用准备语句并记录它们而不是原始查询,因为它更有助于理解系统的行为。
是的,这正是 Ecto 正在执行的 SQL(它在内部通过 db_connection 包使用准备好的查询)并且在该代码中不可能有 SQL 注入.这可以通过在 postgresql.conf
:
log_statement
更改为 all
来打开所有已执行的 SQL 查询的日志记录来验证
...
log_statement = 'all'
...
然后重新启动 PostgreSQL 和 运行 查询。对于以下查询:
Repo.get(Post, 1)
Repo.get(Post, 2)
已记录:
LOG: execute ecto_818: SELECT p0."id", p0."title", p0."user_id", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."id" = )
DETAIL: parameters: = '1'
LOG: execute ecto_818: SELECT p0."id", p0."title", p0."user_id", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."id" = )
DETAIL: parameters: = '2'