Tag Archives: security

Cross Site Scripting (XSS), Cross Site Request Forgery (CSRF) And Server Side Request Forgery (SSRF)

XSS, CSRF (or XSRF) and SSRF are common vulnerability in modern web applications where an attacker tries to imitates either a legitimate client to an unsuspecting server or a legitimate server to another unsuspecting server. The basic underlying principle behind each of these attack remains the same; performing action on behalf of a legitimate entity. Let’s look at each of them in a bit more detail and learn about how to protect our web applications against each of them.

XSS (Cross Site Scripting)

XSS or Cross Site Scripting occurs when an attacker manages to execute malicious script code in a victim’s browser as the victim. Browsers store a lot of sensitive information in them. Some of this information is used to identify a user on a website.

A script loaded from a website can access information stored on your browser through that website, which is how sessions work in your browser. That’s how Facebook or any other website knows to show you your personalized information and not someone else’s.

XSS occurs if an attacker gets control over the scripts running in your browser. If they can execute code, they can steal your login credentials and trick you into installing malware on your computer.

There are different kinds of XSS attacks and they depend on where the payload is stored.

Reflected XSS

A reflected XSS vulnerability occurs when a piece of data from a URL is reflected back into the website code unsanitized and can be injected into. This can be a result of a GET or a POST request, and it is especially severe as an unauthenticated GET request as that URL can be shared on social media and anyone clicking on it gets compromised.

Remediation of reflected XSS – Sanitization of all user inputs before passing it back into the view

Stored XSS

A stored XSS vulnerability occurs when a web application stores an XSS attack payload without sanitizing it and then displays it back to the same user or a different user. A notable recent example is British Airways website getting compromised and exposing sensitive data including credit card information of 380,000 transactions.

Remediation of stored XSS – It is the same as with reflected XSS: Sanitization of all user inputs before storing the data in the database.

DOM based XSS

Unlike reflected/stored XSS, a DOM based XSS occurs only on the client’s side. This can be a result of a user typing in a string into an input field that gets parsed and executed as code. An attacker can trick a user to paste a string into their browser which will execute due to insecure parsing and compromise a user’s credentials.

Remediation against DOM based XSS – Display text as text, and nothing else. Instead of element.innerHtml use element.innerText or element.textContext to ensure the data displayed back to a user is purely text.

CSRF (Cross Side Request Forgery)

CSRF occurs when a malicious website makes a request to a legitimate server through an unsuspecting victim.

Web applications communicate with clients through HTTP requests. When a request is made, the browser attacks all information that it knows about the website along with the request, including login/authentication credentials (called cookies).

If the web server doesn’t have protective measures, a request made through a legitimate website and an attacker’s website look exactly the same (or they can be forged to look the same). As a result, an attacker can make a request telling the victim’s bank to transfer $100 to the attacker’s account, and since the request is made through the attacker’s browser, the bank’s server will process it as a legitimate request.

Remediation of CSRF – CSRF can be easily prevented by requiring any unsafe request to validate itself using a valid CSRF token that can only be found in the website’s code and changes on every use. Additionally, authentication/login cookies can be marked as sameSite only, such that any third party website making the request doesn’t contain the sensitive authentication cookies.

SSRF (Server Side Request Forgery)

SSRF is similar to CSRF, but instead of an compromised client making a request to an unsuspecting server, here a compromised server makes a request to itself or another unsuspecting server.

Since a server might be a privileged node in the network, the attacker can make the server access and return sensitive information or perform privileged actions that the attacker’s account wouldn’t allow.

SSRF can also be used to trigger code execution in servers where the vulnerability can be exploited using the privileges of the server itself.

Remediation of SSRF – Any outgoing request needs to be explicitly allowed from the application by maintaining an allowlist of domains and servers a given server can connect to. The scope of these requests should be made as narrow as possible.

In conclusion

I hope that was an interesting quick read on one of the most common vulnerabilities in modern web application. Injection and SSRF are two of OWASP’s top 10 for 2021, so it is definitely worth looking into them and protecting our web applications from potential vulnerabilities.

