Giter VIP home page Giter VIP logo

sql_firewall's Introduction

sql_firewall

Note: This is a fork of poreklo/sql_firewall, but has been updated to work with PostgreSQL 10+.

Overview

sql_firewall is a PostgreSQL extension which is intended to protect database from SQL injections or unexpected queries.

sql_firewall module learns queries which can be executed, and prevents/warns on executing queries which are not found in the learned firewall rule.

How it works

sql_firewall can take one of four modes specified in sql_firewall.firewall parameter: "learning", "enforcing", "permissive" and "disabled".

In the "learning" mode, sql_firewall collects pairs of "userid" and "queryid" associated with the executed queries. "queryid" is calculated based on a parse tree, similar to pg_stat_statements.

In the "enforcing" mode, sql_firewall checks whether queries are in the list of collected pairs of "userid" and "queryid", the firewall rules. When a query not in the firewall rules comes in, sql_firewall produces an error with the message to prevent execution.

In the "permissive" mode, sql_firewall checks queries as well, but allows to execute even not in the firewall rules. And produces warnings if the queries are not in the rules.

Compatibility

sql_firewall supports PostgreSQL 9.4.x. Other major versions would be supported in the future release.

Exported rule files would not be compatible between different PostgreSQL major versions, because queryid is calculated from the internal data structure (the Query structure) which is different in different major versions.

Installation

sql_firewall can be built as a PostgreSQL extension.

$ sh ./build.sh
$ sh ./build.sh install

Then, restart the PostgreSQL service.

Configuration

 $ vi $PGDATA/postgresql.conf
 <add>
 shared_preload_libraries = 'sql_firewall'
 sql_firewall.firewall = 'learning'
 </add>
 $ pg_ctl -D $PGDATA restart
 $ psql mydb
 mydb=# create extension sql_firewall;

sql_firewall would check all queries incoming to not only the specific database where the module is installed, but all the databases in the entire PostgreSQL cluster.

Even though, the views and functions in the module would be available only on the installed database.

