diff --git a/.acraconfigs/acra-server/acra-censor.norules.yaml b/.acraconfigs/acra-server/acra-censor.norules.yaml index 9e1e7d9..445ea88 100644 --- a/.acraconfigs/acra-server/acra-censor.norules.yaml +++ b/.acraconfigs/acra-server/acra-censor.norules.yaml @@ -1,2 +1,2 @@ ignore_parse_error: true -version: 0.85.0 \ No newline at end of file +version: 0.95.0 diff --git a/.acraconfigs/acra-server/acra-censor.ruleset01.yaml b/.acraconfigs/acra-server/acra-censor.ruleset01.yaml index 5c76467..d7e5bbb 100644 --- a/.acraconfigs/acra-server/acra-censor.ruleset01.yaml +++ b/.acraconfigs/acra-server/acra-censor.ruleset01.yaml @@ -1,5 +1,5 @@ ignore_parse_error: true -version: 0.85.0 +version: 0.95.0 handlers: - handler: query_ignore queries: diff --git a/.acraconfigs/acra-server/acra-censor.ruleset02.yaml b/.acraconfigs/acra-server/acra-censor.ruleset02.yaml index eb5fc3e..f5553be 100644 --- a/.acraconfigs/acra-server/acra-censor.ruleset02.yaml +++ b/.acraconfigs/acra-server/acra-censor.ruleset02.yaml @@ -1,5 +1,5 @@ ignore_parse_error: true -version: 0.85.0 +version: 0.95.0 handlers: - handler: deny queries: diff --git a/.acraconfigs/acra-server/acra-censor.ruleset03.yaml b/.acraconfigs/acra-server/acra-censor.ruleset03.yaml index b66cb2c..046e8a8 100644 --- a/.acraconfigs/acra-server/acra-censor.ruleset03.yaml +++ b/.acraconfigs/acra-server/acra-censor.ruleset03.yaml @@ -1,4 +1,4 @@ ignore_parse_error: true -version: 0.85.0 +version: 0.95.0 handlers: - handler: denyall diff --git a/.acraconfigs/acra-server/acra-censor.yaml b/.acraconfigs/acra-server/acra-censor.yaml index 9e1e7d9..445ea88 100644 --- a/.acraconfigs/acra-server/acra-censor.yaml +++ b/.acraconfigs/acra-server/acra-censor.yaml @@ -1,2 +1,2 @@ ignore_parse_error: true -version: 0.85.0 \ No newline at end of file +version: 0.95.0 diff --git a/README.md b/README.md index eedd5c3..4b899ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # What is this? -This project illustrates how to use [AcraCensor](https://docs.cossacklabs.com/pages/documentation-acra/#acracensor-acra-s-firewall) as SQL firewall to prevent SQL injections. Target application is a well-known vulnerable web application [OWASP Mutillidae 2](https://github.com/webpwnized/mutillidae). +This project illustrates how to use [AcraCensor](https://docs.cossacklabs.com/pages/documentation-acra/#acracensor-acra-s-firewall) as SQL firewall to prevent SQL injections. Target application is a well-known vulnerable web application [OWASP Mutillidae 2](https://github.com/webpwnized/mutillidae). AcraCensor – is a built-in SQL firewall of [Acra data protection suite](https://cossacklabs.com/acra/). This project is one of numerous Acra's example applications. If you are curious about other Acra features, like transparent encryption, intrusion detection, load balancing support – [Acra Example Applications](https://github.com/cossacklabs/acra-engineering-demo/). @@ -21,21 +21,21 @@ This is a slide from [a talk by Cossack Labs' security software engineer Artem S ## Screencast -Watch the video +Watch the video ## How to run the demo -1. Use docker-compose command to set up and run the whole infrastructure: +1. Use docker-compose command to set up and run the whole infrastructure: ``` -docker-compose -f docker-compose.acra-censor-demo.yml up +docker-compose -f docker-compose.acra-censor-demo.yml up --build ``` -2. Check that the containers are up and running: +2. Check that the containers are up and running: ``` docker ps -a @@ -47,7 +47,7 @@ docker ps -a -4. The database is still empty so we need to fill it first by clicking on `setup/reset the DB`. +4. The database is still empty so we need to fill it first by clicking on `Click here to attempt to setup the database` and then `Opt out of database warnings`. In the Docker console you should see SQL queries in Acra logs. After resetting the database, the main page of Mutillidae application looks like this: @@ -60,16 +60,16 @@ In the Docker console you should see SQL queries in Acra logs. After resetting t -2. Now, let's run an SQL injection. Try to login any name and password `' or 1='1`. +2. Now, let's run an SQL injection. Try to login any name and password `' or 1='1`. -This will construct an SQL query `SELECT * FROM accounts WHERE username='' AND password='' or 1='1'` — containing a typical SQL injection — to the database. +This will construct an SQL query `SELECT * FROM accounts WHERE username='' AND password='' or 1='1'` — containing a typical SQL injection — to the database. ## How AcraCensor prevents SQL injections -1. Now, let's fine-tune AcraCensor for preventing this injection. +1. Now, let's fine-tune AcraCensor for preventing this injection. There are configuration files in `./.acraconfigs/acra-server/` folder: - `acra-censor.norules.yaml` (minimal configuration that simply creates valueless AcraCensor); @@ -83,7 +83,7 @@ Replace the active config with `acra-censor.ruleset01.yaml` (or `acra-censor.rul ```bash cp ./.acraconfigs/acra-server/acra-censor.ruleset01.yaml ./.acraconfigs/acra-server/acra-censor.yaml -docker restart +docker restart acra-censor-demo_acra-server_1 ``` In the docker log, you will see that AcraServer has restarted with an updated configuration file: @@ -96,9 +96,9 @@ acra-censor-demo-master_acra-server_1_979c50cd7b3e exited with code 0 2. Test if the new AcraCensor configuration prevents injections. -On the same web page, try to login again using the password `' or 1='1`. +On the same web page, try to login again using the password `' or 1='1`. -You should see that the response from MySQL server is blocked. In Acra's console, you can see that the malicious query is forbidden: +You should see that the response from MySQL server is blocked. In Acra's console, you can see that the malicious query is forbidden: @@ -122,7 +122,7 @@ and try to use `admin` as a username and `' or 1='1` as a password. 2. Read out blog post [how we built AcraCensor](https://www.cossacklabs.com/blog/how-to-build-sql-firewall-acracensor.html). 3. Watch the slides about the developers' perspective on [building SQL firewall](https://speakerdeck.com/storojs72/building-sql-firewall-insights-from-developers). 4. Check [Mutillidae repository](https://github.com/webpwnized/mutillidae). -5. Check [Mutillidae docker image by @edoz90](https://github.com/edoz90/docker-mutillidae). +5. Check [Mutillidae docker](https://github.com/webpwnized/mutillidae-docker). # Further steps diff --git a/docker-compose.acra-censor-demo.yml b/docker-compose.acra-censor-demo.yml index 82c42d5..f768e5c 100644 --- a/docker-compose.acra-censor-demo.yml +++ b/docker-compose.acra-censor-demo.yml @@ -1,138 +1,77 @@ version: "3" services: - # Create keys: - # - ./.acrakeys/acra-server/${ACRA_CLIENT_ID}_server - # - ./.acrakeys/acra-connector/${ACRA_CLIENT_ID}_server.pub - acra-keymaker_server: - # You can specify docker image tag in the environment - # variable ACRA_DOCKER_IMAGE_TAG or run by default with 'latest' images - image: "cossacklabs/acra-keymaker:${ACRA_DOCKER_IMAGE_TAG:-latest}" - environment: - # INSECURE!!! You MUST define your own ACRA_MASTER_KEY - # The default is only for testing purposes - ACRA_MASTER_KEY: ${ACRA_MASTER_KEY:-UHZ3VUNNeTJ0SEFhbWVjNkt4eDdVYkc2WnNpUTlYa0E=} - volumes: - # Mount the whole ./.acrakeys directory to be able generate keys and - # place them in services' subdirectories - - ./.acrakeys:/keys - # Please specify ACRA_CLIENT_ID environment variable, otherwise run with - # default 'testclientid' client id - command: >- - --client_id=${ACRA_CLIENT_ID:-testclientid} - --generate_acraserver_keys - --keys_output_dir=/keys/acra-server - --keys_public_output_dir=/keys/acra-connector - # Create keys: - # - ./.acrakeys/acra-connector/${ACRA_CLIENT_ID} - # - ./.acrakeys/acra-server/${ACRA_CLIENT_ID}.pub - acra-keymaker_connector: - image: "cossacklabs/acra-keymaker:${ACRA_DOCKER_IMAGE_TAG:-latest}" - environment: - ACRA_MASTER_KEY: ${ACRA_MASTER_KEY:-UHZ3VUNNeTJ0SEFhbWVjNkt4eDdVYkc2WnNpUTlYa0E=} - volumes: - - ./.acrakeys:/keys - command: >- - --client_id=${ACRA_CLIENT_ID:-testclientid} - --generate_acraconnector_keys - --keys_output_dir=/keys/acra-connector - --keys_public_output_dir=/keys/acra-server - - #===== Acra ================================================================ - acra-server: - image: "cossacklabs/acra-server:${ACRA_DOCKER_IMAGE_TAG:-latest}" + image: "cossacklabs/acra-server:${ACRA_DOCKER_IMAGE_TAG:-0.95.0}" # Restart server after correct termination, for example after the config # was changed through the API restart: always - depends_on: - - acra-keymaker_server - - acra-keymaker_connector networks: - - acraconnector-acraserver + - mutillidae-acraserver - acraserver-db environment: ACRA_MASTER_KEY: ${ACRA_MASTER_KEY:-UHZ3VUNNeTJ0SEFhbWVjNkt4eDdVYkc2WnNpUTlYa0E=} volumes: # Mount the directory with only the keys for this service. Must be # rewriteable in case of using API, otherwise should be read-only. - - ./.acrakeys/acra-server:/keys # Directory with configuration, rewriteable - ./.acraconfigs/acra-server:/config command: >- --mysql_enable - --db_host=mutillidae + --db_host=database --db_port=3306 - --keys_dir=/keys - --auth_keys=/keys/httpauth.accounts - --http_api_enable - --incoming_connection_api_string=tcp://0.0.0.0:9090 + --keystore_cache_on_start_enable=false --acracensor_config_file=/config/acra-censor.yaml - -v + --v + --d + #===== OWASP Mutillidae II ================================================= - acra-connector: - image: "cossacklabs/acra-connector:${ACRA_DOCKER_IMAGE_TAG:-latest}" - restart: always + mutillidae: + container_name: mutillidae depends_on: - - acra-keymaker_server - - acra-keymaker_connector + - database - acra-server - # Open the port outside for client application + image: mutillidae + build: + context: https://github.com/webpwnized/mutillidae-docker.git#1.0.39:www + args: + DATABASE_HOST: acra-server + DATABASE_PORT: 9393 ports: - - "3306:3306" + - 127.0.0.1:8080:80 networks: - - acraconnector-acraserver - - mutillidae-acraconnector - environment: - ACRA_MASTER_KEY: ${ACRA_MASTER_KEY:-UHZ3VUNNeTJ0SEFhbWVjNkt4eDdVYkc2WnNpUTlYa0E=} - volumes: - # Mount the directory with only the keys for this service - - ./.acrakeys/acra-connector:/keys:ro - command: >- - --acraserver_connection_host=acra-server - --keys_dir=/keys - --client_id=${ACRA_CLIENT_ID:-testclientid} - --incoming_connection_string=tcp://0.0.0.0:3306 - --http_api_enable - --incoming_connection_api_string=tcp://0.0.0.0:9191 - -v - - - #===== OWASP Mutillidae II ================================================= - - edoz90_mutillidae: - # Build base image - build: - context: https://github.com/storojs72/docker-mutillidae.git - image: storojs72/edoz90_mutillidae:latest - # We don't need to run the container based on the original image - entrypoint: /bin/true - restart: 'no' + - world + - mutillidae-acraserver + #===== OWASP Mutillidae DB ================================================= - mutillidae: - depends_on: - - acra-connector - - edoz90_mutillidae + database: + container_name: database + image: webpwnized/mutillidae:database + healthcheck: + test: "/usr/bin/mysql --user=root --password=mutillidae --execute \"SHOW DATABASES;\"" + interval: 5s + timeout: 30s + retries: 10 build: - context: ./mutillidae - image: mutillidae:latest - ports: - - "8080:80" - - "3306:3306" + context: https://github.com/webpwnized/mutillidae-docker.git#1.0.39:database networks: - - world - - mutillidae-acraconnector - acraserver-db + healthcheck-wait: + image: busybox + container_name: healthcheck-wait + depends_on: + database: + condition: service_healthy networks: world: acraserver-db: internal: true - acraconnector-acraserver: + mutillidae-acraserver: internal: true - mutillidae-acraconnector: + mutillidae-db: internal: true diff --git a/images/acra-censor-scheme-noac.png b/images/acra-censor-scheme-noac.png deleted file mode 100644 index a0bdd8f..0000000 Binary files a/images/acra-censor-scheme-noac.png and /dev/null differ diff --git a/images/acra-censor-scheme.png b/images/acra-censor-scheme.png old mode 100755 new mode 100644 index cfcb1bb..8af80a9 Binary files a/images/acra-censor-scheme.png and b/images/acra-censor-scheme.png differ diff --git a/images/image_1.png b/images/image_1.png index 1ed5643..e23a1bf 100644 Binary files a/images/image_1.png and b/images/image_1.png differ diff --git a/images/image_2.png b/images/image_2.png index 0c8c2e7..794dfa7 100644 Binary files a/images/image_2.png and b/images/image_2.png differ diff --git a/images/image_3.png b/images/image_3.png index 496e550..dcdd81c 100644 Binary files a/images/image_3.png and b/images/image_3.png differ diff --git a/images/image_7.png b/images/image_7.png index 38cdb54..7207eca 100644 Binary files a/images/image_7.png and b/images/image_7.png differ diff --git a/mutillidae/Dockerfile b/mutillidae/Dockerfile deleted file mode 100644 index f75e8fe..0000000 --- a/mutillidae/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM storojs72/edoz90_mutillidae:latest - -ADD ./configure_db.sh /tmp/configure_db.sh -RUN /bin/bash /tmp/configure_db.sh -RUN rm /tmp/configure_db.sh - -EXPOSE 80 3306 diff --git a/mutillidae/configure_db.sh b/mutillidae/configure_db.sh deleted file mode 100644 index df25763..0000000 --- a/mutillidae/configure_db.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -MYSQL_ROOT_PASSWORD='test' - -MYSQL_DB='mutillidae' -MYSQL_USER='mutillidae' -MYSQL_PASSWORD='mutillidae' - -cat < /usr/share/nginx/html/mutillidae/includes/database-config.php - -EOF - -cat < /etc/my.cnf.d/mariadb-server.cnf -[mysqld] -bind-address=0.0.0.0 -EOF