diff --git a/README.md b/README.md index bdf3cad..752b7b6 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Available at [`ricardbejarano/nginx`](https://hub.docker.com/r/ricardbejarano/ng * Built `FROM scratch`, see the [Filesystem](#Filesystem) section below for an exhaustive list of the image's contents * Included [TLS1.3](https://tools.ietf.org/html/rfc8446) protocol support (with [OpenSSL](https://www.openssl.org/)) * Reduced attack surface (no `bash`, no UNIX tools, no package manager...) +* Built with exploit mitigations enabled (see [Security](#Security)) ## Building @@ -40,6 +41,62 @@ $ docker build -t nginx:musl -f musl/Dockerfile . ``` +## Security + +This image attempts to build a secure NGINX Docker image. + +It does so by the following ways: + +- downloading and verifying the source code of NGINX and every library it is built with, +- packaging the image with only those files required during runtime (see [Filesystem](#Filesystem)), +- by enforcing a series of exploit mitigations (PIE, full RELRO, full SSP, NX and Fortify) + +### Verifying the presence of exploit mitigations + +To check whether a binary in a Docker image has those mitigations enabled, use [tests/checksec.sh](https://github.com/ricardbejarano/nginx/blob/master/tests/checksec.sh). + +#### Usage + +``` +usage: checksec.sh docker_image executable_path + +Docker-based wrapper for checksec.sh. +Requires a running Docker daemon. + +Example: + + $ checksec.sh ricardbejarano/nginx:glibc /nginx + + Extracts the '/nginx' binary from the 'ricardbejarano/nginx:glibc' image, + downloads checksec (github.com/slimm609/checksec.sh) and runs it on the + binary. + Everything runs inside Docker containers. +``` + +#### Example: + +Testing the `/nginx` binary in `ricardbejarano/nginx:glibc`: + +``` +$ bash tests/checksec.sh ricardbejarano/nginx:glibc /nginx +Downloading ricardbejarano/nginx:glibc...Done! +Extracting ricardbejarano/nginx:glibc:/nginx...Done! +Downloading checksec.sh...Done! +Running checksec.sh: +RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE +Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH 11563 Symbols Yes 0 34 /tmp/.checksec-ui8eKi3Q +Cleaning up...Done! +``` + +This wrapper script works with any binary in a Docker image. Feel free to use it with any other image. + +Other examples: + +- `bash tests/checksec.sh debian /bin/bash` +- `bash tests/checksec.sh alpine /bin/sh` +- `bash tests/checksec.sh nginx /usr/sbin/nginx` + + ## Filesystem The images' contents are: diff --git a/tests/checksec.sh b/tests/checksec.sh new file mode 100644 index 0000000..95ecd95 --- /dev/null +++ b/tests/checksec.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +usage() { + echo "usage: checksec.sh docker_image executable_path" + echo "" + echo "Docker-based wrapper for checksec.sh." + echo "Requires a running Docker daemon." + echo "" + echo "Example:" + echo "" + echo " $ checksec.sh ricardbejarano/nginx:glibc /nginx" + echo "" + echo " Extracts the '/nginx' binary from the 'ricardbejarano/nginx:glibc' image," + echo " downloads checksec (github.com/slimm609/checksec.sh) and runs it on the" + echo " binary." + echo " Everything runs inside Docker containers." + exit 1 +} + +checksec() { + printf "Downloading $1..." + docker pull "$1" >/dev/null + echo "Done!" + + printf "Extracting $1:$2..." + image_container="$(docker create "$1")" + executable_file="$(mktemp .checksec-XXXXXXXX)" + docker cp "$image_container":"$2" "$executable_file" + docker rm "$image_container" >/dev/null + echo "Done!" + + printf "Downloading checksec.sh..." + docker run \ + --interactive \ + --tty \ + --rm \ + --volume "$PWD/$executable_file":"/tmp/$executable_file" \ + debian \ + bash \ + -c "\ + apt update &>/dev/null && \ + apt install -y curl file procps binutils openssl &>/dev/null && \ + curl \ + --silent \ + --show-error \ + --output /bin/checksec \ + https://raw.githubusercontent.com/slimm609/checksec.sh/master/checksec && \ + chmod +x /bin/checksec && \ + echo 'Done!' && \ + echo 'Running checksec.sh:' && \ + checksec -f /tmp/$executable_file" + + printf "Cleaning up..." + rm -f "$executable_file" + echo "Done!" + + exit 0 +} + +if [ -z "$2" ]; then usage; fi +checksec "$1" "$2"