NGINX.COM

Virtual patching refers to fixing a problem with application code by making a change to related infrastructure rather than the code itself. In the security realm, it’s common to use ModSecurity to virtually patch a vulnerability, for example. But virtual patching can be applied to other types of bugs as well, such as the bugs in backend applications we often encounter in production environments. For various reasons it can be challenging to fix these bugs directly (for example, if the original developer has left the company) and virtual patching is a practical alternative.

An NGINX Plus customer recently experienced an unusual issue: a client‑side app was making GET and POST requests in lowercase (as get and post). The backend application was expecting uppercase, as specified by RFC 7231 section 4.1, and so could not process the requests. The customer had no way to modify the backend application code.

Working with our award‑winning support team, the customer developed a virtual patch that uses the NGINX JavaScript module to convert lowercase get and post to uppercase GET and POST before NGINX Plus proxies the request to the backend application. The NGINX JavaScript module enables you to use JavaScript to perform advanced configurations, with both our open source and commercial offerings. For ease of reading, this post refers to NGINX Plus, but it also applies to NGINX Open Source.

[Editor – This post is one of several that explore use cases for the NGINX JavaScript module. For a complete list, see Use Cases for the NGINX JavaScript Module.]

Creating the Virtual Patch

The virtual patch works by adding a new TCP/UDP virtual server in front of the existing HTTP virtual server that’s proxying traffic to the unmodifiable backend application. TCP/UDP virtual servers (in the stream{} context) can filter content using the NGINX JavaScript module.

For this blog we are employing the conventional scheme for reading function‑specific configuration and JavaScript code into the http{} and stream{} contexts with include directives in the main configuration file, /etc/nginx/nginx.conf:

http {
    include conf.d/*.conf;
    include conf.d/*.js;
}

stream {
    include stream.d/*.conf;
    include stream.d/*.js;
}

Then create the conf.d and stream.d subdirectories in /etc/nginx and place function‑specific .conf and .js files there, for HTTP and TCP/UDP respectively.

Alternatively, you can place the directives directly in nginx.conf. In that case, make sure to place the snippets in the http{} or stream{} block as appropriate.

TCP/UDP Configuration for the Virtual Patch

To read the JavaScript code into the NGINX Plus configuration, we name it with the js_include directive in the stream{} block, on line 2 below. (For an analysis of the JavaScript code, see JavaScript Code for the Virtual Patch below.)

We define a new virtual server (lines 3–11) and invoke the JavaScript function with the js_filter directive (line 8). NGINX Plus proxies the converted request to the HTTP virtual server listening on port 81 (line 9). We enable the PROXY protocol (line 10) so that NGINX Plus can pass the original client IP address through to the HTTP virtual server.

HTTP Configuration for the Virtual Patch

We also modify the existing HTTP virtual server that handles requests made to the backend application, to listen on port 81 and to use the PROXY protocol (line 3), again so that the original client IP address is passed through.

JavaScript Code for the Virtual Patch

We put the following JavaScript code for the virtual patch in a file called methods.js in the /etc/nginx/stream.d directory. It converts requests that use lowercase get and post requests to use uppercase GET and POST.

The variable s (line 5) captures all the relevant information in the client request. The code skips past the end of the PROXY protocol header in the request, then captures chunked user data (up to the newline at the end of the request line) and writes it to the req variable.

The virtual patch uses a PCRE‑style regular expression (line 18) to convert the method name to uppercase and capture the rest of the request as is. Like most regular expressions, this one is not that easy to interpret, but the following example shows how it processes a request string.

Request Line get http://www.example.com/ HTTP/1.1
Regular expression ^(get|post)(\s\S+\sHTTP\/1\.\d)

 

The first capture group (in the first set of parentheses) does an exact match on either get or post.

In the second capture group:

  • The \s matches the space after get or post.
  • The \S+ matches one or more non‑whitespace characters, in this case the URL (orange text).
  • The second \s matches the space after the URL.
  • The HTTP\/1\.\d matches the string HTTP/1.1 (green text). More precisely, the \d matches any digit, so the regex also works for HTTP/1.0 requests.

Note: Although the regular expression theoretically matches HTTP/2.0 as well, that protocol uses a binary‑format header. The regular expression doesn’t match binary strings, so this virtual patch does not work for HTTP/2.0.

The matches from the two capture groups are stored in in the method and uri_version variables respectively: method holds the HTTP method and uri_version holds the URL and HTTP version (line 18). Then the standard JavaScript functions replace() (line 18) and toUpperCase() (line 19) convert the HTTP method to uppercase.

The updated RFC‑compliant request header is sent using s.send() on line 21.

Conclusion

We’ve explained how to use the NGINX JavaScript module to create a virtual patch. With the power of JavaScript, you can modify request and response data in NGINX Plus in any way you see fit. This provides for a powerful solution to quickly respond to and fix production issues.

Try out NGINX Plus and the JavaScript module for yourself – start your free 30-day trial today or contact us to discuss your use cases.

Learn More

To learn more about the NGINX JavaScript module, see the following resources:

Hero image
免费白皮书:
NGINX 企阅版全解析

助力企业用户规避开源治理风险,应对开源使用挑战

关于作者

Faisal Memon

软件工程师

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。