diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43f3cc15f4..3a6bf05636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,6 +111,9 @@ jobs: run: | postgres_enabled=0 if [ ${{ runner.os }} == "Linux" ]; then + sudo apt-get update + sudo apt-get install -y libpcre3 libpcre3-dev + sudo docker run --rm -d -e POSTGRES_PASSWORD=test123 -p 5432:5432 postgres:15.4-alpine3.18 postgres_enabled=1 fi diff --git a/waku/common/databases/db_postgres/dbconn.nim b/waku/common/databases/db_postgres/dbconn.nim index 6ed26d9289..9a53a0d148 100644 --- a/waku/common/databases/db_postgres/dbconn.nim +++ b/waku/common/databases/db_postgres/dbconn.nim @@ -1,5 +1,5 @@ import - std/[times, strutils, asyncnet, os, sequtils, sets], + std/[times, strutils, asyncnet, os, sequtils, sets, strformat], results, chronos, chronos/threadsync, @@ -207,6 +207,32 @@ proc waitQueryToFinish( pqclear(pqResult) +proc containsRiskyPatterns(input: string): bool = + let riskyPatterns = + @[ + " OR ", " AND ", " UNION ", " SELECT ", "INSERT ", "DELETE ", "UPDATE ", "DROP ", + "EXEC ", "--", "/*", "*/", + ] + + for pattern in riskyPatterns: + if pattern.toLowerAscii() in input.toLowerAscii(): + return true + + return false + +proc isSecureString(input: string): bool = + ## Returns `false` if the string contains risky characters or patterns, `true` otherwise. + let riskyChars = {'\'', '\"', ';', '-', '#', '\\', '%', '_', '/', '*', '\0'} + + for ch in input: + if ch in riskyChars: + return false + + if containsRiskyPatterns(input): + return false + + return true + proc dbConnQuery*( dbConnWrapper: DbConnWrapper, query: SqlQuery, @@ -214,6 +240,9 @@ proc dbConnQuery*( rowCallback: DataProc, requestId: string, ): Future[Result[void, string]] {.async, gcsafe.} = + if not requestId.isSecureString(): + return err("the passed request id is not secure: " & requestId) + dbConnWrapper.futBecomeFree = newFuture[void]("dbConnQuery") let cleanedQuery = ($query).replace(" ", "").replace("\n", "") @@ -224,7 +253,8 @@ proc dbConnQuery*( var queryStartTime = getTime().toUnixFloat() - (await dbConnWrapper.sendQuery(query, args)).isOkOr: + let reqIdAndQuery = "/* requestId=" & requestId & " */ " & $query + (await dbConnWrapper.sendQuery(SqlQuery(reqIdAndQuery), args)).isOkOr: error "error in dbConnQuery", error = $error dbConnWrapper.futBecomeFree.fail(newException(ValueError, $error)) return err("error in dbConnQuery calling sendQuery: " & $error)