Read more on OWASP top 10 here: https://owasp.org/www-project-top-ten/

Thank you for reading

nginx blocking malicious request

Setting Up ModSecurity + OWASP Core Rule Set + Nginx On AWS EC2

ModSecurity is a web application firewall. It can protect your web application from preying eyes of vulnerability scanners and attackers. It is extremely customizable, and when paired with OWASP’s Core Rule Set, covers quite a lot of web technologies and frameworks.

In this article, we’ll set up ModSecurity on an AWS EC2 Server running Nginx web server.

Table of contents

Set up Nginx on Ubuntu server

For this tutorial, we’re using AWS LightSail’s Ubuntu image. Choose any instance size depending on your requirements. I’ll choose a 40$ / Month instance with 8GB RAM and 2vCPUs just so that the compilation of ModSecurity is faster.

Once the instance is created, log into the instance with SSH and update packages

$ apt update && apt upgrade -y

Install Nginx

$ sudo apt install nginx

Check what version of Nginx did we get from our package manager. This will be used when compiling Nginx later.

$ nginx -v

I got the following output:

nginx version: nginx/1.18.0 (Ubuntu)

To make sure the webserver is successfully installed and running, simply visit the IP address of the server. It should look something similar to this:

Set up ModSecurity

First we’ll need to install compilation and other dependencies.

$ sudo apt-get install -y apt-utils autoconf automake build-essential git libcurl4-openssl-dev libgeoip-dev liblmdb-dev libpcre++-dev libtool libxml2-dev libyajl-dev pkgconf wget zlib1g-dev git

Next we’ll clone the ModSecurity repository into the /opt directory

$ cd /opt && sudo git clone --recursive https://github.com/SpiderLabs/ModSecurity && cd ModSecurity

Next we run the build script

$ sudo ./build.sh

Next we’ll run the compile script that will fetch all the dependencies for the compilation

$ sudo ./configure

It is possible that this command fails and reports you of any dependencies that are still missing. You can simply google them with “install XYZ on Ubuntu” and run the configure command again. Ideally it will just exit without any errors.
Next we start with the actual compilation of ModSecurity

$ sudo make

A reason why I didn’t go with the smallest server was that this step is resource intensive and could take 15 minutes or more depending on your server’s CPU and memory.

If all went through, we can now install ModSecurity

$ sudo make install

If all went through without any errors, we have ModSecurity installed.

Set up ModSecurity <-> Nginx connector

We start off by downloading ModSecurity-Nginx and Nginx source code. Note that the version of Nginx in the next command must match the version installed on our system. For me, that’s 1.18.0 but it could be different for you.

$ cd /opt && git clone https://github.com/SpiderLabs/ModSecurity-nginx.git
$ cd /opt && sudo wget http://nginx.org/download/nginx-1.18.0.tar.gz

Untar the Nginx source. Replace the Nginx version in the next command if needed.

$ sudo tar -xvf nginx-1.18.0.tar.gz

Next, we need to grab configure arguments. For that, run the nginx command with a capital ‘V’ flag.

$ nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-7KvRN5/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

Note the “configure arguments” in the command’s output. We need to build modsecurity with these arguments.

$ sudo ./configure --add-dynamic-module=../ModSecurity-nginx <paste configure args here>

For example, here’s what I’ll run:

$ sudo ./configure --add-dynamic-module=../ModSecurity-nginx --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-7KvRN5/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

Don’t copy the above command. You must use the configure arguments supplied by your installation of Nginx.

Next we build the modules

$ sudo make modules

This is a compilation step and may take a little while (a minute or so) to complete. The final step here is to copy the compiled modules to a place from where we can reference them from our Nginx config.

$ sudo mkdir /etc/nginx/modules
$ sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules

Loading ModSecurity module in Nginx

Simply add the following line to the nginx config file at /etc/nginx/nginx.conf outside any block.

load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;

Set up OWASP Core Rule Set

