monique axt
software engineer

Projects

Web Security Application

Focusing on the implementation of security measures in a web application.

This application handles security vulnerabilities including SQL injection, XSS and XSRF. Inspiration from completion of the SEED labs.

  • Home page (not logged in)
  • Home page (logged in)
  • Topics page
  • Create a new topic
  • Search function, by keyword
  • Search function, by username
  • Delete functionality
  • Topic with reply Posts

About

A PHP/JavaScript web-based messaging application that provides a forum for users to communicate by posting Topics or replying to these with Posts. Users need to be logged-in to submit a Topic or Post. The latter can be upvoted, downvoted and deleted. The frontend was written in Vanilla JavaScript, and while the website and its associated forum are fully functional for the purposes of this project, the focus is on security.

Github repo Github repo link

Website functionality

  1. Users can post messages ⇔ they are logged in.
  2. Users can up- and down-vote messages ⇔ they are logged in.
  3. Search/filter posts by keyword.
  4. Search/filter posts by username.
  5. Users should be able to delete their own messages.

Environment and build

A PHP/JavaScript web application that was developed on a Linux/GNU distribution loaded on a virtual machine with a localhost server setup. Want a copy of the virtual machine? Contact me.

Setup 
VM operating systemUbuntu (64-bit) 20.04.2 LTS
IDEPHPStorm 2020.1.4
Server hostingApache/2.4.41
Database managementPostgreSQL and PgAdmin 4
Version controlBitBucket and git
Virtualization softwareOracle VirtualBox Manager 6.1
Languages usedPHP 7.4.3, JavaScript, HTML5, CSS3
DocumentationDoxygen 1.8.17
Coding toolsJSHint

Main security measures

This sections details the security measures implemented. The overarching concepts regarding security-related decision were based on the following principles:

  1. Least privilege
  2. Keep it simple
  3. Defence in depth
  4. Fail securely

SQL injection

When an application communicates with a database, it is important to safeguard against potential SQL injections.

Prepared SQL statements

A DatabaseConnection.php class provides a method to query the database using prepared statements. The key to this is that the SQL statements are performed in two separate steps: preparation and execution. All queries to the database using parameter input are done using prepared statements.

Hiding sensitive DB data

In the case of an SQL-injection vulnerability leading to a breach, all passwords are hashed and verified using password_hash and password_verify.

Additionally, the database password column data type is text (size limit of 1GB1), ensuring there is enough space to hold the hashed values.

Limiting input size and type

While not as powerful as using prepared statements, limiting the size and type of input serves as some protection against attacks by limiting options, AKA a sanity check. Checks are done both in the front and backend.

Principle of least privilege

Connecting to the database is done using an account with the least privileges necessary. This ensures that in the case of a breach an attacker does not have full administrative capabilities and thus potential manipulation of other assets in the database, or the server itself, is limited. In this application, the admin account postgres has full privileges and a separate account userbob is used by the application to connect to the database and execute queries

Up to table of contents

DOM-based XSS (type 0)

Insecurely written HTML pages are the prerequisite for this type of attack. In the CoolForums project, preventing attacks that involve manipulating the DOM is done by limiting the use of JavaScript’s innerHTML() method (used only with trusted data) and ensuring the use of methods such as innerText() when the former method is not necessary - so that any malicious input is rendered as text. Additionally, all JS construction of HTML elements is done using createElement(), setting its properties and then using appendChild() (avoiding insertAdjacentHTML() for example) to inject the new element into the DOM. Additionally, user-input fields are restricted in length on the client-side (a slight deterrent as this can be altered) and on the server-side (see Limiting input size and type).

XSS type 1 & 2

AKA Reflected/Nonpersistent XSS (type 1) and Stored/Persistent XSS (type 2). The potential risks are mitigated by validating input as well as HTML-encoding output before echoing it using htmlentities() or htmlspecialchars(). A check is done in a PHP function

  • if the topic ID and title do not match the data in the database, no data is returned. Data fetched from the database is always executed using prepared SQL statements.

In the case of a missed XSS bug, additional defensive measures were taken. HttpOnly Cookies, which helps protect some users (if the browser used supports this) by preventing cookies being read by the client using document.cookie.

Double quotes are used to wrap tag properties, which can help foil some attacks that can bypass HTML-encoding.

A default character set is set for the web pages, which helps reduce the potential attacker’s options. This is set in all web pages in the application, as encouraged by the HTML5 standard. (This could also be done via PHP using mb_internal_encoding("UTF-8") or set as a header(), or within Apache2 config). This measure is less important now than it was historically, as most modern browsers do not support UTF-7 (in order to be compatible with the HTML5 specification).

HTTP Response Splitting

Whereas XSS attacks involve a malicious data inserted into the web page (as part of the HTML payload), this vulnerability occurs when malicious input is inserted directly into the HTTP headers of the web page sent to the victim. To defend against this, all headers set with PHP using the header() function are specified explicitly, and not set using GET parameters that could be manipulated on the client-side.

XSRF

Cross-site Request Forgery. The main steps taken to mitigate this attack:

  1. POST-requests for write-operations, GET-requests only for read operations
  2. Session timeout
  3. A log-in token

GET requests are only used for operations that don’t change state on the server-side and, additionally, the parameters are validated and checked. Erite operations are done using POST requests and this is checked on the back-end to restrict form-processing to only POST type requests.

Another defence employed includes setting specific cookie attributes.

  • The SameSite attribute specifies whether the cookie should be restricted to a first-party or same-site context. Although the top browsers set “lax” as the default and GET requests in this project are limited, it is still good practice to explicitly declare this attribute to limit the cookie to same-site requests.
  • The Secure attribute instructs the browser to avoid sending cookies over an unencrypted HTTP request (CoolForums was built with HTTPS in mind (see here) so setting this attribute will not cause issues).
  • Setting the Lifetime attribute adds a timeout to the session which limits the window of opportunity for an attacker.
  • The HttpOnly flag is set to protect against XSS attacks by blocking access to a cookie from the client- side, i.e. via the JavaScript Document.cookie API.

Additionally, a randomly generated session token is used to help thwart XSFR attacks. This token is created dynamically by PHP and placed in the HTML of the webpage. Using JS, the token value is passed back to the server for validation.

Up to table of contents

Additional security measures

HTTPS

As a standard defensive measure which mitigates against Man-In-The-Middle attacks, communication trans-fer is done using via HTTPS, meaning data is protected by SLL/TLS encryption. For the purposes of the loc-ally contained CoolForums application, the mkcert2 tool was used which is a simple tool for making locally-trusted development certificates, so that a real environment could be emulated (without browser security warnings). Apache redirects for the HTTP version of the URL as well as 404 or 50x errors were then configured.

Obfuscation

Security via obscurity is the weakest form of security, but often requires very little effort to implement. Related to the Hiding sensitive database data section, information leakage is a security vulnerability that provides an attacker with information that could lead to a breach of security or privacy policy.

Avoiding verbose error/info messages. Following crypto protocols for best practice, any information in this application that is sent from the server to the client is minimized. Errors, for example, are logged in detail on the server; however the client is simply aware that an error occurred and responds accordingly. Path information and version information are also obfuscated, although more for learning purposes than as any real protection.

Moreover, default cases are included in the code logic, i.e. handling unexpected situations and input.

Restricted access

Many of the website’s features deal with restricted access. Using PHP’s header() function, pages are redirected if the user is not logged-in, denying access.

  1. Text is variable unlimited length, although practically this is limited by the architecture. See link

  2. mkcert tool