GUC Parameters

  • shared_preload_libraries

    sql_firewall module needs to be loaded in the shared_preload_libraries parameter as following:

    shared_preload_libraries = 'sql_firewall'

    Note for developers

    pg_stat_statements built with `--enable-cassert' causes assert when queryId already has non-zero value.

    So, to use both pg_stat_statements and sql_firewall at the same time, pg_stat_statements needs to be loaded prior to sql_firewall in the shared_preload_libraries parameter as following.

    shared_preload_libraries = 'pg_stat_statements,sql_firewall'

    Then, sql_firewall can skip queryId calculation if queryId is already set by pg_stat_statements, and avoid the assert.

  • sql_firewall.firewall

    sql_firewall.firewall is able to take one of the following values: 'disabled', 'learning', 'permissive' and 'enforcing'. The default value is 'disabled'.

  • sql_firewall.max

    Number of queries the SQL Firewall can learn. It can take an int value between 100 and INT_MAX. The default value is 5000. The queries which exceed this value in the "learning" mode would never be learned.

Functions

  • sql_firewall_reset()

    sql_firewall_reset() clears the firewall rules.

    This function is available only under the disabled mode with superuser privilege.

  • sql_firewall_stat_reset()

    sql_firewall_reset() clears the counters of warning and error. Only available with superuser privilege.

  • sql_firewall_export_rule('/path/to/rule.txt')

    sql_firewall_export_rule() writes the firewall rules in the specified CSV file.

    This function is available only under the disabled mode with superuser privilege.

  • sql_firewall_import_rule('/path/to/rule.txt')

    sql_firewall_import_rule() reads the firewall rules from the specified CSV file.

    This function is available only under the disabled mode with superuser privilege.

Views

  • sql_firewall.sql_firewall_statements

    sql_firewall_statements view shows the firewall rules and execution counter for each query.

    postgres=# select * from sql_firewall.sql_firewall_statements; userid | queryid | query | calls --------+------------+---------------------------------+------- 10 | 3294787656 | select * from k1 where uid = ?; | 4 (1 row)

    postgres=#

  • sql_firewall.sql_firewall_stat

    sql_firewall_stat view has two counters: "sql_warning" and "sql_error".

    "sql_warning" shows number of executed queries with warnings in the "permissive" mode.

    "sql_error" shows number of prevented queries in the "enforcing" mode.

    postgres=# select * from sql_firewall.sql_firewall_stat; sql_warning | sql_error -------------+----------- 2 | 1 (1 row)

    postgres=#

Examples

  • Permissive mode

    postgres=# select * from sql_firewall.sql_firewall_statements; WARNING: Prohibited SQL statement userid | queryid | query | calls --------+------------+---------------------------------+------- 10 | 3294787656 | select * from k1 where uid = 1; | 1 (1 row)

    postgres=# select * from k1 where uid = 1; uid | uname -----+------------- 1 | Park Gyu-ri (1 row)

    postgres=# select * from k1 where uid = 3; uid | uname -----+----------- 3 | Goo Ha-ra (1 row)

    postgres=# select * from k1 where uid = 3 or 1 = 1; WARNING: Prohibited SQL statement uid | uname -----+---------------- 1 | Park Gyu-ri 2 | Nicole Jung 3 | Goo Ha-ra 4 | Han Seung-yeon 5 | Kang Ji-young (5 rows)

    postgres=#

  • Enforcing mode

    postgres=# select * from k1 where uid = 3; uid | uname -----+----------- 3 | Goo Ha-ra (1 row)

    postgres=# select * from k1 where uid = 3 or 1 = 1; ERROR: Prohibited SQL statement postgres=#

Authors

Satoshi Nagayasu [email protected]

sql_firewall's People

Contributors

poreklo avatar rodo avatar snaga avatar turgs avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

sql_firewall's Issues

Compilation errors in Postgres 10

On DigitalOcean, I have an Ubuntu 16.04 droplet, where Postgres is installed via apt-get.

This extension compiled and installed correctly on Postgres 9.6, however it's now failing with Postgres 10. Everything else is the same. I'm installing the same way, on Ubuntu 16.04. From a quick googling myself, it sounds like some API changes may have occurred in Postgres 10.

Compiling the extension via ‘sudo sh ./build.sh’ shows these errors:

sql_firewall.c: In function ‘_PG_init’:
sql_firewall.c:420:19: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
  ExecutorRun_hook = pgss_ExecutorRun;
                   ^
sql_firewall.c:426:22: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
  ProcessUtility_hook = pgss_ProcessUtility;
                      ^
sql_firewall.c: In function ‘pgss_ExecutorRun’:
sql_firewall.c:979:4: error: too few arguments to function ‘prev_ExecutorRun’
    prev_ExecutorRun(queryDesc, direction, count);
    ^
sql_firewall.c:981:4: error: too few arguments to function ‘standard_ExecutorRun’
    standard_ExecutorRun(queryDesc, direction, count);
    ^
In file included from /usr/include/postgresql/10/server/funcapi.h:22:0,
                 from sql_firewall.c:76:
/usr/include/postgresql/10/server/executor/executor.h:172:13: note: declared here
 extern void standard_ExecutorRun(QueryDesc *queryDesc,
             ^
sql_firewall.c: In function ‘pgss_ProcessUtility’:
sql_firewall.c:1086:25: warning: passing argument 1 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
     prev_ProcessUtility(parsetree, queryString,
                         ^
sql_firewall.c:1086:25: note: expected ‘PlannedStmt * {aka struct PlannedStmt *}’ but argument is of type ‘Node * {aka struct Node *}’
sql_firewall.c:1088:10: warning: passing argument 5 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
          dest, completionTag);
          ^
sql_firewall.c:1088:10: note: expected ‘QueryEnvironment * {aka struct QueryEnvironment *}’ but argument is of type ‘DestReceiver * {aka struct _DestReceiver *}’
sql_firewall.c:1088:16: warning: passing argument 6 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
          dest, completionTag);
                ^
sql_firewall.c:1088:16: note: expected ‘DestReceiver * {aka struct _DestReceiver *}’ but argument is of type ‘char *’
sql_firewall.c:1086:5: error: too few arguments to function ‘prev_ProcessUtility’
     prev_ProcessUtility(parsetree, queryString,
     ^
sql_firewall.c:1090:29: warning: passing argument 1 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
     standard_ProcessUtility(parsetree, queryString,
                             ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘PlannedStmt * {aka struct PlannedStmt *}’ but argument is of type ‘Node * {aka struct Node *}’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1092:11: warning: passing argument 5 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
           dest, completionTag);
           ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘QueryEnvironment * {aka struct QueryEnvironment *}’ but argument is of type ‘DestReceiver * {aka struct _DestReceiver *}’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1092:17: warning: passing argument 6 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
           dest, completionTag);
                 ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘DestReceiver * {aka struct _DestReceiver *}’ but argument is of type ‘char *’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1090:5: error: too few arguments to function ‘standard_ProcessUtility’
     standard_ProcessUtility(parsetree, queryString,
     ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: declared here
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1157:24: warning: passing argument 1 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
    prev_ProcessUtility(parsetree, queryString,
                        ^
sql_firewall.c:1157:24: note: expected ‘PlannedStmt * {aka struct PlannedStmt *}’ but argument is of type ‘Node * {aka struct Node *}’
sql_firewall.c:1159:9: warning: passing argument 5 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
         dest, completionTag);
         ^
sql_firewall.c:1159:9: note: expected ‘QueryEnvironment * {aka struct QueryEnvironment *}’ but argument is of type ‘DestReceiver * {aka struct _DestReceiver *}’
sql_firewall.c:1159:15: warning: passing argument 6 of ‘prev_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
         dest, completionTag);
               ^
sql_firewall.c:1159:15: note: expected ‘DestReceiver * {aka struct _DestReceiver *}’ but argument is of type ‘char *’
sql_firewall.c:1157:4: error: too few arguments to function ‘prev_ProcessUtility’
    prev_ProcessUtility(parsetree, queryString,
    ^
sql_firewall.c:1161:28: warning: passing argument 1 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
    standard_ProcessUtility(parsetree, queryString,
                            ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘PlannedStmt * {aka struct PlannedStmt *}’ but argument is of type ‘Node * {aka struct Node *}’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1163:10: warning: passing argument 5 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
          dest, completionTag);
          ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘QueryEnvironment * {aka struct QueryEnvironment *}’ but argument is of type ‘DestReceiver * {aka struct _DestReceiver *}’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1163:16: warning: passing argument 6 of ‘standard_ProcessUtility’ from incompatible pointer type [-Wincompatible-pointer-types]
          dest, completionTag);
                ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: expected ‘DestReceiver * {aka struct _DestReceiver *}’ but argument is of type ‘char *’
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
sql_firewall.c:1161:4: error: too few arguments to function ‘standard_ProcessUtility’
    standard_ProcessUtility(parsetree, queryString,
    ^
In file included from sql_firewall.c:86:0:
/usr/include/postgresql/10/server/tcop/utility.h:38:13: note: declared here
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
             ^
<builtin>: recipe for target 'sql_firewall.o' failed
make: *** [sql_firewall.o] Error 1

After enabling enforcing mode, SQL statement with SQL function is prohibited

After running learning mode, a SQL statement which include SQL function was captured in sql_firewall_statements. When enforcing mode is turned on for the postgresql server, running the same statement encounter Prohibited SQL statement error "CONTEXT: SQL function xxx during startup" .

The SQL function is something like this
"select description from pg_catalog.pg_description where objoid = $1 and classoid = 'pg_catalog.pgclass'::pg_catalog.regclass and objsubid = $2"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.