LoveDuckie

Securing HTTP Headers with NGINX in Docker

Securing HTTP Headers with NGINX in Docker

Securing HTTP Headers with NGINX in Docker

Securing HTTP Headers with NGINX in Docker

Updated 3 years ago
7 Minute(s) to read
Posted 3 years ago Updated 3 years ago 7 Minute(s) to read 30 comments

Nginx, stylized as NGINX, nginx or NginX, is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. More typically it is the web server of choice for most applications and APIs targeting the web. Like other popular web servers, NGINX tends to emit more data than necessary when serving HTTP requests when using the default configuration, which in turn can make it susceptible to (zero day) exploits.

An example of what is meant can be found in the image below.

HTTP headers from our page response using Google Chrome's developer tools.

HTTP headers from our page response using Google Chrome's developer tools.

This is the emitted response from navigating to any page on this website when using the default configuration. This is not ideal, as hackers or penetration testers can use automated tools for scanning and detecting websites that have potential vulnerabilities.

This article will cover some steps that you can take for securing the HTTP responses that your NGINX server emits when using the Alpine Linux version of the Docker image.

This article assumes that you have appropriately configured your development environment for usage with Docker's BuildKit features.


Extending NGINX

 In the root of your project, create the following directory layout.

containers/
- nginx/
-- build/
--- Dockerfile
-- configuration/
--- templates/
docker-compose.yaml
.env

Your docker-compose.yaml should look something like this...

version: '3.9'

services:
  nginx:
    container_name: '${SERVICE_NAME}-nginx'
    image: '${REMOTE_REGISTRY_HOST}${SERVICE_NAME}/nginx:${BUILD_VERSION}'
    build: 
      context: '${BUILD_ROOT}' 
      dockerfile: '${CONTAINERS_ROOT}/nginx/build/Dockerfile'
      target: portfolio-nginx-build
      args:
        NGINX_VERSION: ${NGINX_VERSION}
        NGINX_HEADERS_MORE_VERSION: ${NGINX_HEADERS_MORE_VERSION}
    environment:
      NGINX_ENVSUBST_TEMPLATE_DIR: /etc/nginx/templates
      NGINX_ENVSUBST_OUTPUT_DIR: /etc/nginx/conf.d
      NGINX_ENVSUBST_TEMPLATE_SUFFIX: .template

Your .env file should look something like this...

SERVICE_NAME=your-service-name-goes-here
COMPOSE_PROJECT_NAME=${SERVICE_NAME}
BUILD_ROOT=${PWD}
PROJECT_ROOT=${PWD}
CONTAINERS_ROOT=${PROJECT_ROOT}/containers

So far, so good, and nothing out of the ordinary either.

Dockerfile

Keep in mind that this article assumes that you are intending on using the Alpine Linux flavour or variant of NGINX's Docker image. It's significantly smaller in size, as the operating system variant comes typically bundled with far less system utilities and running services. The Linux variant is typically used in embedded systems for the same reasoning.

The beginning of our Dockerfile is nothing out of the ordinary. It provides 3 arguments that are used for describing this particular flavour of the image, which are

  • CUSTOM_BUILD_VERSION
  • CUSTOM_BUILD_DATE
  • CUSTOM_BUILD_UID

These are ideal if you are generating the Docker images as part of your continuous integration or build pipeline. At the time of writing this article, we are using version 1.20.1 of NGINX, which is compatible with version 0.33 of the Headers More plugin.

In addition, our Dockerfile "parameterises" the version numbers used for retrieving the correct version of NGINX and Headers More. 

ARG CUSTOM_BUILD_VERSION
ARG CUSTOM_BUILD_DATE
ARG CUSTOM_BUILD_UID

ARG NGINX_VERSION 1.20.1

FROM nginx:${NGINX_VERSION}-alpine AS builder

ARG CUSTOM_BUILD_VERSION
ARG CUSTOM_BUILD_DATE
ARG CUSTOM_BUILD_UID

ARG NGINX_VERSION 1.20.1
ARG NGINX_HEADERS_MORE_VERSION 0.33

Next, we are going to have to download the source files for both NGINX and the Headers More plugin.

RUN wget "http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" -O nginx.tar.gz && \
    wget "https://github.com/openresty/headers-more-nginx-module/archive/v${NGINX_HEADERS_MORE_VERSION}.tar.gz" -O headers-more.tar.gz

This is necessary as we have to produce a local build of NGINX that integrates Headers More as a dynamic module. Therefore this means that we need to ensure that Alpine Linux has the GCC compiler toolchain available, along with make tool and some additional packages.

RUN apk add --no-cache --virtual .build-deps \
  git \
  gcc \
  libc-dev \
  make \
  openssl-dev \
  pcre-dev \
  zlib-dev \
  linux-headers \
  curl \
  gnupg \
  libxslt-dev \
  gd-dev \
  geoip-dev

This bit consists of preparing the compilation environment for NGINX, including adjusting environment variables used by the compilation toolchain.

RUN mkdir -p /usr/src

# Reuse same cli arguments as the nginx:alpine image used to build
RUN CONFARGS=$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p') \
	tar -zxC /usr/src -f "nginx.tar.gz"

RUN tar -zxvC /usr/src -f "headers-more.tar.gz" 

RUN HEADERSMOREDIR="/usr/src/headers-more-nginx-module-0.33" && \
  cd /usr/src/nginx-$NGINX_VERSION && \
  ./configure --without-http_autoindex_module --with-compat $CONFARGS --add-dynamic-module=$HEADERSMOREDIR && \
  make && make install

