2016-12-07 3 views
2

나는이 같은 체외 쿼리를 건물입니다 :Ecto에서 원시 SQL을 기록 할 수 있습니까?

from item in query, 
where: like(item.description, ^"%#{text}%") 

내가이 text에서 SQL 주입을 허용하는 걱정. 이 문제를 해결하기 전에 실제로 쿼리가 데이터베이스로 어떻게 보내지는지보고 싶습니다.

내가 inspect the query이거나 기록 된 것을 보면 일부 SQL이 표시되지만 유효하지 않습니다. 내가 Repo.all이 쿼리를 전달하면

{"SELECT i0.\"id\", i0.\"store_id\", i0.\"title\", i0.\"description\" 
    FROM \"items\" AS i0 WHERE (i0.\"description\" LIKE $1)", 
["%foo%"]} 

, 그것은이 기록합니다 : 예를 들어

가 쿼리를 검사하는 것은이 나에게 보여 내가 복사 psql 붙여 넣 경우

SELECT i0."id", i0."store_id", i0."title", i0."description" 
    FROM "items" AS i0 WHERE (i0."description" LIKE $1) ["%foo%"] 

을하지만, PostgreSQL은 다음과 같은 오류 메시지를 표시합니다 :

ERROR: 42P02: there is no parameter $1

ough 체외 사실이처럼 parameterized query을 수행 할 수있다 : 그렇다면

PREPARE bydesc(text) AS SELECT i0."id", 
    i0."store_id", i0."title", i0."description" 
    FROM "items" AS i0 WHERE (i0."description" LIKE $1); 
EXECUTE bydesc('foo'); 

, 나는 그 SQL 주입을 방지 할 생각한다. 하지만 저는 이것이 Ecto가하는 일이라고 추측합니다.

Ecto가 실행중인 실제 SQL을 어떻게 볼 수 있습니까?

답변

7

Ecto는 준비된 문만 사용합니다. ecto 쿼리 구문을 사용하는 경우 SQL 주입을 도입 할 수 없습니다. 쿼리 구문은 SQL 주입이 불가능하다는 것을 컴파일 타임에 확인합니다. 실행 쿼리 때문에 몇 가지 이유 어려울 수 있습니다 정확히 표시

:

  • Postgrex (따라서 체외은) 그래서, PostgreSQL의 바이너리 프로토콜을 (대신 가장 일반적인하지만, 덜 효율적, 텍스트 프로토콜)을 사용 PREPARE 쿼리는 실제로 문자열로 존재하지 않습니다.
  • 대부분의 경우 처음 나타나는 것은 PREPARE 64237612638712636123(...) AS ...이고 나중에는 EXECUTE 64237612638712636123(...)인데 이는별로 도움이되지 않습니다. 하나와 다른 것을 연관 짓는 것은 끔찍한 일입니다. 그런 종류의 내 경험으로 대부분의 소프트웨어에서

은 제표를 작성하고 훨씬 더 도움이 시스템의 동작을 이해하는 이후, 원시 쿼리 대신 그 로그 사용합니다.

+1

"쿼리 구문은 어떤 SQL 주입이 가능하지 컴파일시에 확인합니다." Ecto가'like (item.description,^"% # {text} %")'를 컴파일하면'text'에 이스케이프가 추가되는 것을 말하고 있습니까? PostgreSQL은 미리 준비된 문장을 사용하고 있기 때문에 안전합니다. 그래서 PostgreSQL은 미리 (예를 들어) 하나의 SELECT와 DROP TABLE 뒤에 SELECT를 실행하지 않을 것입니다. –

+1

이스케이프 처리를하지 않고 매개 변수를 사용합니다. '% foo %'는 쿼리의 일부가 아니므로 결코 쿼리에 아무것도 삽입 할 수 없습니다. 이것은 준비된 명령문에 매개 변수로서 완전히 분리되어 전달됩니다. – michalmuskala

+1

또한 - 준비된 명령문에는 하나의 명령문 만 포함될 수 있으므로'-;와 같은 것을 추가 할 수 없습니다. DROP TABLE' - 포스트 그레스 (Postgres)는 두 개의 표현식을 하나에 넣으려고하고 있다고 bork가 말합니다. – michalmuskala

3

예, Ecto에서 실행중인 정확한 SQL입니다 (내부적으로 db_connection 패키지를 통해 준비된 쿼리를 사용함). 해당 코드에서 SQL 삽입이 가능하지 않습니다. PostgreSQL의를 다시 시작하고 쿼리를 실행 한 후

... 
log_statement = 'all' 
... 

과 : 이것은 postgresql.confalllog_statement을 변경하여 실행 된 모든 SQL 쿼리의 로깅을 설정하여 확인할 수 있습니다.이 기록됩니다

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" = $1) 
DETAIL: parameters: $1 = '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" = $1) 
DETAIL: parameters: $1 = '2'