You know that web app you inherited? The one that sits there in the corner keeping you up at night. It hasn’t been properly maintained for years and you suspect (more than suspect, probably) that there are big issues with security vulnerabilities lurking inside. Worse still, you wouldn’t know what to do if it went down. And if that wasn’t bad enough, the original people who built and maintained it have disappeared into the digital sunset.

Step 1: Review the web application

The first step is reviewing the web application from a high level. By understanding the components, you can come up with a plan to address all of the potential security vulnerabilities, performance bottlenecks and other issues that can arise from an application that’s been ignored for while.

Architecture

Web application architecture ranges from monolith applications hosted on internal rack servers to micro services hosted on small cloud instances—and everywhere in between. It’s important to understand these details before making any changes and record the structure on a flow chart or diagram to use as a constant reference.

Many legacy applications are monoliths hosted on either internal rack servers or managed private servers. In these cases, it’s important to ensure that the operating system and any other software is kept secure and up-to-date. You may also want to look at server usage to see if CPU, RAM or storage capacity needs to be increased to handle growth.

Cloud web applications present different challenges. You may not know where different parts are hosted. For example, a single web application could use Amazon EC2 to host the application, Amazon S3 to host user uploads and Google Firebase for real-time messaging within the application. You may not even know the usage or costs for each of these services.

Some hardware architecture questions to ask include:

  • Do you have any on-premise servers?
  • What external services do you use for hosting?
  • What resources are available and consumed for each?

In addition to the hardware architecture, you should assess and understand the software architecture. The way code is structured can have a big impact on the maintainability of a web application, as well as any plans to update or upgrade it. Some web applications aren’t organized at all, whereas others may have a clean structure in place.

Some code architecture questions to ask include:

  • Does the code use a model-view-controller (MVC) paradigm or another standard?
  • How are web requests handled by the application?
  • How is the application loaded on the server?

The specific questions to ask will depend a lot on the type of web application as well as the languages or frameworks. For example, PHP web applications may range from CakePHP or CodeIgniter frameworks with a cohesive structure, to a single folder of files with each file representing a URL path.

Database

Web application databases come in many shapes and sizes, ranging from PostgreSQL to MongoDB to Redis, while many applications use multiple databases.

Start by cataloguing each database and the type of data that it contains. Next, determine if there are any performance improvements that can be made. For example, you may see that a database is very large, but doesn’t use indexes or relationships, which can degrade performance. Note these performance recommendations for future follow-up.

In addition to the database, you should check if the application uses an object-relational mapping tool (ORM). These solutions make it easier to securely execute queries against a database without worrying about low-level concerns. Many ORMs are also database agnostic, which means there may be an opportunity to easily switch database solutions.

Some database-related questions to ask include:

  • What are all of the different databases? How and where do they interface with the code base?
  • What is the size of the database? How many tables or rows in an SQL database or records in a NoSQL database?
  • Are proper indexes and other performance strategies employed to enable faster queries for SQL databases?
  • Are there any NULL values or other database design issues that could cause bugs for certain queries?

The answers to these questions could help identify potential areas where you could make performance improvements or eliminate common database-related application errors.

Third-party libraries

Web applications regularly use third party libraries that can introduce security and performance issues. While third-party libraries are unavoidable in many situations, it’s important to ensure they are secure and updated at all times.

The most important thing to look for is a dependency manager for third-party libraries, which serves as a single source of truth for third-party code that can be updated over time. For example, most Ruby applications use Bundler and Gems to manage dependencies. A single Gemfile in the application directory contains a list of each dependency and version.

Some dependency related questions to ask include:

  • Are there any dependencies that have been deprecated or are no longer actively maintained by the development team?
  • Are there any dependencies that are outdated by a major version where updating could break the application?
  • Are there any dependencies with known security vulnerabilities that could pose an immediate threat?

The answers to these questions could help you identify immediate issues that need to be addressed, as well as longer term issues that need to be fixed.

Testing

Software testing is a somewhat new phenomenon. By writing automated tests and running them before each new code contribution, developers can avoid introducing bugs that cause failure. Test-driven development (TDD) is widely considered a best practice for modern web applications.

Start by assessing whether the web application has test coverage, and if so, how much of the code base is covered by tests. Next, run the test suite to see whether the tests are still passing or if the tests have been ignored for too long and are failing. Even if they fail, these tests can be a helpful starting point for getting things back up to speed.

Some testing-related questions to ask include:

  • What kinds of tests are used? (e.g., unit tests vs. integration tests)
  • Is there a continuous integration server that runs these tests before a deploy?
  • What parts of the application are covered by tests?
  • What language and framework are the tests written in?

By assessing this test coverage early on, you can determine how much effort would be required to improve test coverage, as well as determine how confident you can be when deploying any new code.

Step 2: Assess security

Web applications face a wide range of security risks, so it helps to have a clear checklist of potential issues. The Open Web Application Security Project, (OWASP) provides these standards, which can be very helpful when auditing a web application for security issues.