OWASP’s Core Rule Set is a set of rules that cover most common frameworks and technologies as well as cover signatures for common web application attack payload. It is a good place to start if you don’t want to write custom rules for many common attacks.

First, we’ll clone the modsecurity-crs repository

$ sudo git clone https://github.com/coreruleset/coreruleset /opt/coreruleset

Then we’ll rename the crs-setup config file

$ sudo mv /opt/coreruleset/crs-setup.conf.example /opt/coreruleset/crs-setup.conf

Activate the default exclusion rule file.

sudo mv /opt/coreruleset/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example /opt/coreruleset/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Next we create a place for coreruleset to live within /etc/nginx and copy some additional config files.

$ sudo mkdir -p /etc/nginx/modsec
$ sudo cp /opt/ModSecurity/unicode.mapping /etc/nginx/modsec
$ sudo cp /opt/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf

Next we create a config file that will include our main ModSecurity config file and CRS setup files.

$ sudo touch /etc/nginx/modsec/main.conf

And add the following lines to the config file.

Include /etc/nginx/modsec/modsecurity.conf
Include /opt/coreruleset/crs-setup.conf
Include /opt/coreruleset/rules/*.conf

Finally, we reference this main.conf file from our Nginx config.

$ sudo vim /etc/nginx/sites-available/default

And add the following line within the server block.

modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;

Turn ModSecurity “on” and test XSS payload

So far, we’ve configured everything but if we restart Nginx now, it won’t filter attacks but only detect them since the default operating mode of ModSecurity is to only log malicious requests. To change that, let’s open the file /etc/nginx/modsec/modsecurity.conf and change the line

SecRuleEngine DetectionOnly


SecRuleEngine On

For our changes to go live, we’ll need to restart Nginx.

$ sudo systemctl restart nginx

Let’s test our ModSecurity installation. Open your browser and send a sample payload in the GET parameter. It doesn’t have to be a real parameter, but just something that can trigger an XSS filter.


That’s ideal. ModSecurity is working and blocking seemingly malicious requests to our web server. Now any application that sits behind our web server will be protected against many generic web application attacks, even OWASP Top 10 thanks to OWASP’s CoreRuleSet.

In conclusion

It isn’t the most straightforward of installations, but it isn’t very difficult either. The hard part, however, starts here and it is to get rid of all false positives and tweak the installation such that it fits the needs of your specific web application. Depending on how complex an application you’re trying to protect, it can be fairly time consuming.

I’ll write an article on how to tweak the parameters of ModSecurity and make it fit our needs in the future in a separate article.

That’s it for this article, thank you for reading!

WordPress Security Checklist: How To Secure Your WordPress Website

WordPress has been powering my blog since the start of last year. In fact, migrating my Jekyll template to WordPress was one of the highlights of my new year 2021 and I’m very happy that I did, although I didn’t publish as much as I had hoped for. Fortunately, I’ve learned a lot more about WordPress over the course of a year than when I started. In this short primer, I hope to go into a bit more depth on how to securely run a self hosted WordPress website.


Before we get started, there are a few things that we need to make sure we have to

  • Self hosted WordPress installation with SSH access
  • Administrator account to set up plugins

Table of contents

  1. Keep plugins to the minimum and up to date
  2. Fix file permissions
  3. Two-Factor Authentication
  4. Set up auto banning of failed logins
  5. Enable regular backups
  6. Disable XML-RPC
  7. Disable file editing in WordPress admin
  8. Use a Web Application Firewall
  9. Don’t forget the usual web security measures

1. Keep plugins to the minimum and up to date

I wish I could just sticky something like this on top of most of my articles, but most people trying to attack our websites don’t have the time or resources to develop and use 0days. They use existing exploits out in the wild and some of these exploits can be months old, if not more. WordPress core and plugin authors can only do so much more than promptly releasing patches for security vulnerabilities that they find.

So then it is up to us as site admins to make sure we patch as soon as is feasible. Having worked on many large codebases, I know automatic updating isn’t always possible or even desirable, but having an eye on the changelog can definitely help not get compromised.

I’d also recommend a web security helper plugin that sends alert emails when it detects outdated plugins / themes / core.

2. Fix file permissions

During development, many files and directories permissions are way too open to make it easy to set up the website and all plugins. In production, however, the permissions can be dialed down a notch to prevent anyone with any access on the server to take over the whole website.

Similarly, attackers typically upload shell code using the uploads functionality, and if code execution is disabled in the directory, we make it harder for this attack to succeed.

A detailed guide on setting file permissions can be found on official WordPress documentation: https://wordpress.org/support/article/changing-file-permissions/

3. Two-Factor Authentication

Administrator accounts have many powers on a WordPress website, and a compromised administrator account can lead to uploading of PHP shell code leading to command execution and server compromise.

To make sure admin accounts are extra secure, enforce 2FA on all administrator accounts. This can be done by any 2FA or login security plugin on the WordPress plugin store.

4. Set up auto banning of failed logins

Since WordPress doesn’t ship with any builtin way of auto-banning failed login attempts, we have to rely on plugins like WordFence. WordFence will need to be configured with options to block login attempts after a certain number of failed attempts.

WordFence can also help you disable execution in upload directories, block IP addresses making malicious requests and much more.

5. Enable regular backups

While we can take preventive measures against mishaps, we can never be sure. Hence it is imperative that the website is backed up regularly. Backing up can be done at multiple places. The database can be backed up separately from the static assets and files. There are many plugins, like WPVivid, that help you fine tune what gets backed up and where it gets stored. It is always nice if you can afford an external backup location, like AWS S3.

The hosting provider might also have ways of backing up the website. For example, AWS Lightsail has daily instance snapshots which backs up the entire disk.

6. Disable XML-RPC

If you don’t use plugins that rely on XML-RPC or using the WordPress mobile app, it is wise to disable XML-RPC which removes another widely used attack surface by attackers. Many plugins allow the disabling of XML-RPC, including the aforementioned WordFence.

7. Disable file editing in WordPress admin

Disable editing of files from WordPress admin as that’s almost never a good idea, especially if you can achieve the same using more secure methods like SSH. To disable file editor, simply add

define( 'DISALLOW_FILE_EDIT', true );

to your wp-config.php file.

8. Use a Web Application Firewall

A firewall plugin like Sucuri or WordFence can identify attack signatures and block malicious requests. Many also include IP address block lists that prevent known malicious IP addresses from reaching your WordPress website.

For more control, there’s ModSecurity. ModSecurity needs to be installed alongside the web server and it can detect and block known attack signatures for not just WordPress but just about any popular web framework. It does require a deeper technical know how to setup and maintain ModSecurity, and a plugin might work be a better approach for most people.

9. Don’t forget the usual web security measures

A WordPress website is, at the end of it all, a website. While there are WordPress specific ways of hardening a WordPress installation, there is also a whole plethora of best practices that apply to every website, including the WordPress ones.

  1. Use HTTPS – SSL/TLS certificates are free, and usually come by default with many hosting providers and CDNs. Don’t forget to turn it on and enforce it in strict mode.
  2. Use appropriate security headers – Headers tell the browser how to handle your website’s content. Many client side attacks can be mitigated by using the right set of headers. A detailed list of useful headers can be found on OWASP’s website: https://owasp.org/www-project-secure-headers
  3. Use CAPTCHA on login page – to prevent bot submissions and more sophisticated bruteforce attacks, enforce a CAPTCHA like reCaptcha on login page. WordFence supports this out of the box (needs an API key from Google).
  4. Handle user input with care when using a custom theme – when using a custom theme that accepts user input in the form of query parameters to show filtered content, the regular best practices around user generated input has to be followed. Embedding user input in output can lead to Cross Site Scripting, while passing it straight to the database can lead to SQL Injection.

In conclusion

I hope that was useful. If you have any questions around WordPress or suggestions to improve this article, feel free to reach out to me via email. Thank you for reading!