This does the following:

  1. Uses the tool sed to search and replace part of the string output from invoking nginx -V in the shell.
    1. The output from nginx -V displays the switch parameters used for compiling NGINX and configuring make.
    2. It makes use of the output generated, while appending our additional module (which is Headers More).
  2. Extracts the contents of the Headers More plugin that we downloaded in our previous snippet.
  3. Defines a variable pointing to the path where Headers More has been extracted to
  4. Runs make.

In this next stage, we finally make use of the generated build output after downloading and building NGINX and Headers More together. We make use of a feature in Docker called "multi-stage" builds, which enables us to copy the contents from another stage of a build. This approach to generating Docker images is considered to be significantly more efficient, as it enables us to reuse cached stages when rebuilding the Docker image, or making iterative changes.

FROM nginx:${NGINX_VERSION}-alpine as your-service-name-goes-here-nginx

# Extract the dynamic module "headers more" from the builder image
COPY --from=builder /usr/local/nginx/modules/ngx_http_headers_more_filter_module.so /usr/local/nginx/modules/ngx_http_headers_more_filter_module.so

The rest of the Dockerfile definition is entirely up to you. Depending on the flavour of the build (i.e. development or production), you can choose to copy or include other files that you would find useful in that particular flavour of the build.

You can find the complete Dockerfile constructed in this article here.


Configuration

Now that you have a working Dockerfile definition for your NGINX image, we can now configure how the NGINX server will behave. The intent behind this configuration is to ensure that we are not sending more data that necessary in our HTTP responses. Using the Headers More extension that we downloaded, compiled, included as part of our NGINX Dockerfile, we can now prepare a NGINX server block configuration that can remove headers using the appropriate syntax.

The Headers More extension makes the more_clear_headers command available for us to use, meaning that we can now remove headers that are added by default by the NGINX web server.

more_clear_headers 'Server';
more_clear_headers 'X-Powered-By';

A more complete example would look like this. Find below an example root nginx.conf configuration file.

# Load in the headers more module
load_module /usr/local/nginx/modules/ngx_http_headers_more_filter_module.so;

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {

    more_clear_headers 'Server';
    more_clear_headers 'X-Powered-By';

    server_tokens off;

    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;


    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

This configuration ensures that all HTTP responses served, regardless of which server blocks you have configured, will have the X-Powered-By and Server headers stripped from the HTTP response. Handy!

Now you can rest assured that visitors will be none-the-wiser about which kind of software you are using for serving your web applications, and thus mitigating the ability for a malicious visitor to find or target exploits in your software stack.


Further Reading

You might find these links interesting if you wish to take further steps to mitigate security vulnerabilities on your web application.


Programming Languages:

Shell Script Bash Dockerfile

Technologies:

NGINX Docker


Comments

Comments


Helpful stuff. With thanks.
<a href="https://essaywritingservicelinked.com/">cheap custom essay writing service</a> fast essay writing service <a href="https://essaywritingservicetop.com/">top essay writing</a> what is the best essay writing service
<a href=https://argumentativethesis.com/>phd thesis database</a> a good thesis statement <a href=https://bestmasterthesiswritingservice.com/>thesis statement</a> thesis
college goals essay https://studentessaywriting.com

You expressed this exceptionally well.
<a href="https://studentessaywriting.com/">last minute essay writing service</a> professional essay writers <a href="https://essaywritingserviceahrefs.com/">buy essay writing service</a> legit essay writing services


Truly lots of great facts!
<a href="https://payforanessaysonline.com/">order essay</a> where to buy essays online <a href="https://buycheapessaysonline.com/">essays for sale</a> order essay online

You actually expressed it effectively!
<a href="https://essaytyperhelp.com/">cheap essay help</a> essay writing service <a href="https://helptowriteanessay.com/">free writing assistant</a> argumentative essay
<a href=https://theessayswriters.com/>essay writers</a> make an essay <a href=https://bestcheapessaywriters.com/>write an essay for me</a> write my essay for free
cheap essay writers https://essayservicehelp.com


Thank you! Lots of posts!
<a href="https://payforanessaysonline.com/">pay for essay</a> pay for papers <a href="https://buycheapessaysonline.com/">pay for essays</a> pay for an essay


Truly a lot of excellent data!
<a href="https://writingpaperforme.com/">pay someone to write your paper</a> write a paper for me <a href="https://custompaperwritersservices.com/">online essay writer</a> write a paper
<a href=https://phdthesisdissertation.com/>dissertation abstracts</a> dissertation definition <a href=https://writeadissertation.com/>dissertation definition</a> dissertation editing
write college essays https://domyhomeworkformecheap.com


With thanks! I enjoy it.
<a href="https://domyhomeworkformecheap.com/">do my homework for free</a> do my finance homework <a href="https://domycollegehomeworkforme.com/">coursework</a> do my finance homework
<a href=https://ouressays.com/>research paper services</a> research proposal <a href=https://researchpaperwriterservices.com/>proposal writer</a> proposal essay
best college application essay service https://cheapessaywriteronlineservices.com


Good info. Thanks!
<a href="https://topswritingservices.com/">essay writing tips</a> coursework writing service <a href="https://essaywriting4you.com/">my essay service</a> my essay service


Useful forum posts. Cheers.
<a href="https://essaywritingservicehelp.com/">personal statement writing service</a> cheap essay writing service us <a href="https://essaywritingservicebbc.com/">college papers writing service</a> writing a college admission essay
<a href=https://homeworkcourseworkhelps.com/>pay to do my homework</a> i don t want to do my homework <a href=https://helpmedomyxyzhomework.com/>do my homework for free</a> coursework
dissertation writing software https://essaywritingservicehelp.com


Beneficial stuff. Thanks!
<a href="https://helpwithdissertationwriting.com/">dissertation proposal</a> writing dissertation <a href="https://dissertationwritingtops.com/">best dissertation</a> writing help