Let’s take a look at each of the OWASP’s top ten risk factorsto see what kinds of security issues you should be watching for in your code base.

1. Injection

Injection occurs when untrusted data is sent to an interpreter as part of a command or query to trick it into executing unintended comments. For example, an SQL injection may involve a user inputting their own SQL query to give themselves administrative privileges in a web application and ultimately stealing data.

Some issues to look for include:

  • Validation for user supplied data.
  • Use of an ORM.
  • Dynamic queries without context-aware escaping.

2. Broken authentication

Improper implementation of authentication enables attackers to compromise passwords, keys, or session tokens. For example, automated brute force attacks can be used to try thousands of common passwords in just minutes to identify ones that work. These credentials can then be used to gain privileged access to the web application.

Some issues to look for include:

  • Lack of password rules and enforcement.
  • Storing passwords as plain-text.
  • Exposure of session IDs in the URL string.

3. Sensitive data exposure

Sensitive data can be compromised without extra protection, such as encryption at rest or in transit, including financial, health, or other data. For example, the transmission of sensitive data in clear text through HTML forms (e.g., using HTTP vs. HTTPS) could be intercepted through a man-in-the-middle attack on a wireless network.

Some issues to look for include:

  • Old or weak cryptographic algorithms.
  • Default crypto keys or insufficient key management.
  • Lack of secure data transmission (e.g., HTTP and FTP).

4. XML external entities

Old or poorly configured XML processes may disclose internal files on a server using the file URI handler, internal file shares or other attack vectors. For example, legacy applications with SOAP prior to version 1.2 may be susceptible to XXE attacks if XML entities are passed to the framework. These are more complex attacks that can be very devastating.

Some issues to look for include:

  • The acceptance of XML or XML uploads from untrusted sources.
  • Outdated SOAP frameworks (e.g., less than version 1.2).
  • SAML for identity processing for single sign on purposes.

5. Broken access control

Access control policies ensure that users cannot act outside of their intended permissions. Broken access control systems can lead to the disclosure, modification, or destruction of data by unauthorized users. For example, a CORS misconfiguration can lead to unauthorized API access to a web application, and ultimately, data theft or loss.

Some common issues to look for include:

  • URL modification to bypass access control checks.
  • Replaying or tampering with JSON Web Tokens (JWT).
  • CORS misconfiguration leading to unlimited API access.

6. Security misconfiguration

Security misconfiguration can happen at any level of the application stack and encompasses a variety of issues. For example, a server may still have default user accounts enabled, unprotected files and directories, or other unpatched flaws that could enable intruders to gain access to the server and steal information.

Some common issues to look for include:

  • Default accounts and passwords.
  • Default security settings for frameworks, libraries, databases, and other systems.
  • Unnecessary features enabled and/or installed.

7. Cross-site scripting

Cross-site scripting occurs when attacks inject client-side scripts into web applications viewed by other users to bypass access controls. For example, a web application with a user forum could enable a forum user to input a script on a public-facing web page that collects user details and uploads them to the attacker’s data store.

Some common issues to look for include:

  • The storage of plain-text user details on their browser.
  • Unvalidated user input that can be shown as HTML output.

8. Insecure deserialization

Insecure deserialization takes place when a web application deserializes hostile objects supplied by an attacker. For example, a web application may deserialize a hostile API authentication token that modifies the application logic and provides the attacker with potentially devastating remote code execution capabilities.

Some common issues to look for include:

  • Processes that HTTP cookies, HTML forms, or API token are deserialized.
  • Serialization of databases, file servers, or cache servers.
  • Remote and inter-process communication mechanisms.

9. Components with known vulnerabilities

Web applications have many different components, including libraries, frameworks and operating systems. When these components aren’t kept up-to-date, they may be exposed to a wide range of security vulnerabilities. For example, an outdated version of PHP could expose an application to known security risks like DDoS attacks.

Some common issues to look for include:

  • Outdated third-party libraries and dependencies.
  • Outdated nested dependencies for these libraries.
  • Operating system, database, or platform vulnerabilities.

10. Insufficient logging and monitoring

Logging and monitoring are critical to prevent potential attacks and ensure that a web application is secure. In fact, many breach studies suggest that the time to detect a breach exceeds 200 days! For example, an accidentally exposed database could be downloaded hundreds of times without proper monitoring.

Some common issues to look for include:

  • Loggingfor logins, failed logins, or high-value transactions.
  • Clear log messages, warnings, and error messages.
  • Monitoring of suspicious activity for APIs.

Step 3: Check compatibility

The next step is running a compatibility check to see what might break if you update everything.  For example, suppose that you have a PHP web application running on version 5.6. The version is very old and no longer maintained and there are many known security vulnerabilities, which means that you must upgrade, but you’re not sure if the application will still work.

Let’s take a look at two different kinds of compatibility checks—language compatibility and dependency compatibility.

a. Language compatibility

Language compatibility represents how an upgrade in the web application’s programming language or framework will impact its functionality.

