├── .gitattributes ├── .github ├── RELEASE_WORKFLOW.md ├── dependabot.yml └── workflows │ ├── build-push.yml │ └── test-pr.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── logo └── skull_mask_266.png └── rootfs ├── etc ├── motd └── nginx │ ├── conf.d │ ├── events.conf │ ├── http.conf │ ├── http.srv.service1.conf │ ├── main.conf │ ├── stream.conf │ └── stream.srv.service2.conf │ ├── modsec.d │ └── modsec_includes.conf │ └── nginx.conf ├── opt └── swaf │ └── sbin │ ├── bootstrap.sh │ └── start.sh └── var └── lib └── nginx └── html ├── 400.html ├── 403.html ├── 404.html ├── 50x.html └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/RELEASE_WORKFLOW.md: -------------------------------------------------------------------------------- 1 | # Release Workflow 2 | 3 | This document describes the workflow to apply for releasing. 4 | 5 | ## Steps 6 | 7 | 1. Prepare 8 | 9 | * Code is ready, documented, tested for versioning. 10 | * Update `CHANGELOG.md` according to the release version, release date and change details, and the [[Changelog Template](#changelog-template)] below. 11 | * Delete empty sections in `CHANGELOG.md`. 12 | * Review `README.md` by removing roadmap-related messages ("Not Yet Implemented", "Roadmap vX.Y.Z", etc.) and other updates if needed. 13 | * Commit `CHANGELOG.md`. 14 | * Commit `README.md`. 15 | * Update [[Wiki/Build-Details](https://github.com/swaf-project/swaf-docker/wiki/Build-Details)] with last used versions. 16 | 17 | 2. Tag & Release 18 | 19 | * ALTERNATIVE 1 - Tag locally then make the GitHub release 20 | 21 | * `git checkout master` **#** Be sure to be on master branch 22 | * `git tag -a v -m "Release version "` **#** Tag master HEAD 23 | * `git push origin master --tags` **#** Push master branch with tags to the remote origin 24 | * Create the release on GitHub according to the [[GitHub Release Template](#github-release-template)] below with the existing tag. 25 | 26 | * ALTERNATIVE 2 - Create tag at the GitHub release creation step 27 | 28 | * Create the release on GitHub according to the [[GitHub Release Template](#github-release-template)] below especially for TAG and TITLE. 29 | * `git pull origin` **#** To locally pull the tag 30 | 31 | ## Changelog Template 32 | 33 | ```text 34 | # Changelog 35 | 36 | ## Version () 37 | 38 | Breaking Changes: 39 | 40 | * 41 | 42 | New Features: 43 | 44 | * 45 | 46 | Improvements: 47 | 48 | * 49 | 50 | Security Issues: 51 | 52 | * 53 | 54 | Bugfixes: 55 | 56 | * 57 | ``` 58 | 59 | ## GitHub Release Template 60 | 61 | * TAG (_Existing or to create_): 62 | 63 | * v 64 | 65 | * TITLE (_The same as tag_): 66 | 67 | * v 68 | 69 | * BODY TEMPLATE: 70 | 71 | ```text 72 | 73 | 74 | Please get the docker image on [[Docker Hub](https://hub.docker.com/r/swafproject/swaf)]: `docker pull swafproject/swaf` 75 | 76 | 77 | ``` 78 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" -------------------------------------------------------------------------------- /.github/workflows/build-push.yml: -------------------------------------------------------------------------------- 1 | name: Build & Publish on Docker Hub 2 | # Based on https://github.com/docker/build-push-action 3 | 4 | on: 5 | push: 6 | # Publish master head branch into dev repository 7 | branches: 8 | - master 9 | # Publish v*.*.* tagged image into release repository 10 | tags: 11 | - v*.*.* 12 | 13 | env: 14 | DH_ORGA: swafproject 15 | DH_REPO_DEV: swaf-dev 16 | DH_REPO_REL: swaf 17 | TITLE_DEV: sWAF-dev 18 | TITLE_REL: sWAF 19 | # Build time for linux/amd64 only: ~20-25min 20 | # Buid time for linux/amd64 & linux/arm/v7 & linux/arm64/v8: ~3h25min 21 | PLATFORMS_DEV: linux/amd64 22 | PLATFORMS_REL: linux/amd64,linux/arm/v7,linux/arm64/v8 23 | 24 | jobs: 25 | # Push image to Docker Hub 26 | build_push: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v2 31 | 32 | - name: Repo metadata for labels 33 | id: repo 34 | uses: actions/github-script@v3 35 | with: 36 | script: | 37 | const repo = await github.repos.get(context.repo) 38 | return repo.data 39 | 40 | - name: Prepare repository and tags 41 | id: prep 42 | run: | 43 | DOCKER_IMAGE=${DH_ORGA}/${DH_REPO_DEV} 44 | TITLE=${TITLE_REL} 45 | PLATFORMS=${PLATFORMS_DEV} 46 | VERSION=noop 47 | if [[ $GITHUB_REF == refs/tags/* ]]; then 48 | DOCKER_IMAGE=${DH_ORGA}/${DH_REPO_REL} 49 | TITLE=${TITLE_REL} 50 | PLATFORMS=${PLATFORMS_REL} 51 | VERSION=$(echo ${GITHUB_REF#refs/tags/} | sed -r 's#v##g') 52 | else 53 | DOCKER_IMAGE=${DH_ORGA}/${DH_REPO_DEV} 54 | TITLE=${TITLE_DEV} 55 | PLATFORMS=${PLATFORMS_DEV} 56 | VERSION=dev-$(date -u +'%Y%m%dT%H%M%SZ') 57 | fi 58 | TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest" 59 | if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 60 | MINOR=${VERSION%.*} 61 | MAJOR=${MINOR%.*} 62 | TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR}" 63 | fi 64 | echo ::set-output name=title::${TITLE} 65 | echo ::set-output name=platforms::${PLATFORMS} 66 | echo ::set-output name=version::${VERSION} 67 | echo ::set-output name=tags::${TAGS} 68 | echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ') 69 | 70 | - name: Set up QEMU 71 | uses: docker/setup-qemu-action@v1 72 | 73 | - name: Set up Docker Buildx 74 | uses: docker/setup-buildx-action@v1 75 | 76 | - name: Cache Docker layers 77 | uses: actions/cache@v2 78 | with: 79 | path: /tmp/.buildx-cache 80 | key: ${{ runner.os }}-buildx-${{ github.sha }} 81 | restore-keys: | 82 | ${{ runner.os }}-buildx- 83 | 84 | - name: Login to Docker Hub 85 | uses: docker/login-action@v1 86 | with: 87 | username: ${{ secrets.DOCKERHUB_USERNAME }} 88 | password: ${{ secrets.DOCKERHUB_TOKEN }} 89 | 90 | #- name: Login to GitHub Container Registry 91 | #uses: docker/login-action@v1 92 | #with: 93 | #registry: ghcr.io 94 | #username: ${{ github.repository_owner }} 95 | #password: ${{ secrets.CR_PAT }} 96 | 97 | - name: Build & Push 98 | uses: docker/build-push-action@v2 99 | with: 100 | context: . 101 | file: ./Dockerfile 102 | platforms: ${{ steps.prep.outputs.platforms }} 103 | cache-from: type=local,src=/tmp/.buildx-cache 104 | cache-to: type=local,dest=/tmp/.buildx-cache 105 | push: true 106 | tags: ${{ steps.prep.outputs.tags }} 107 | labels: | 108 | org.opencontainers.image.title=${{ steps.prep.outputs.title }} 109 | org.opencontainers.image.description=${{ fromJson(steps.repo.outputs.result).description }} 110 | org.opencontainers.image.url=${{ fromJson(steps.repo.outputs.result).html_url }} 111 | org.opencontainers.image.documentation=${{ fromJson(steps.repo.outputs.result).html_url }}/wiki 112 | org.opencontainers.image.source=${{ fromJson(steps.repo.outputs.result).clone_url }} 113 | org.opencontainers.image.version=${{ steps.prep.outputs.version }} 114 | org.opencontainers.image.created=${{ steps.prep.outputs.created }} 115 | org.opencontainers.image.revision=${{ github.sha }} 116 | org.opencontainers.image.licenses=${{ fromJson(steps.repo.outputs.result).license.spdx_id }} 117 | 118 | #- name: Push to GitHub Packages 119 | # uses: docker/build-push-action@v1 120 | # with: 121 | # username: ${{ github.actor }} 122 | # password: ${{ secrets.GITHUB_TOKEN }} 123 | # registry: docker.pkg.github.com 124 | # repository: my-org/my-repo/my-image 125 | #ghcr.io/user/app:latest 126 | #ghcr.io/user/app:1.0.0 127 | 128 | - name: Image digest 129 | run: echo ${{ steps.docker_build.outputs.digest }} -------------------------------------------------------------------------------- /.github/workflows/test-pr.yml: -------------------------------------------------------------------------------- 1 | name: Test Pull Request 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | # Testing job 10 | test_pr: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Run tests 17 | run: | 18 | docker build . --file ./Dockerfile --tag swaf-test-pr 19 | # TODO Add run test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | .old 4 | .bak 5 | .tmp 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - windows 4 | language: minimal 5 | 6 | services: 7 | - docker 8 | 9 | jobs: 10 | include: 11 | - stage: build & test docker image 12 | script: 13 | - docker build -t swaf . 14 | - docker images 15 | - docker run --name swaf -d --restart always swaf 16 | - docker ps -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 0.2.0 (YYYY-MM-DD) 4 | 5 | Breaking Changes: 6 | 7 | TODO 8 | 9 | New Features: 10 | 11 | * NAXSI 1.2 compiled with NGINX as a dynamic module. 12 | * NAXSI core rules file staged from NAXSI 1.2. 13 | * acme.sh 2.8.7 for Let's Encrypt and others free CA support. 14 | * acme.sh works with http-01 (in webroot mode only) and dns-01 challenges. 15 | * Upgrade to LibreSSL 3.2.2 ([Release Notes](https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.2.2-relnotes.txt)). 16 | * Upgrade to NGINX 1.19.4 ([Release Notes](https://nginx.org/en/CHANGES)). 17 | 18 | TODO 19 | 20 | Improvements: 21 | 22 | * DH parameters for DHE ciphers automatically generated. 23 | * Reviewed default SSL params. 24 | * Set up the default server loaded aa the first one in `http.conf`. 25 | * Improved documentation - Less in [README](https://github.com/swaf-project/swaf-docker), more in [Wiki](https://github.com/swaf-project/swaf-docker/wiki). 26 | * Added all commands related to control ACME certificates in the documentation. 27 | * Example HTTP virtual server more ready to be used. 28 | * Updated default HTML pages. 29 | * `bootstrap.sh` and `start.sh` moved in `/opt/swaf/sbin`. 30 | 31 | TODO 32 | 33 | Security Issues: 34 | 35 | TODO 36 | 37 | Bugfixes: 38 | 39 | * Patch acme.sh script with LibreSSL, which is retrocompatible with OpenSSL and used here in sWAF. 40 | * Patch acme.sh script header back to the default shell call. 41 | * Patch acme.sh script with LibreSSL instead of OpenSSL calls hard-coded twice. 42 | 43 | TODO 44 | 45 | ## Version 0.1.0 (2020-10-27) 46 | 47 | Initial Features: 48 | 49 | * Dockerfile based on Alpine Linux 3.12.0. 50 | * Bootstrap script to compile, install, deploy & configure tools. 51 | * Docker entrypoint script to deploy the sWAF image's initial configuration at the first time and to launch NGINX each time starting. 52 | * Additional installed tools: 53 | + curl 7.69.1 54 | + git 2.26.2 55 | + nano 4.9.3 56 | * ModSecurity 3.0.4 compiled with: 57 | + LibCURL 7.69.1 58 | + YAJL 2.1.0 59 | + LibXML2 2.9.10 60 | + SSDEEP (Last version from GitHub at build date) 61 | + LUA 5.1.5 62 | + Test Utilities 63 | + SecDebugLog 64 | * LibreSSL 3.2.1 compiled. 65 | * NGINX 1.19.2 compiled (detailed compilation options are listed into the bootstrap script): 66 | + using threads 67 | + using system PCRE library 68 | + using LibreSSL library with TLS 1.3 and TLS SNI support 69 | + using system zlib library 70 | + using system libatomic_ops library 71 | + using all NGINX all default and additional static modules except: fastcgi, scgi, http_geoip 72 | + using stream module with all default and additional static modules except stream_geoip 73 | + using ModSecurity-nginx connector (ngx_http_modsecurity_module). Last version from GitHub at build date. 74 | + with pcre and pcre-jit 75 | + no mail proxy modules 76 | + no google_perftools_module 77 | + no cpp_test_module 78 | + no http_perl_module 79 | + with debug logging capacity 80 | * Default NGINX configuration files staged with initial examples. 81 | * NGINX configuration files splitted by context (main, events, http, stream, server). 82 | * HTML pages staged for default index and error pages. 83 | * Default ModSecurity configuration files staged from ModSecurity 3.0.4. 84 | * Default Core Rule Set 3.3.0 configuration staged with: 85 | + 'SecRuleEngine On' by default 86 | + modsec_audit.log path properly set 87 | + unicode.mapping path properly set 88 | * Custom modsec_includes.conf staged for ModSecurity configuration load. 89 | * Custom motd for sWAF. 90 | * Set Docker image labels. 91 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # sWAF - A simple Web Application Firewall 2 | # Copyright (C) 2020 styx0x6 3 | 4 | # This file is part of sWAF. This software is licensed under the 5 | # European Union Public License 1.2 (EUPL-1.2), published in Official Journal 6 | # of the European Union (OJ) of 19 May 2017 and available in 23 official 7 | # languages of the European Union. 8 | # The English version is included with this software. Please see the following 9 | # page for all the official versions of the EUPL-1.2: 10 | # https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 11 | 12 | FROM alpine:3.12.0 13 | 14 | # https://github.com/opencontainers/image-spec/blob/master/annotations.md 15 | LABEL org.opencontainers.image.authors="The sWAF Project Team " 16 | LABEL org.opencontainers.image.vendor="https://github.com/swaf-project" 17 | # Others labels are dynamically set at built-time (See repo's GitHub Actions) 18 | 19 | # Bootstrap sWAF 20 | ## --> Copy scripts 21 | COPY rootfs/opt/swaf/sbin/bootstrap.sh /tmp/bootstrap.sh 22 | COPY rootfs/opt/swaf/sbin/start.sh /tmp/start.sh 23 | ## --> Copy static files 24 | COPY rootfs/etc/motd /tmp/ 25 | COPY rootfs/etc/nginx/*.conf* /tmp/ 26 | COPY rootfs/etc/nginx/conf.d/*.conf* /tmp/ 27 | COPY rootfs/etc/nginx/modsec.d/*.conf* /tmp/ 28 | COPY rootfs/var/lib/nginx/html/*.html /tmp/ 29 | ## --> Only one RUN to avoid a multi-layered and oversized image 30 | RUN mkdir -p /opt/swaf/sbin \ 31 | && cp /tmp/start.sh /opt/swaf/sbin/start.sh \ 32 | && cp /tmp/bootstrap.sh /opt/swaf/sbin/bootstrap.sh \ 33 | && chmod +x /opt/swaf/sbin/start.sh \ 34 | && chmod +x /opt/swaf/sbin/bootstrap.sh \ 35 | && /opt/swaf/sbin/bootstrap.sh 36 | 37 | # Entrypoint 38 | ENTRYPOINT ["/opt/swaf/sbin/start.sh"] 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | EUROPEAN UNION PUBLIC LICENCE v. 1.2 2 | EUPL © the European Union 2007, 2016 3 | 4 | This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined 5 | below) which is provided under the terms of this Licence. Any use of the Work, 6 | other than as authorised under this Licence is prohibited (to the extent such 7 | use is covered by a right of the copyright holder of the Work). 8 | 9 | The Work is provided under the terms of this Licence when the Licensor (as 10 | defined below) has placed the following notice immediately following the 11 | copyright notice for the Work: 12 | 13 | Licensed under the EUPL 14 | 15 | or has expressed by any other means his willingness to license under the EUPL. 16 | 17 | 1. Definitions 18 | 19 | In this Licence, the following terms have the following meaning: 20 | 21 | - ‘The Licence’: this Licence. 22 | 23 | - ‘The Original Work’: the work or software distributed or communicated by the 24 | Licensor under this Licence, available as Source Code and also as Executable 25 | Code as the case may be. 26 | 27 | - ‘Derivative Works’: the works or software that could be created by the 28 | Licensee, based upon the Original Work or modifications thereof. This Licence 29 | does not define the extent of modification or dependence on the Original Work 30 | required in order to classify a work as a Derivative Work; this extent is 31 | determined by copyright law applicable in the country mentioned in Article 15. 32 | 33 | - ‘The Work’: the Original Work or its Derivative Works. 34 | 35 | - ‘The Source Code’: the human-readable form of the Work which is the most 36 | convenient for people to study and modify. 37 | 38 | - ‘The Executable Code’: any code which has generally been compiled and which is 39 | meant to be interpreted by a computer as a program. 40 | 41 | - ‘The Licensor’: the natural or legal person that distributes or communicates 42 | the Work under the Licence. 43 | 44 | - ‘Contributor(s)’: any natural or legal person who modifies the Work under the 45 | Licence, or otherwise contributes to the creation of a Derivative Work. 46 | 47 | - ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of 48 | the Work under the terms of the Licence. 49 | 50 | - ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, 51 | renting, distributing, communicating, transmitting, or otherwise making 52 | available, online or offline, copies of the Work or providing access to its 53 | essential functionalities at the disposal of any other natural or legal 54 | person. 55 | 56 | 2. Scope of the rights granted by the Licence 57 | 58 | The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, 59 | sublicensable licence to do the following, for the duration of copyright vested 60 | in the Original Work: 61 | 62 | - use the Work in any circumstance and for all usage, 63 | - reproduce the Work, 64 | - modify the Work, and make Derivative Works based upon the Work, 65 | - communicate to the public, including the right to make available or display 66 | the Work or copies thereof to the public and perform publicly, as the case may 67 | be, the Work, 68 | - distribute the Work or copies thereof, 69 | - lend and rent the Work or copies thereof, 70 | - sublicense rights in the Work or copies thereof. 71 | 72 | Those rights can be exercised on any media, supports and formats, whether now 73 | known or later invented, as far as the applicable law permits so. 74 | 75 | In the countries where moral rights apply, the Licensor waives his right to 76 | exercise his moral right to the extent allowed by law in order to make effective 77 | the licence of the economic rights here above listed. 78 | 79 | The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to 80 | any patents held by the Licensor, to the extent necessary to make use of the 81 | rights granted on the Work under this Licence. 82 | 83 | 3. Communication of the Source Code 84 | 85 | The Licensor may provide the Work either in its Source Code form, or as 86 | Executable Code. If the Work is provided as Executable Code, the Licensor 87 | provides in addition a machine-readable copy of the Source Code of the Work 88 | along with each copy of the Work that the Licensor distributes or indicates, in 89 | a notice following the copyright notice attached to the Work, a repository where 90 | the Source Code is easily and freely accessible for as long as the Licensor 91 | continues to distribute or communicate the Work. 92 | 93 | 4. Limitations on copyright 94 | 95 | Nothing in this Licence is intended to deprive the Licensee of the benefits from 96 | any exception or limitation to the exclusive rights of the rights owners in the 97 | Work, of the exhaustion of those rights or of other applicable limitations 98 | thereto. 99 | 100 | 5. Obligations of the Licensee 101 | 102 | The grant of the rights mentioned above is subject to some restrictions and 103 | obligations imposed on the Licensee. Those obligations are the following: 104 | 105 | Attribution right: The Licensee shall keep intact all copyright, patent or 106 | trademarks notices and all notices that refer to the Licence and to the 107 | disclaimer of warranties. The Licensee must include a copy of such notices and a 108 | copy of the Licence with every copy of the Work he/she distributes or 109 | communicates. The Licensee must cause any Derivative Work to carry prominent 110 | notices stating that the Work has been modified and the date of modification. 111 | 112 | Copyleft clause: If the Licensee distributes or communicates copies of the 113 | Original Works or Derivative Works, this Distribution or Communication will be 114 | done under the terms of this Licence or of a later version of this Licence 115 | unless the Original Work is expressly distributed only under this version of the 116 | Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee 117 | (becoming Licensor) cannot offer or impose any additional terms or conditions on 118 | the Work or Derivative Work that alter or restrict the terms of the Licence. 119 | 120 | Compatibility clause: If the Licensee Distributes or Communicates Derivative 121 | Works or copies thereof based upon both the Work and another work licensed under 122 | a Compatible Licence, this Distribution or Communication can be done under the 123 | terms of this Compatible Licence. For the sake of this clause, ‘Compatible 124 | Licence’ refers to the licences listed in the appendix attached to this Licence. 125 | Should the Licensee's obligations under the Compatible Licence conflict with 126 | his/her obligations under this Licence, the obligations of the Compatible 127 | Licence shall prevail. 128 | 129 | Provision of Source Code: When distributing or communicating copies of the Work, 130 | the Licensee will provide a machine-readable copy of the Source Code or indicate 131 | a repository where this Source will be easily and freely available for as long 132 | as the Licensee continues to distribute or communicate the Work. 133 | 134 | Legal Protection: This Licence does not grant permission to use the trade names, 135 | trademarks, service marks, or names of the Licensor, except as required for 136 | reasonable and customary use in describing the origin of the Work and 137 | reproducing the content of the copyright notice. 138 | 139 | 6. Chain of Authorship 140 | 141 | The original Licensor warrants that the copyright in the Original Work granted 142 | hereunder is owned by him/her or licensed to him/her and that he/she has the 143 | power and authority to grant the Licence. 144 | 145 | Each Contributor warrants that the copyright in the modifications he/she brings 146 | to the Work are owned by him/her or licensed to him/her and that he/she has the 147 | power and authority to grant the Licence. 148 | 149 | Each time You accept the Licence, the original Licensor and subsequent 150 | Contributors grant You a licence to their contributions to the Work, under the 151 | terms of this Licence. 152 | 153 | 7. Disclaimer of Warranty 154 | 155 | The Work is a work in progress, which is continuously improved by numerous 156 | Contributors. It is not a finished work and may therefore contain defects or 157 | ‘bugs’ inherent to this type of development. 158 | 159 | For the above reason, the Work is provided under the Licence on an ‘as is’ basis 160 | and without warranties of any kind concerning the Work, including without 161 | limitation merchantability, fitness for a particular purpose, absence of defects 162 | or errors, accuracy, non-infringement of intellectual property rights other than 163 | copyright as stated in Article 6 of this Licence. 164 | 165 | This disclaimer of warranty is an essential part of the Licence and a condition 166 | for the grant of any rights to the Work. 167 | 168 | 8. Disclaimer of Liability 169 | 170 | Except in the cases of wilful misconduct or damages directly caused to natural 171 | persons, the Licensor will in no event be liable for any direct or indirect, 172 | material or moral, damages of any kind, arising out of the Licence or of the use 173 | of the Work, including without limitation, damages for loss of goodwill, work 174 | stoppage, computer failure or malfunction, loss of data or any commercial 175 | damage, even if the Licensor has been advised of the possibility of such damage. 176 | However, the Licensor will be liable under statutory product liability laws as 177 | far such laws apply to the Work. 178 | 179 | 9. Additional agreements 180 | 181 | While distributing the Work, You may choose to conclude an additional agreement, 182 | defining obligations or services consistent with this Licence. However, if 183 | accepting obligations, You may act only on your own behalf and on your sole 184 | responsibility, not on behalf of the original Licensor or any other Contributor, 185 | and only if You agree to indemnify, defend, and hold each Contributor harmless 186 | for any liability incurred by, or claims asserted against such Contributor by 187 | the fact You have accepted any warranty or additional liability. 188 | 189 | 10. Acceptance of the Licence 190 | 191 | The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ 192 | placed under the bottom of a window displaying the text of this Licence or by 193 | affirming consent in any other similar way, in accordance with the rules of 194 | applicable law. Clicking on that icon indicates your clear and irrevocable 195 | acceptance of this Licence and all of its terms and conditions. 196 | 197 | Similarly, you irrevocably accept this Licence and all of its terms and 198 | conditions by exercising any rights granted to You by Article 2 of this Licence, 199 | such as the use of the Work, the creation by You of a Derivative Work or the 200 | Distribution or Communication by You of the Work or copies thereof. 201 | 202 | 11. Information to the public 203 | 204 | In case of any Distribution or Communication of the Work by means of electronic 205 | communication by You (for example, by offering to download the Work from a 206 | remote location) the distribution channel or media (for example, a website) must 207 | at least provide to the public the information requested by the applicable law 208 | regarding the Licensor, the Licence and the way it may be accessible, concluded, 209 | stored and reproduced by the Licensee. 210 | 211 | 12. Termination of the Licence 212 | 213 | The Licence and the rights granted hereunder will terminate automatically upon 214 | any breach by the Licensee of the terms of the Licence. 215 | 216 | Such a termination will not terminate the licences of any person who has 217 | received the Work from the Licensee under the Licence, provided such persons 218 | remain in full compliance with the Licence. 219 | 220 | 13. Miscellaneous 221 | 222 | Without prejudice of Article 9 above, the Licence represents the complete 223 | agreement between the Parties as to the Work. 224 | 225 | If any provision of the Licence is invalid or unenforceable under applicable 226 | law, this will not affect the validity or enforceability of the Licence as a 227 | whole. Such provision will be construed or reformed so as necessary to make it 228 | valid and enforceable. 229 | 230 | The European Commission may publish other linguistic versions or new versions of 231 | this Licence or updated versions of the Appendix, so far this is required and 232 | reasonable, without reducing the scope of the rights granted by the Licence. New 233 | versions of the Licence will be published with a unique version number. 234 | 235 | All linguistic versions of this Licence, approved by the European Commission, 236 | have identical value. Parties can take advantage of the linguistic version of 237 | their choice. 238 | 239 | 14. Jurisdiction 240 | 241 | Without prejudice to specific agreement between parties, 242 | 243 | - any litigation resulting from the interpretation of this License, arising 244 | between the European Union institutions, bodies, offices or agencies, as a 245 | Licensor, and any Licensee, will be subject to the jurisdiction of the Court 246 | of Justice of the European Union, as laid down in article 272 of the Treaty on 247 | the Functioning of the European Union, 248 | 249 | - any litigation arising between other parties and resulting from the 250 | interpretation of this License, will be subject to the exclusive jurisdiction 251 | of the competent court where the Licensor resides or conducts its primary 252 | business. 253 | 254 | 15. Applicable Law 255 | 256 | Without prejudice to specific agreement between parties, 257 | 258 | - this Licence shall be governed by the law of the European Union Member State 259 | where the Licensor has his seat, resides or has his registered office, 260 | 261 | - this licence shall be governed by Belgian law if the Licensor has no seat, 262 | residence or registered office inside a European Union Member State. 263 | 264 | Appendix 265 | 266 | ‘Compatible Licences’ according to Article 5 EUPL are: 267 | 268 | - GNU General Public License (GPL) v. 2, v. 3 269 | - GNU Affero General Public License (AGPL) v. 3 270 | - Open Software License (OSL) v. 2.1, v. 3.0 271 | - Eclipse Public License (EPL) v. 1.0 272 | - CeCILL v. 2.0, v. 2.1 273 | - Mozilla Public Licence (MPL) v. 2 274 | - GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 275 | - Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for 276 | works other than software 277 | - European Union Public Licence (EUPL) v. 1.1, v. 1.2 278 | - Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong 279 | Reciprocity (LiLiQ-R+). 280 | 281 | The European Commission may update this Appendix to later versions of the above 282 | licences without producing a new version of the EUPL, as long as they provide 283 | the rights granted in Article 2 of this Licence and protect the covered Source 284 | Code from exclusive appropriation. 285 | 286 | All other changes or additions to this Appendix require the production of a new 287 | EUPL version. 288 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```text 2 | ___ ___ _________ 3 | ___\ \ / \ | _____/ 4 | ( __\ \ /\ / _ \ | |___ 5 | \ \ \ \/ \/ / \ \| __/ >>> A simple Web Application Firewall docker image. 6 | ___) \ \ /\ /---\ \ | 7 | \_____/ \_/ \_/ \____| 8 | ``` 9 | 10 | **sWAF** is a **simple Web Application Firewall** [docker image](https://hub.docker.com/r/swafproject/swaf), pre-configured to be easily used within your web services architecture. 11 | 12 | It runs [NGINX](https://www.nginx.com/) as a dedicated reverse proxy embedding powerful WAF engines: [ModSecurity 3](https://www.modsecurity.org/), using [OWASP® ModSecurity Core Rule Set (CRS)](https://coreruleset.org/) rules, and [NAXSI](https://github.com/nbs-system/naxsi). It uses [acme.sh](https://acme.sh/) for Let's Encrypt and others free CA support. 13 | 14 | [![dockeri.co](https://dockeri.co/image/swafproject/swaf)](https://hub.docker.com/r/swafproject/swaf) 15 | 16 | [![Docker Image Version](https://img.shields.io/docker/v/swafproject/swaf?sort=semver&logo=docker&color=blue)](https://hub.docker.com/r/swafproject/swaf) 17 | [![Docker Image Size](https://img.shields.io/docker/image-size/swafproject/swaf?sort=semver&logo=docker)](https://hub.docker.com/r/swafproject/swaf) 18 | [![GitHub Release](https://img.shields.io/github/release/swaf-project/swaf-docker.svg?logo=github&sort=semver&color=brightgreen)](https://github.com/swaf-project/swaf-docker/releases) 19 | [![Travis CI Build Status](https://img.shields.io/travis/swaf-project/swaf-docker/master.svg?logo=travis&label=master)](https://travis-ci.org/swaf-project/swaf-docker) 20 | [![License](https://img.shields.io/github/license/swaf-project/swaf-docker?color=blue)](https://raw.githubusercontent.com/swaf-project/swaf-docker/master/LICENSE) 21 | 22 | ## About 23 | 24 | ### Why sWAF 25 | 26 | A lot of people are **self-hosting** their own cloud infrastructure (using Nextcloud, Synology, QNAP, a cloud lease server or home-made solutions...), but we can never be too much paranoid about web security for a lot of good reasons. Too much time security is left on background, or only by using some basics - but not sufficient - options, and applications are front-faced to the big bad Internet. 27 | 28 | That's why **sWAF** is here to offer a **simple WAF** docker image acting as an infrastructure security asset ready to be deployed wherever into your network infrastructure: 29 | 30 | **[Client]** --`hxxp(s)://drive.example.com`--> **[sWAF > rProxy+Security]** --`hxxp://a.b.c.d:6666`--> **[webservice1]** 31 | 32 | ### Main Features 33 | 34 | * **NGINX** with: 35 | + **LibreSSL** & **TLS 1.3** support. 36 | + **ModSecurity 3** & **OWASP® ModSecurity Core Rule Set**. 37 | + **NAXSI**. (_Roadmap v0.2.0_) 38 | * **acme.sh** for **Let's Encrypt** and others free CA support. (_Roadmap v0.2.0_) 39 | 40 | ### Links 41 | 42 | * **Homepage**: [[swaf-project.github.io](https://swaf-project.github.io/)] 43 | * **Git Repository**: [[https://github.com/swaf-project/swaf-docker.git](https://github.com/swaf-project/swaf-docker.git)] 44 | * **Docker Hub**: [[swafproject/swaf](https://hub.docker.com/r/swafproject/swaf)] 45 | * **Issues Tracker**: [[Bugs & Support](https://github.com/swaf-project/swaf-docker/issues)] 46 | * **Documentation**: [[Wiki](https://github.com/swaf-project/swaf-docker/wiki)] or [[Clone Wiki Documentation](https://github.com/swaf-project/swaf-docker.wiki.git)] to get a local copy. 47 | 48 | ## Getting Started 49 | 50 | 1. Get sWAF docker image: 51 | 52 | ```shell 53 | docker pull swafproject/swaf 54 | ``` 55 | 56 | 2. Start a sWAF container: 57 | 58 | ```shell 59 | docker run -d --name swaf --restart always --net host swafproject/swaf 60 | ``` 61 | 62 | 3. Test it: 63 | 64 | TODO Testing GIF 65 | 66 | 4. Check out [[Wiki](https://github.com/swaf-project/swaf-docker/wiki)] documentation for all details about usage. 67 | 68 | ## Releases Lifecycle 69 | 70 | Build details on [[Wiki/Build-Details](https://github.com/swaf-project/swaf-docker/wiki/Build-Details)] 71 | 72 | ### Releases 73 | 74 | * Releases are built in [[swafproject/swaf](https://hub.docker.com/r/swafproject/swaf)] repository on Docker Hub. Checkout [[Releases Page](https://github.com/swaf-project/swaf-docker/releases)] for details. 75 | 76 | ### Development 77 | 78 | * `master` branch is continuously built in [[swafproject/swaf-dev](https://hub.docker.com/r/swafproject/swaf-dev)] repository on Docker Hub. 79 | 80 | * Last development status (based on master HEAD): 81 | 82 | [![Docker Image Version](https://img.shields.io/docker/v/swafproject/swaf-dev?sort=semver&logo=docker)](https://hub.docker.com/r/swafproject/swaf-dev) 83 | [![Docker Image Size](https://img.shields.io/docker/image-size/swafproject/swaf-dev?sort=semver&logo=docker)](https://hub.docker.com/r/swafproject/swaf-dev) 84 | 85 | * **DO NOT use development image for your production, the only purpose of this image is for development!** 86 | 87 | ### Changelog 88 | 89 | Change details are listed into [[CHANGELOG.md](CHANGELOG.md)]. 90 | 91 | ## Contributing 92 | 93 | Feel free to submit enhancement proposal via [[Pull Requets](https://github.com/swaf-project/swaf-docker/pulls)]! 94 | 95 | Please check [[Contributing](https://github.com/MarcDiethelm/contributing)] by Marc Diethelm for more details about how to do. 96 | 97 | ## Credits 98 | 99 | A project initiated by **[@styx0x6](https://github.com/styx0x6)**. 100 | 101 | ## License 102 | 103 | sWAF - A simple Web Application Firewall docker image. 104 | 105 | Copyright © 2020 **[@styx0x6](https://github.com/styx0x6)** 106 | 107 | This file is part of sWAF. This software is licensed under the 108 | European Union Public License 1.2 (EUPL-1.2), published in Official Journal 109 | of the European Union (OJ) of 19 May 2017 and available in 23 official 110 | languages of the European Union. 111 | 112 | The English version is included with this software. Please see the following 113 | page for all the official versions of the EUPL-1.2: 114 | 115 | 116 | -------------------------------------------------------------------------------- /logo/skull_mask_266.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaf-project/swaf-docker/17094f53cf220e3f6850561256b47cd51dfd349e/logo/skull_mask_266.png -------------------------------------------------------------------------------- /rootfs/etc/motd: -------------------------------------------------------------------------------- 1 | ============================================ 2 | ___ ___ _________ 3 | ___\ \ / \ | _____/ 4 | ( __\ \ /\ / _ \ | |___ 5 | \ \ \ \/ \/ / \ \| __/ 6 | ___) \ \ /\ /---\ \ | 7 | \_____/ \_/ \_/ \____| 8 | 9 | Welcome to sWAF! 10 | https://swaf-project.github.io 11 | ============================================ 12 | 13 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/events.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'events' context directives 3 | # Configuration of connection processing 4 | 5 | 6 | worker_connections 1024; 7 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/http.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'http' context directives 3 | # Configuration specific to HTTP and affecting all virtual servers 4 | 5 | 6 | include mime.types; 7 | default_type application/octet-stream; 8 | 9 | # 'main' log format which is combined log format appended with "$http_x_forwarded_for" 10 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 11 | '$status $body_bytes_sent "$http_referer" ' 12 | '"$http_user_agent" "$http_x_forwarded_for"'; 13 | 14 | access_log /var/log/nginx/access.log main; 15 | 16 | # Optimization 17 | sendfile on; 18 | tcp_nodelay on; 19 | tcp_nopush on; 20 | 21 | 22 | # DNS resolver (https://blog.cloudflare.com/dns-resolver-1-1-1-1/) 23 | resolver 1.1.1.1; 24 | 25 | 26 | keepalive_timeout 65; 27 | 28 | 29 | # Global server security settings 30 | 31 | ## --> TLS settings 32 | ### https://nginx.org/en/docs/http/ngx_http_ssl_module.html 33 | ssl_protocols TLSv1.2 TLSv1.3; 34 | ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305-D:ECDHE-RSA-CHACHA20-POLY1305-D:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384'; 35 | ssl_session_timeout 20m; 36 | ssl_session_cache shared:ssl_http_cache:10m; 37 | ssl_session_tickets off; 38 | ssl_dhparam /etc/ssl/dhparams.pem; 39 | ssl_prefer_server_ciphers off; 40 | #### Improves TTFB by using a smaller SSL buffer than the nginx default 41 | ssl_buffer_size 4k; 42 | 43 | 44 | ## --> HTTP compression 45 | # FIXME http://www.breachattack.com/ ? 46 | gzip on; 47 | 48 | 49 | # ModSecurity 50 | modsecurity on; 51 | modsecurity_rules_file /etc/nginx/modsec.d/modsec_includes.conf; 52 | 53 | 54 | # NAXSI 55 | include /etc/nginx/naxsi.d/naxsi_core.rules; 56 | 57 | 58 | # Default server 59 | 60 | ## --> "Catch-All":80 virtual server to be loaded before user-defined virtual servers 61 | server { 62 | listen 80 default_server; 63 | #listen [::]:80 default_server; 64 | server_name _; 65 | 66 | ### Configuration specific to acme.sh in webroot mode 67 | ### DO NOT MODIFY THIS BLOCK 68 | location ~ ^/\.well-known/acme-challenge/([\-_a-zA-Z0-9]+)$ { 69 | root /var/lib/acme; 70 | access_log /var/log/nginx/acme.access.log main; 71 | default_type text/plain; 72 | } 73 | 74 | ### Error pages return 444, a non-standard code that closes the connection 75 | error_page 400 403 404 500 502 503 504 =444 /444.html; 76 | location = /444.html { 77 | return 444; 78 | } 79 | 80 | ### DEFAULT FIRST TEST PAGE 81 | ### !!! PLEASE COMMENT THE BLOCK BELOW BEFORE USING SWAF !!! 82 | location / { 83 | root /var/lib/nginx/html; 84 | index index.html; 85 | } 86 | 87 | } 88 | 89 | ## --> "No Host Header":80 to prevent processing requests with undefined server names 90 | server { 91 | listen 80; 92 | #listen [::]:80; 93 | server_name ""; 94 | return 444; 95 | } 96 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/http.srv.service1.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'http' context directives 3 | # Configuration specific to HTTP virtual servers and upstreams 4 | 5 | 6 | ## --> EXAMPLE: Define simple upstream group. 7 | #upstream pool_server { 8 | # server server1:80; 9 | # server server2:80; 10 | #} 11 | 12 | 13 | ## --> EXAMPLE: Redirect from HTTP to HTTPS. 14 | #server { 15 | # ### Listening on IPv4 16 | # listen 80; 17 | # ### Listening on IPv6 18 | # listen [::]:80; 19 | # server_name example.com example.org; 20 | # 21 | # return 301 https://$host$request_uri; 22 | #} 23 | 24 | #server { 25 | # ### Listening on IPv4 26 | # listen 443 ssl http2; 27 | # ### Listening on IPv6 28 | # listen [::]:443 ssl http2; 29 | # server_name example.com example.org; 30 | # 31 | # ### Always use fullchained certificate that includes intermediate ones 32 | # ssl_certificate /var/lib/certs/example.com/fullchain.cer; 33 | # ssl_certificate_key /var/lib/certs/example.com/example.com.key; 34 | # 35 | # ### Prefix properly the access.log file 36 | # access_log /var/log/nginx/example.access.log main; 37 | # 38 | # ### Enable HSTS if your web service should only be served using HTTPS 39 | # ### Set max-age to 86400s at first in case of mistake in the HTTPS deployment 40 | # add_header Strict-Transport-Security "max-age=86400; includeSubDomains" always; 41 | # ### Set HSTS max-age to 1 year if you are sure of your deployment 42 | # #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 43 | # 44 | # ### Proxify requests to the backend pool server 45 | # location / { 46 | # proxy_pass http://pool_server; 47 | # } 48 | # 49 | # location /one { 50 | # # Specific configuration for processing URIs starting with '/one' 51 | # } 52 | # 53 | # location /two { 54 | # # Specific configuration for processing URIs starting with '/two' 55 | # } 56 | # 57 | # ### sWAF defined error pages without any signature 58 | # error_page 400 /400.html; 59 | # location = /400.html { 60 | # root /var/lib/nginx/html; 61 | # } 62 | # error_page 403 /403.html; 63 | # location = /403.html { 64 | # root /var/lib/nginx/html; 65 | # } 66 | # error_page 404 /404.html; 67 | # location = /404.html { 68 | # root /var/lib/nginx/html; 69 | # } 70 | # error_page 500 502 503 504 /50x.html; 71 | # location = /50x.html { 72 | # root /var/lib/nginx/html; 73 | # } 74 | # 75 | # ### Or error can be more strictly handled by returning 444, a non-standard code that closes the connection 76 | # error_page 400 403 404 500 502 503 504 =444 /444.html; 77 | # location = /444.html { 78 | # return 444; 79 | # } 80 | #} 81 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/main.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'main' context directives 3 | 4 | 5 | user nginx nginx; 6 | daemon on; 7 | worker_processes auto; 8 | 9 | error_log /var/log/nginx/error.log info; 10 | 11 | pid /run/nginx/nginx.pid; 12 | 13 | 14 | # Modules 15 | 16 | ## Enables the use of JIT for regular expressions to speed-up their processing 17 | pcre_jit on; 18 | 19 | ## Load dynamic modules 20 | load_module /usr/lib/nginx/modules/ngx_http_modsecurity_module.so; 21 | load_module /usr/lib/nginx/modules/ngx_http_naxsi_module.so; 22 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/stream.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'stream' context directives 3 | # Configuration specific to TCP/UDP and affecting all virtual servers 4 | 5 | 6 | # Global server security settings 7 | 8 | ## --> TLS settings 9 | ### https://nginx.org/en/docs/stream/ngx_stream_ssl_module.html 10 | ssl_protocols TLSv1.2 TLSv1.3; 11 | ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305-D:ECDHE-RSA-CHACHA20-POLY1305-D:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384'; 12 | ssl_session_timeout 20m; 13 | ssl_session_cache shared:ssl_stream_cache:20m; 14 | ssl_dhparam /etc/ssl/dhparams.pem; 15 | ssl_prefer_server_ciphers on; 16 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/conf.d/stream.srv.service2.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # 'stream' context directives 3 | # Configuration specific to TCP/UDP virtual servers and upstreams 4 | 5 | 6 | # DOC: http://nginx.org/en/docs/stream/ngx_stream_core_module.html 7 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/modsec.d/modsec_includes.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX/ModSecurity 2 | # ModSecurity includes directives 3 | # DO NOT MODIFY THIS CONFIGURATION FILE 4 | # PLEASE REFER TO THE DOCUMENTATION FOR FURTHER DETAILS. 5 | 6 | 7 | Include /etc/nginx/modsec.d/modsecurity.conf 8 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/crs-setup.conf 9 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf 10 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf 11 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf 12 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf 13 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9003-NEXTCLOUD-EXCLUSION-RULES.conf 14 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9004-DOKUWIKI-EXCLUSION-RULES.conf 15 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9005-CPANEL-EXCLUSION-RULES.conf 16 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-903.9006-XENFORO-EXCLUSION-RULES.conf 17 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf 18 | # TODO Related to GeoIP 19 | #Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf 20 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf 21 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf 22 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf 23 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf 24 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf 25 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf 26 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf 27 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf 28 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf 29 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-NODEJS.conf 30 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf 31 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf 32 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf 33 | # FIXME nginx: [emerg] "modsecurity_rules_file" directive Rules error. File: /etc/nginx/modsec.d/modsec_includes.conf. Line: 37. Column: 96. /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-JAVA.conf: Not able to open file. 34 | #Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-JAVA.conf 35 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf 36 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf 37 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf 38 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf 39 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf 40 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf 41 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf 42 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf 43 | Include /etc/nginx/modsec.d/owasp-modsecurity-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf 44 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | # sWAF/NGINX 2 | # DO NOT MODIFY THIS CONFIGURATION FILE 3 | # PLEASE REFER TO THE DOCUMENTATION FOR FURTHER DETAILS. 4 | 5 | 6 | # 'main' context configuration file 7 | include conf.d/main.conf; 8 | 9 | events { 10 | # 'events' context configuration file 11 | include conf.d/events.conf; 12 | } 13 | 14 | http { 15 | # 'http' context configuration file 16 | include conf.d/http.conf; 17 | # HTTP servers configuration files 18 | include conf.d/http.srv.*.conf; 19 | } 20 | 21 | stream { 22 | # 'stream' context configuration file 23 | include conf.d/stream.conf; 24 | # Stream (TCP/UDP) servers configuration files 25 | include conf.d/stream.srv.*.conf; 26 | } 27 | -------------------------------------------------------------------------------- /rootfs/opt/swaf/sbin/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # sWAF - A simple Web Application Firewall 3 | # Copyright (C) 2020 styx0x6 4 | 5 | # This file is part of sWAF. This software is licensed under the 6 | # European Union Public License 1.2 (EUPL-1.2), published in Official Journal 7 | # of the European Union (OJ) of 19 May 2017 and available in 23 official 8 | # languages of the European Union. 9 | # The English version is included with this software. Please see the following 10 | # page for all the official versions of the EUPL-1.2: 11 | # https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 12 | 13 | 14 | # Set build args 15 | 16 | ## --> Bootstrap script start time 17 | export BOOTSTRAP_STARTTIME=$(date +%s.%N) 18 | 19 | ## --> sWAF version 20 | ### Alpine image used for this sWAF version 21 | export ALPINE_VER="3.12.0" 22 | 23 | ## --> Packages versions to use 24 | export MODSECURITY_VER="3.0.4" 25 | export CRS_VER="3.3.0" 26 | export NAXSI_VER="1.2" 27 | export LIBRESSL_VER="3.2.2" 28 | export NGINX_VER="1.19.4" 29 | export ACME_VER="2.8.7" 30 | 31 | ## --> ModSecurity paths 32 | export MODSEC_LOG_PATH="/var/log/modsec" 33 | ### Create NGINX and modules folders 34 | mkdir -p ${MODSEC_LOG_PATH} 35 | 36 | ## --> LibreSSL paths & binary name 37 | export LIBRESSL_PREFIX_PATH="/" 38 | export LIBRESSL_EPREFIX_PATH="/usr" 39 | export LIBRESSL_CONFIG_PATH="/etc" 40 | export LIBRESSL_RUN_PATH="/run" 41 | export LIBRESSL_INCLUDE_PATH="${LIBRESSL_EPREFIX_PATH}/include" 42 | export LIBRESSL_DATAROOT_PATH="${LIBRESSL_EPREFIX_PATH}/share" 43 | export LIBRESSL_BIN_NAME="libressl" 44 | 45 | ## --> NGINX paths (including modules configfiles paths) & user/group 46 | export NGINX_PREFIX_PATH="/var/lib/nginx" 47 | export NGINX_SBIN_PATH="/usr/sbin" 48 | export NGINX_MODULES_PATH="/usr/lib/nginx/modules" 49 | export NGINX_ROOT_CONFIG_PATH="/etc/nginx" 50 | export NGINX_CONF_D_CONFIG_PATH="${NGINX_ROOT_CONFIG_PATH}/conf.d" 51 | export NGINX_MODSEC_D_CONFIG_PATH="${NGINX_ROOT_CONFIG_PATH}/modsec.d" 52 | export NGINX_CRS_CONFIG_PATH="${NGINX_MODSEC_D_CONFIG_PATH}/owasp-modsecurity-crs" 53 | export NGINX_NAXSI_D_CONFIG_PATH="${NGINX_ROOT_CONFIG_PATH}/naxsi.d" 54 | export NGINX_RUN_PATH="/run/nginx" 55 | export NGINX_LOCK_PATH="/run/nginx" 56 | export NGINX_LOG_PATH="/var/log/nginx" 57 | export NGINX_CLIENT_BODY_TEMP_PATH="${NGINX_PREFIX_PATH}/tmp/client_body" 58 | export NGINX_PROXY_TEMP_PATH="${NGINX_PREFIX_PATH}/tmp/proxy" 59 | export NGINX_FASTCGI_TEMP_PATH="${NGINX_PREFIX_PATH}/tmp/fastcgi" 60 | export NGINX_UWSGI_TEMP_PATH="${NGINX_PREFIX_PATH}/tmp/uwsgi" 61 | export NGINX_SCGI_TEMP_PATH="${NGINX_PREFIX_PATH}/tmp/scgi" 62 | export NGINX_USER=nginx 63 | export NGINX_GROUP=nginx 64 | ### Create NGINX and related modules folders 65 | mkdir -p ${NGINX_PREFIX_PATH} 66 | mkdir -p ${NGINX_SBIN_PATH} 67 | mkdir -p ${NGINX_MODULES_PATH} 68 | mkdir -p ${NGINX_ROOT_CONFIG_PATH} 69 | mkdir -p ${NGINX_CONF_D_CONFIG_PATH} 70 | mkdir -p ${NGINX_MODSEC_D_CONFIG_PATH} 71 | mkdir -p ${NGINX_CRS_CONFIG_PATH} 72 | mkdir -p ${NGINX_NAXSI_D_CONFIG_PATH} 73 | mkdir -p ${NGINX_RUN_PATH} 74 | mkdir -p ${NGINX_LOCK_PATH} 75 | mkdir -p ${NGINX_LOG_PATH} 76 | mkdir -p ${NGINX_CLIENT_BODY_TEMP_PATH} 77 | mkdir -p ${NGINX_PROXY_TEMP_PATH} 78 | mkdir -p ${NGINX_FASTCGI_TEMP_PATH} 79 | mkdir -p ${NGINX_UWSGI_TEMP_PATH} 80 | mkdir -p ${NGINX_SCGI_TEMP_PATH} 81 | ### Create NGINX running user & group 82 | adduser -D -H -h ${NGINX_PREFIX_PATH} -g "sWAF User" -s /sbin/nologin ${NGINX_USER} ${NGINX_GROUP} 83 | 84 | ## --> acme.sh paths & configuration vars 85 | export ACME_HOME_PATH="/opt/acme" 86 | export ACME_CONFIG_HOME_PATH="${ACME_HOME_PATH}/data" 87 | export ACME_CERT_HOME_PATH="/var/lib/certs" 88 | export ACME_CHAL_ROOT_PATH="/var/lib/acme" 89 | export ACME_CHAL_SUBPATH="${ACME_CHAL_ROOT_PATH}/.well-known/acme-challenge" 90 | # TODO Set ACME_ACC_EMAIL as a variable from bootstrap script args(?) or a config file(?) 91 | #export ACME_ACC_EMAIL="myswaf@example.org" 92 | export ACME_ACC_EMAIL="" 93 | export ACME_ACC_KEY="${ACME_HOME_PATH}/account.key" 94 | export ACME_ACC_CONF="${ACME_HOME_PATH}/account.conf" 95 | export ACME_USERAGENT="acme.sh/${ACME_VER} for sWAF" 96 | ### Create acme.sh folders 97 | mkdir -p ${ACME_HOME_PATH} 98 | mkdir -p ${ACME_CONFIG_HOME_PATH} 99 | mkdir -p ${ACME_CERT_HOME_PATH} 100 | mkdir -p ${ACME_CHAL_ROOT_PATH} 101 | mkdir -p ${ACME_CHAL_SUBPATH} 102 | chown -R ${NGINX_USER}:${NGINX_GROUP} ${ACME_CHAL_ROOT_PATH} 103 | # TODO needed? chmod -R 0555 ${ACME_CHAL_ROOT_PATH} 104 | 105 | 106 | ## --> sWAF paths, configfiles & variables 107 | ### sWAF paths 108 | export SWAF_CONFIGFILES_SRC_PATH="/tmp" 109 | export SWAF_HOME_PATH="/opt/swaf" 110 | export SWAF_BIN_PATH="${SWAF_HOME_PATH}/bin" 111 | export SWAF_BIN_SYMLINK_PATH="/usr/local/bin" 112 | ### sWAF configfiles 113 | export SWAF_DEFAULT_CONFIG_BACKUP_FILE="${SWAF_HOME_PATH}/swaf_def_cnf_bck.tar.gz" 114 | export SWAF_IS_SET_FILE="${SWAF_HOME_PATH}/SWAF_IS_SET" 115 | ### Create sWAF folders 116 | mkdir -p ${SWAF_HOME_PATH} 117 | mkdir -p ${SWAF_BIN_PATH} 118 | 119 | 120 | # Check if this script is run on the proper Alpine version 121 | export $(cat /etc/os-release | grep VERSION_ID) 122 | if [[ $VERSION_ID != $ALPINE_VER ]]; then 123 | echo "Alpine version ${ALPINE_VER} expected. Exiting..." 124 | exit 1 125 | fi 126 | 127 | 128 | # Install system packages 129 | apk update 130 | 131 | ## --> Run packages 132 | # TODO list versions at build into the script report 133 | apk add --no-cache \ 134 | curl \ 135 | git \ 136 | nano \ 137 | `### ModSecurity v3` \ 138 | libcurl \ 139 | libgcc \ 140 | libstdc++ \ 141 | lua \ 142 | yajl \ 143 | `### NGINX - Core` \ 144 | libatomic_ops \ 145 | `### NGINX - Core http_gzip_module` \ 146 | zlib \ 147 | `### NGINX - Core http_rewrite_module + Module NAXSI` \ 148 | pcre \ 149 | `### NGINX - Core http_xslt_module` \ 150 | libxml2 \ 151 | libxslt \ 152 | `### NGINX - Module http_image_filter_module` \ 153 | libgd 154 | ### Turn git detached message off 155 | git config --global advice.detachedHead false 156 | 157 | ## --> Build packages 158 | apk add --no-cache --virtual .tmp-build-tools \ 159 | autoconf \ 160 | automake \ 161 | bison \ 162 | curl-dev \ 163 | file \ 164 | flex \ 165 | gcc \ 166 | g++ \ 167 | gd-dev \ 168 | libatomic_ops-dev \ 169 | libc-dev \ 170 | libtool \ 171 | libxml2-dev \ 172 | libxslt-dev \ 173 | linux-headers \ 174 | lua-dev \ 175 | make \ 176 | openrc \ 177 | pcre-dev \ 178 | pkgconf \ 179 | yajl-dev \ 180 | zlib-dev 181 | 182 | 183 | # Build libraries & tools 184 | 185 | ## --> Build SSDEEP - Needed by ModSecurity v3 186 | cd /tmp 187 | git clone --depth 1 https://github.com/ssdeep-project/ssdeep.git 188 | cd /tmp/ssdeep 189 | ./bootstrap 190 | ./configure 191 | make 192 | make install 193 | make clean 194 | 195 | ## --> Get ModSecurity-nginx connector 196 | cd /tmp 197 | git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git 198 | 199 | ## --> Build ModSecurity v3 200 | cd /tmp 201 | git clone -b v${MODSECURITY_VER} --depth 1 https://github.com/SpiderLabs/ModSecurity.git 202 | cd /tmp/ModSecurity 203 | git submodule init 204 | ### For bindings/python, others/libinjection, test/test-cases/secrules-language-tests 205 | git submodule update 206 | ./build.sh 207 | ./configure \ 208 | --with-ssdeep=/usr/local/lib \ 209 | --enable-examples=no 210 | make 211 | make install 212 | make clean 213 | 214 | ## --> Get NGINX NAXSI module 215 | cd /tmp 216 | curl -SL https://github.com/nbs-system/naxsi/archive/${NAXSI_VER}.tar.gz -o naxsi-${NAXSI_VER}.tar.gz 217 | tar xvfz naxsi-${NAXSI_VER}.tar.gz 218 | 219 | ## --> Build LibreSSL - Needed by NGINX - Modules http_ssl_module + stream_ssl_module 220 | cd /tmp 221 | curl -SLO https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VER}.tar.gz 222 | tar xvfz libressl-${LIBRESSL_VER}.tar.gz 223 | cd /tmp/libressl-${LIBRESSL_VER} 224 | ./configure \ 225 | `### Build options (most default options are based on prefix and exec-prefix):` \ 226 | --prefix=${LIBRESSL_PREFIX_PATH} \ 227 | --exec-prefix=${LIBRESSL_EPREFIX_PATH} \ 228 | `### Other forced paths:` \ 229 | --sysconfdir=${LIBRESSL_CONFIG_PATH} \ 230 | --runstatedir=${LIBRESSL_RUN_PATH} \ 231 | --includedir=${LIBRESSL_INCLUDE_PATH} \ 232 | `### Default doc root path (declined options based on datarootdir):` \ 233 | --datarootdir=${LIBRESSL_DATAROOT_PATH} \ 234 | `### Program name sed substitution:` \ 235 | --program-transform-name="s,openssl,${LIBRESSL_BIN_NAME}," 236 | make 237 | make install 238 | make clean 239 | 240 | ## --> Get NGINX http_geoip2_module 241 | # TODO GEOIP2 to finish 242 | #curl -SL https://github.com/leev/ngx_http_geoip2_module/archive/${GEOIP2_VER}.tar.gz -o ngx_http_geoip2_module-${GEOIP2_VER}.tar.gz 243 | #tar xvfz ngx_http_geoip2_module-${GEOIP2_VER}.tar.gz 244 | 245 | 246 | # Build NGINX 247 | 248 | ## --> Get NGINX sources 249 | cd /tmp 250 | curl -SLO http://nginx.org/download/nginx-${NGINX_VER}.tar.gz 251 | tar xvfz nginx-${NGINX_VER}.tar.gz 252 | 253 | ## --> Build NGINX 254 | cd /tmp/nginx-${NGINX_VER} 255 | ./configure \ 256 | `### Build options:` \ 257 | --prefix=${NGINX_PREFIX_PATH} \ 258 | --sbin-path=${NGINX_SBIN_PATH}/nginx \ 259 | --modules-path=${NGINX_MODULES_PATH} \ 260 | --conf-path=${NGINX_ROOT_CONFIG_PATH}/nginx.conf \ 261 | --pid-path=${NGINX_RUN_PATH}/nginx.pid \ 262 | --lock-path=${NGINX_LOCK_PATH}/nginx.lock \ 263 | --error-log-path=${NGINX_LOG_PATH}/error.log \ 264 | --http-log-path=${NGINX_LOG_PATH}/access.log \ 265 | --http-client-body-temp-path=${NGINX_CLIENT_BODY_TEMP_PATH} \ 266 | --http-proxy-temp-path=${NGINX_PROXY_TEMP_PATH} \ 267 | --http-fastcgi-temp-path=${NGINX_FASTCGI_TEMP_PATH} \ 268 | --http-uwsgi-temp-path=${NGINX_UWSGI_TEMP_PATH} \ 269 | --http-scgi-temp-path=${NGINX_SCGI_TEMP_PATH} \ 270 | --user=${NGINX_USER} \ 271 | --group=${NGINX_GROUP} \ 272 | `### Static modules included by default:` \ 273 | `#http_gzip_module` \ 274 | `#http_charset_module` \ 275 | `#http_ssi_module` \ 276 | `#http_userid_module` \ 277 | `#http_access_module` \ 278 | `#http_auth_basic_module` \ 279 | `#http_mirror_module` \ 280 | `#http_autoindex_module` \ 281 | `#http_geo_module` \ 282 | `#http_map_module` \ 283 | `#http_split_clients_module` \ 284 | `#http_referer_module` \ 285 | `#http_rewrite_module` \ 286 | `#http_proxy_module` \ 287 | --without-http_fastcgi_module \ 288 | `#http_uwsgi_module` \ 289 | --without-http_scgi_module \ 290 | `#http_grpc_module` \ 291 | `#http_memcached_module` \ 292 | `#http_limit_conn_module` \ 293 | `#http_limit_req_module` \ 294 | `#http_empty_gif_module` \ 295 | `#http_browser_module` \ 296 | `#http_upstream_hash_module` \ 297 | `#http_upstream_ip_hash_module` \ 298 | `#http_upstream_least_conn_module` \ 299 | `#http_upstream_keepalive_module` \ 300 | `#http_upstream_zone_module` \ 301 | `#http` \ 302 | `#http-cache` \ 303 | `### Static modules to include in the build:` \ 304 | --with-threads \ 305 | --with-file-aio \ 306 | --with-http_ssl_module \ 307 | --with-http_v2_module \ 308 | --with-http_realip_module \ 309 | --with-http_addition_module \ 310 | --with-http_sub_module \ 311 | --with-http_dav_module \ 312 | --with-http_flv_module \ 313 | --with-http_mp4_module \ 314 | --with-http_gunzip_module \ 315 | --with-http_gzip_static_module \ 316 | --with-http_auth_request_module \ 317 | --with-http_random_index_module \ 318 | --with-http_secure_link_module \ 319 | --with-http_degradation_module \ 320 | --with-http_slice_module \ 321 | --with-http_stub_status_module \ 322 | --with-http_xslt_module \ 323 | --with-http_image_filter_module \ 324 | `# TODO GeoIP2 used instead: https://docs.nginx.com/nginx/admin-guide/dynamic-modules/geoip/` \ 325 | `#--with-http_geoip_module` \ 326 | --with-stream \ 327 | `#stream_limit_conn_module` \ 328 | `#stream_access_module` \ 329 | `#stream_geo_module` \ 330 | `#stream_map_module` \ 331 | `#stream_split_clients_module` \ 332 | `#stream_return_module` \ 333 | `#stream_upstream_hash_module` \ 334 | `#stream_upstream_least_conn_module` \ 335 | `#stream_upstream_zone_module` \ 336 | --with-stream_ssl_module \ 337 | --with-stream_realip_module \ 338 | --with-stream_ssl_preread_module \ 339 | `# TODO geoip? use geoip2` \ 340 | `#--with-stream_geoip_module` \ 341 | `### Dynamic modules included in the build:` \ 342 | --add-dynamic-module=/tmp/ModSecurity-nginx \ 343 | --add-dynamic-module=/tmp/naxsi-${NAXSI_VER}/naxsi_src \ 344 | `# TODO GEOIP2` \ 345 | `#--add-dynamic-module=/tmp/ngx_http_geoip2_module-${GEOIP2_VER}` \ 346 | `# no mail proxy modules` \ 347 | `# no google_perftools_module` \ 348 | `# no cpp_test_module` \ 349 | `# no http_perl_module` \ 350 | `### Force default options:` \ 351 | --with-pcre \ 352 | --with-pcre-jit `# pcre Alpine package is compiled with JIT: https://build.alpinelinux.org/buildlogs/build-edge-x86_64/main/pcre/pcre-8.44-r0.log` \ 353 | `### Set additional options:` \ 354 | --with-compat `# Enables dynamic modules compatibility` \ 355 | --with-libatomic `# Forces the libatomic_ops library usage` \ 356 | --with-openssl=/tmp/libressl-${LIBRESSL_VER} `# Set LibreSSL as the SSL library to compile with` \ 357 | --with-openssl-opt=enable-tls1_3 `# Ensure TLS 1.3 support` \ 358 | --with-debug `# Include debug logging capacity` 359 | make 360 | make modules 361 | make install 362 | make clean 363 | 364 | 365 | # Install acme.sh 366 | 367 | ## --> Get acme.sh sources 368 | cd /tmp 369 | curl -SL https://github.com/acmesh-official/acme.sh/archive/${ACME_VER}.tar.gz -o acme.sh-${ACME_VER}.tar.gz 370 | tar xvfz acme.sh-${ACME_VER}.tar.gz 371 | 372 | ## --> Install acme.sh 373 | cd /tmp/acme.sh-${ACME_VER} 374 | ### FIXME Use --openssl-bin instead 375 | ### Patch acme.sh script with LibreSSL which is retrocompatible with OpenSSL and used here in sWAF 376 | sed -i 's|DEFAULT_OPENSSL_BIN="openssl"|DEFAULT_OPENSSL_BIN="libressl"|' /tmp/acme.sh-${ACME_VER}/acme.sh 377 | ### FIXME Hard-coded into acme.sh 378 | ### Patch acme.sh script with LibreSSL instead of OpenSSL calls hard-coded twice 379 | sed -i 's|openssl x509 -noout -text -in "$_cf"|libressl x509 -noout -text -in "$_cf"|' /tmp/acme.sh-${ACME_VER}/acme.sh 380 | sed -i 's|openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1|libressl x509 -noout -text -in "$_cf" >/dev/null 2>&1|' /tmp/acme.sh-${ACME_VER}/acme.sh 381 | ### Install acme.sh 382 | ./acme.sh --install \ 383 | `#### Install options:` \ 384 | --noprofile \ 385 | --home ${ACME_HOME_PATH} \ 386 | --config-home ${ACME_CONFIG_HOME_PATH} \ 387 | `#### FIXME https://github.com/acmesh-official/acme.sh/issues/3153` 388 | --cert-home ${ACME_CERT_HOME_PATH} \ 389 | --accountemail "${ACME_ACC_EMAIL}" \ 390 | --accountkey ${ACME_ACC_KEY} \ 391 | --accountconf ${ACME_ACC_CONF} \ 392 | --useragent "${ACME_USERAGENT}" 393 | ### FIXME Why header is changed?? 394 | ### Patch acme.sh script header back to the default shell call 395 | sed -i 's|#!/bin/bash|#!/usr/bin/env sh|' ${ACME_HOME_PATH}/acme.sh 396 | 397 | ## --> Set acme.sh reachable from standard PATH 398 | ln -s ${ACME_HOME_PATH}/acme.sh ${SWAF_BIN_SYMLINK_PATH}/acme.sh 399 | 400 | 401 | # Prepare configuration files 402 | 403 | ## --> NGINX configuration files 404 | cd /tmp 405 | ### Copy sWAF's NGINX configuration files 406 | ### Related to copied files in Dockerfile 407 | cp ${SWAF_CONFIGFILES_SRC_PATH}/nginx.conf ${NGINX_ROOT_CONFIG_PATH}/nginx.conf 408 | cp ${SWAF_CONFIGFILES_SRC_PATH}/main.conf ${NGINX_CONF_D_CONFIG_PATH}/main.conf 409 | cp ${SWAF_CONFIGFILES_SRC_PATH}/events.conf ${NGINX_CONF_D_CONFIG_PATH}/events.conf 410 | cp ${SWAF_CONFIGFILES_SRC_PATH}/http.conf ${NGINX_CONF_D_CONFIG_PATH}/http.conf 411 | cp ${SWAF_CONFIGFILES_SRC_PATH}/stream.conf ${NGINX_CONF_D_CONFIG_PATH}/stream.conf 412 | cp ${SWAF_CONFIGFILES_SRC_PATH}/http.srv.service1.conf.example ${NGINX_CONF_D_CONFIG_PATH}/http.srv.service1.conf.example 413 | cp ${SWAF_CONFIGFILES_SRC_PATH}/stream.srv.service2.conf.example ${NGINX_CONF_D_CONFIG_PATH}/stream.srv.service2.conf.example 414 | ### Create related 'default' files 415 | cp ${NGINX_CONF_D_CONFIG_PATH}/main.conf ${NGINX_CONF_D_CONFIG_PATH}/main.conf.default 416 | cp ${NGINX_CONF_D_CONFIG_PATH}/events.conf ${NGINX_CONF_D_CONFIG_PATH}/events.conf.default 417 | cp ${NGINX_CONF_D_CONFIG_PATH}/http.conf ${NGINX_CONF_D_CONFIG_PATH}/http.conf.default 418 | cp ${NGINX_CONF_D_CONFIG_PATH}/stream.conf ${NGINX_CONF_D_CONFIG_PATH}/stream.conf.default 419 | 420 | ## --> NGINX default HTML pages 421 | cd /tmp 422 | ### Copy sWAF's NGINX default HTML pages 423 | ### Related to copied files in Dockerfile 424 | cp -f ${SWAF_CONFIGFILES_SRC_PATH}/index.html ${NGINX_PREFIX_PATH}/html/index.html 425 | cp -f ${SWAF_CONFIGFILES_SRC_PATH}/403.html ${NGINX_PREFIX_PATH}/html/403.html 426 | cp -f ${SWAF_CONFIGFILES_SRC_PATH}/404.html ${NGINX_PREFIX_PATH}/html/404.html 427 | cp -f ${SWAF_CONFIGFILES_SRC_PATH}/50x.html ${NGINX_PREFIX_PATH}/html/50x.html 428 | 429 | ## --> ModSecurity configuration files 430 | cd /tmp 431 | ### Copy ModSecurity 'default' files 432 | cp /tmp/ModSecurity/modsecurity.conf-recommended ${NGINX_MODSEC_D_CONFIG_PATH}/modsecurity.conf 433 | cp /tmp/ModSecurity/unicode.mapping ${NGINX_MODSEC_D_CONFIG_PATH}/unicode.mapping 434 | ### Copy sWAF's ModSecurity configuration files 435 | ### Related to copied files in Dockerfile 436 | cp ${SWAF_CONFIGFILES_SRC_PATH}/modsec_includes.conf ${NGINX_MODSEC_D_CONFIG_PATH}/modsec_includes.conf 437 | 438 | ## --> OWASP Core Rule Set 439 | cd ${NGINX_CRS_CONFIG_PATH} 440 | ### Get CRS 441 | curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_VER}.tar.gz -o coreruleset-${CRS_VER}.tar.gz 442 | tar xvfz coreruleset-${CRS_VER}.tar.gz 443 | ### Copy files 444 | cp coreruleset-${CRS_VER}/crs-setup.conf.example crs-setup.conf 445 | cp -R coreruleset-${CRS_VER}/rules rules 446 | cp coreruleset-${CRS_VER}/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf 447 | cp coreruleset-${CRS_VER}/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf 448 | cp -R coreruleset-${CRS_VER}/util util 449 | ### Clean 450 | rm -f coreruleset-${CRS_VER}.tar.gz 451 | 452 | ## --> NAXSI configuration files 453 | cd /tmp 454 | cp /tmp/naxsi-${NAXSI_VER}/naxsi_config/naxsi_core.rules ${NGINX_NAXSI_D_CONFIG_PATH}/naxsi_core.rules 455 | 456 | 457 | # Tuning 458 | cd /tmp 459 | export CF_MODSECURITY=${NGINX_MODSEC_D_CONFIG_PATH}/modsecurity.conf 460 | 461 | ## --> modsecurity.conf 462 | sed -i "s|SecRuleEngine DetectionOnly|SecRuleEngine On|" ${CF_MODSECURITY} 463 | sed -i "s|SecAuditLog /var/log/modsec_audit.log|SecAuditLog ${MODSEC_LOG_PATH}/modsec_audit.log|" ${CF_MODSECURITY} 464 | sed -i "s|SecUnicodeMapFile unicode.mapping 20127|SecUnicodeMapFile /etc/nginx/modsec.d/unicode.mapping 20127|" ${CF_MODSECURITY} 465 | # TODO Tune more modsecurity.conf 466 | #sed -i 's|SecAuditLogType Serial|SecAuditLogType Concurrent|' ${CF_MODSECURITY} 467 | #Specify the path for concurrent audit logging. 468 | #SecAuditLogStorageDir /opt/modsecurity/var/audit/ 469 | # TODO Check SecServerSignature to empty it by default 470 | 471 | ## --> crs-setup.conf 472 | # TODO Tune crs-setup.conf 473 | # TODO Tune below files that will allow to add exceptions without updates overwriting them in the future. 474 | # TODO Tune rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf 475 | # TODO Tune rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf 476 | 477 | 478 | # Set sWAF global configuration 479 | echo "Preparing sWAF global configuration..." 480 | 481 | ## --> Package sWAF core configuration (NGINX) 482 | cd ${NGINX_ROOT_CONFIG_PATH} 483 | tar cz -f ${SWAF_DEFAULT_CONFIG_BACKUP_FILE} -C ${NGINX_ROOT_CONFIG_PATH} . 484 | 485 | ## --> Set sWAF installation state 486 | echo "0" > ${SWAF_IS_SET_FILE} 487 | 488 | ## --> Copy sWAF motd 489 | ### Related to copied files in Dockerfile 490 | cp ${SWAF_CONFIGFILES_SRC_PATH}/motd /etc/motd 491 | 492 | 493 | # Clean 494 | cd / 495 | 496 | ## --> Remove build tools 497 | apk del .tmp-build-tools 498 | 499 | ## --> Delete cache and build files 500 | rm -rf /var/cache/apk/* 501 | rm -rf /tmp/* 502 | 503 | 504 | # Outro 505 | 506 | ## --> sWAF Bootstrap Script Report 507 | echo -e "\n\n" 508 | echo "------------========================================------------" 509 | echo "sWAF Bootstrap Script Report" 510 | echo 511 | echo "--> Build done." 512 | echo "--> Script Execution Time: $(date -d@$(echo "$(date +%s.%N) - ${BOOTSTRAP_STARTTIME}" | bc) -u +%Hh\ %Mm\ %Ss)" 513 | echo 514 | echo "--> LibreSSL details:" 515 | echo "> # libressl version -a" 516 | libressl version -a 517 | echo 518 | echo "--> NGINX details:" 519 | echo "> # nginx -V" 520 | nginx -V 521 | echo 522 | echo "--> acme.sh details:" 523 | echo "> # acme.sh -v" 524 | acme.sh -v 525 | echo "> # crontab -l" 526 | crontab -l 527 | echo "------------========================================------------" 528 | echo -e "\n\n" 529 | -------------------------------------------------------------------------------- /rootfs/opt/swaf/sbin/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # sWAF - A simple Web Application Firewall 3 | # Copyright (C) 2020 styx0x6 4 | 5 | # This file is part of sWAF. This software is licensed under the 6 | # European Union Public License 1.2 (EUPL-1.2), published in Official Journal 7 | # of the European Union (OJ) of 19 May 2017 and available in 23 official 8 | # languages of the European Union. 9 | # The English version is included with this software. Please see the following 10 | # page for all the official versions of the EUPL-1.2: 11 | # https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 12 | 13 | 14 | # Show header 15 | cat /etc/motd 16 | 17 | # Deploy /etc/nginx after potentially mounted volume 18 | if [[ $(cat /opt/swaf/SWAF_IS_SET) == 0 ]]; then 19 | echo "+ Deploying sWAF configuration..." 20 | tar xz -f /opt/swaf/swaf_def_cnf_bck.tar.gz -C /etc/nginx 21 | echo "+ Generating DH parameters for DHE ciphers..." 22 | libressl dhparam -out /etc/ssl/dhparams.pem -dsaparam 4096 23 | echo "+ Configuring container..." 24 | echo "1" > /opt/swaf/SWAF_IS_SET 25 | fi 26 | 27 | # Let's go 28 | echo "+ Starting sWAF..." 29 | /usr/sbin/nginx 30 | /bin/sh 31 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/html/400.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 400 Bad Request 5 | 6 | 7 |

400 Bad Request

8 | 9 | 10 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/html/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 |

403 Forbidden

8 | 9 | 10 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/html/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 Not Found 5 | 6 | 7 |

404 Not Found

8 | 9 | 10 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/html/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 |

An error occurred.

8 |

9 | Sorry, the page you are looking for is currently unavailable.
10 |
11 | Please try again later. 12 |

13 | 14 | 15 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome to sWAF 5 | 11 | 12 | 13 |

Welcome to sWAF

14 |

15 | Your sWAF's NGINX service is up and running. 16 |

17 |

18 | Further configuration is required and this page must be deactivated now.
19 | Please follow the sWAF documentation for further details. 20 |

21 | 22 | 23 | --------------------------------------------------------------------------------