Improving Application Security Through Automated Testing
Turn Your Software Development Security into a Repeatable Engineering Process
Companies have long viewed application security testing as a black art that’s dependent upon a small number of experts wielding arcane tools to find vulnerabilities and develop exploits. However, as the velocity of software development increases, the old way of running security tests becomes less acceptable.
This situation is most pronounced in a DevOps environment, where developers may deploy software faster than security testing tools run. When properly applied, automated security unit and integration tests can help turn security in the software development lifecycle (SDLC) from an art into a repeatable engineering process.
Since developers can execute the entire abuse case process without intervention from the security team, this process scales with the number of developers, unlike many security controls.
Empower Your Developers
DevOps presents a breaking point for many traditional security processes. When developers need the capability to push code to production multiple times per day, it is no longer feasible to rely on a security expert to run a tool or interpret results. Organizations need to empower their developers to create code without the hassle of requesting outside assistance or approval. Developers also need fast feedback to fix vulnerabilities while the code is still fresh in their minds and before the code makes it to production. If security teams fail to adapt to this changing paradigm, they risk being marginalized–a losing proposition for secure software development.
3 Key Security Testing Tools to Use
Companies typically use three security testing tools in their SDLC processes.
- Static application security testing (SAST)
Of these three tests, only SAST runs without a functioning application. Many SAST tools also are available in a developer’s desktop environment, before code is even committed to the repository. This early availability makes SAST a reasonable control in a DevOps environment. However, SAST has limitations. Vulnerabilities in the “Broken Access Control” category are difficult for SAST tools to locate, since they do not have the context of what the application should or should not do.
- Dynamic application security testing (DAST)
DAST tools work by sending malformed information to input fields on a live application. DAST tools also are not often able to locate “Broken Access Control” issues. They too lack the context of what is appropriate within the application. Using a DAST tool against a full web application may be too time-consuming to run within the continuous integration/continuous deployment (CI/CD) pipeline. Security teams will often “seed” the DAST tool with specific requests that exercise recently-modified code. Focusing the DAST tool only on modified code helps to reduce the total running time.
- Application Penetration Testing
Application penetration testing is a manual process where a human makes targeted requests to a running application to locate security vulnerabilities. This process can find “Broken Access Control” vulnerabilities, but is extremely slow and requires a running application. Due to time constraints and the manual nature of application penetration testing, this control is not part of the CI/CD pipeline. Any vulnerabilities found during testing inevitably cost more to fix since application penetration testing occurs so long after the developers wrote the code.
Automated Unit Tests
The quality assurance (QA) field has also struggled with similar issues working with modern software development practices. However, concerns that developers will release buggy software or software that simply does not meet requirements have not blocked DevOps adoption. Instead, the industry has adapted by having developers write unit and integration tests that run early and often. Testing languages, such as JUnit, xUnit, and Mocha, allow developers and integration tools to run thousands of tests to ensure software functionality.
It is possible to automate security testing in much the same way as functional tests. Developers can write security unit and integration tests to ensure not just that the software functions, but that it treats input correctly, encodes output properly, and even restricts access to sensitive resources. Once a developer has written these unit and integration tests, the tests can run before deployment, within the deployment pipeline, and as regression tests. These tests run in a fraction of the time it takes for any other testing activity. Testing software can run thousands of tests in a matter of minutes, which makes security unit and integration tests a viable part of the CI/CD pipeline.
Threat Models to Security Unit/Integration Tests
One of the largest barriers to adopting developer-written security unit and integration tests is developers knowing which tests to write. The argument of “developers are not able to test their code because they do not think like attackers” is not without merit. Threat modeling can guide developers on which threats are pertinent to the specific code they are writing. Ideally, a developer can look at their use case, turn to the threat model, and find pertinent threats.
For example, consider the following use case: “As a user, I should be able to view my shopping cart, which contains items I have marked for purchase,” and the following threat: “Attackers may attempt to access resources belonging to another user.”
Some possible abuse cases for this use case are: “As an attacker, I should not be able to view the shopping cart of another user,” and, “As an attacker, I should not be able to add items to another user’s shopping cart.” Both insecure direct object reference vulnerabilities may be difficult for SAST and DAST tools to locate. The developer can use this information to create automated tests that ensure the system responds with a 403 response error code in both of these abuse cases.
The Function of the Security Team
Notably absent from the process of using a threat model to create and test abuse cases is the security team. By taking a less active role in the automated testing process, security teams can ensure that the testing process remains scalable. In situations where a company has 100 times more developers than application security personnel, the security team must focus on test case monitoring and improvement. Existing code coverage tools can provide useful insight as to whether developers have created enough security unit and integration tests. Software security teams can ensure continuous improvement in the security unit/integration testing process by feeding results from application penetration testing, SAST, and DAST tools into the threat model templates. When development teams apply the updated templates to their existing threat models, the threat modeling application will generate a list of threats based upon other recent application testing activities.
Another touchpoint software security teams have in the SDLC is developer training. As organizations learn lessons from testing and incident response activities, the security team should ensure recurring developer training is updated to highlight new information.
The following paper provides specific guidance on how to generate abuse cases, unit tests, and integration tests. Unit and Integration tests to demonstrate using Mocha to automate testing of the OWASP Juice Shop application are located here.