Many popular programming languages include migration guides between major versions to answer these questions. For instance, PHP includes migration guides that cover new and deprecated features, new and changed functions, new classes and interfaces, new global constants, and other information. You can use this information to determine what could break.

But, how do you analyse an application that might be 10,000 or 100,000 lines of code?

The good news is that there are many tools that can help you uncover any compatibility issues. A good example is the PHP Compatibility Checker for PHP_CodeSniffer, which analyses your code base for compatibility with higher and lower versions. These tools will never be 100 percent accurate, but they provide a great starting point for compatibility testing.

b. Dependency compatibility

Dependency compatibility refers to the compatibility of various third-party dependencies with a different version of the underlying programming language or framework. If you upgrade the programming language or framework, you need to make sure that all dependencies are working properly and that the application will still function.

Dependency managers make this process easy by managing everything in a single location. For example, Ruby’s bundler has built-in commands to automatically update gems to the latest compatible version and remove any unused gems. RVMcan also be used to update Ruby versions dynamically to see how they impact the web application.

If the web application isn’t using a dependency manager, it might be worth installing one as a first step to assist with compatibility issues. The alternative is manually checking each dependency to determine its compatibility or going through each readme and then testing the application in a development environment to confirm compatibility.

Step 4: Run code metrics

The last step of an audit before coming up with an action plan is running some basic code metrics. These should provide insights into performance, complexity, errors rates and other issues that can guide the upgrading process. These metrics should be measurable and uniform in order to assess whether the code has been improved over time.

Example Code Metrics – Source: PHPMetrics

Three of the most important metrics include:

  • Cohesion of Methods (LCOM): This metric measures the number of responsibility of a class. In an ideal world, this metric should be equal to one in order to adhere to SOLIDprinciples.
  • Maintainability Index: This metric measures the maintainability of any project by looking at lines of code, complexity and the number of commented lines.
  • Halstead’s Difficulty: This metric looks at how difficult the code is to understand by assessing the software’s vocabulary and length with operators and operands.

There are many software solutions that can automate this process as well. For example, PHPMetrics is an open-source tool that can be used to calculate and visualize these metrics within a PHP application. Many other programming languages have their own code metrics platforms designed to provide these same pieces of information.

Application monitoring

Application monitoring is also a great way to assess an application’s performance, identify any relevant bugs and prioritize what needs to be fixed. Many popular application monitoring platforms provide real-time alerts for errors driven by actual usage that can be very helpful when prioritizing what to fix. They also provide detailed stack tracing that can simplify the process of tracking down the offending code to make a fix.

Example of Airbrake Report – Source: Airbrake.io

Airbrake is a popular example of a web application monitoring service that includes all of these features. In addition, many platform-as-a-service (PaaS) providers have real-time monitoring tools for performance usage and application errors. These metrics can be invaluable when looking for ways to improve performance through either fixing offending issues or upgrading plans with cloud providers.

Step 5: Compile recommendations

The final step is making recommendations based on the four areas involved in the audit. These recommendations will ultimately serve as the guide that you can use to upgrade the web application and bring it up-to-date. In addition, developers can reference these recommendations when implementing their fixes.

Let’s take a look at what to include in each section:

  • Architecture Review: The web application review should culminate in a manifest of hardware and software architecture that can be used as a map for future work. It may also help to create a flowchart showing how each piece of the application works in conjunction with the data passed between them.
  • Security Review: The security review should culminate in a list of security issues sorted in order of severity. Urgent security issues are those that should be fixed immediately, medium risk issues should be scheduled out in the near-term and low-risk issues should be fixed as time permits.
  • Compatibility Review: The compatibility review should highlight the extent of language, framework, and dependency compatibility issues and a plan for resolving them. Many of these reports can be automated using a compatibility checker and included in the final report for review.
  • Code Metrics Review: The code metrics review should lay out the performance, maintainability, and error rates as a baseline that can be improved upon over time. Again, many components of this report can be automated to include in the final report.

These recommendations can be consolidated into a single report that can be distributed to the relevant team members. For example, managers can have an idea of what needs to happen while developers can have a specific list of items that they need to address in the order they should address them.

Should you outsource the audit?

The auditing process is complex and time-consuming, which makes it a natural candidate for outsourcing. In addition, hiring an expert can ensure that you don’t miss any crucial components of the audit, such as a hidden security vulnerability or minor language change that could come back and cause issues further down the road.

For PHP web applications, Siftware provides an extensive and affordable security and performance audit solution designed to help you understand everything that needs to be done and come up with a clear plan of action. The deliverable is a single PDF report that clearly outlines all of these key areas and includes actionable recommendations that you can start implementing immediately.

If you want to outsource PHP app development or support and maintenance of your web application, we also provide a hands-off application maintenance program. We can handle all of the necessary upgrades and bug fixes that need to be made in order to free up your time and resources to focus on more pressing needs within your organization.

If you’d like to see if Siftware is a good fit for you and your project, please don’t hesitate to get in touch.