<< Back to Blog

How to hide sensitive POST data in NGINX log

NGINX is an extremely popular web server that can handle high volumes of web traffic. Each client connection might be logged and you can control which information to store. Sometimes, it is essential not only to save remote IP address, user agent or status but also store a body of requests, especially POST requests. For instance, POST data can be really useful to be analysed if you want to ensure that your server is secured enough because the most of the attacks are sent by this type of HTTP requests. However, some POST headers may contain sensitive data such as passwords and therefore it is essential to have a making method.

To log a request body, we need to use the echo_read_request_body command and the $request_body variable which is initialized by the Echo module. Then split the variable into two using a regex to filter the sensitive data. It is possible to do it by using the ngx_http_map_module module.

To install the Echo module on Debian or Ubuntu server use the following command:
apt-get install nginx-full

It contains the Echo and the Map modules. I skip the procedure of installation of any web application you may have and show how it can be configured for Wordpress which is one of the most popular CMS platforms.

To configure NGINX, firstly, add the 'echo_read_request_body' command to a location context of the site, for instance, Wordpress, in /etc/nginx/conf.d/default.conf:

location ~ \.php$ {
root /var/www/html;
fastcgi_index index.php;
include fastcgi_params;
access_log /var/log/nginx/access.log logreqbody;

Let assume that we have to hide the parameter named 'pwd' which is actually used to send a user password by submitting the login form of the Wordpress application. Our aim is to split $request_body variable into $req_body_start variable, which contains all data before the '&pwd=' string, and the $req_body_end variable, which filled with the data after the '&pwd=' string if it exists. Additionally, we need to replace the password with the '[FILTERED]' string. To do so, we need to modify the file /etc/nginx/nginx.conf:

map $request_body $req_body_start {
"~(?.*)\&pwd=[^\&]*.+" $nopwd;
default $request_body;

map $request_body $req_body_end {
"~.*\&pwd=[^\&]*(?.+)" $nopwd1;
default '';

map $request_body $req_body_pwd {
"~.*\&pwd=[^\&]*.+" '&pwd=[FILTERED]';
default '';

Then it is possible to define the log format with data masking:

log_format logreqbody '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$req_body_start$req_body_pwd$req_body_end"';

The log entry without masking will be: - - [17/Sep/2016:00:58:42 +0300] "POST /wp-login.php HTTP/1.1" 200 1554 "http://www.example.com/wp-login.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-" "log=admin&pwd=12345678&wp-submit=Log+In&redirect_to=http:%2F%2Flocalhost%2Fwp-admin%2F&testcookie=1"

The filtered log entry will be: - - [17/Sep/2016:00:58:42 +0300] "POST /wp-login.php HTTP/1.1" 200 1554 "http://www.example.com/wp-login.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-" "log=admin&pwd=[FILTERED]&wp-submit=Log+In&redirect_to=http:%2F%2Flocalhost%2Fwp-admin%2F&testcookie=1"

You should now have POST parameters logging enabled and sure that sensible data is scrubbled. Experiment with the configuration files to find out what works best for you.

Posted on September 18, 2016 by Yury Sergeev