Integrating security tests into web applications

Integrating security tests into web applications

Writing automated tests while building your application has become common practice for quite some time now. Everyone likes to brag about the coverage that their application has and nobody likes to find out from their users that they just released a buggy update. So nowadays most dev teams implement processes and techniques, such as continuous integration and Test Driven Development, to allow code problems tracking and assure that the quality of the overall solution is within the established specifications and standards.

Building tests while developing new features can help ensure that the application behaves as expected when subjected to a normal usage but - more frequently than not - this doesn’t cover every possible interaction that an attacker might try.

Nowadays, much of the development uses frameworks like Ruby on Rails, making it easier to prevent against several common vulnerabilities, but the overall product might still have some security holes when it is deployed.

Many companies with big budgets running critical services hire security teams or consultants to perform all kinds of penetration tests and other types of analysis, further enhancing the degree of protection they assure. This approach is often out of the budget to startups or small businesses, making security issues regularly neglected until some kind of trouble shows up.

There are tools to help us find security problems and improve the overall security of our application. Some of them can even be deployed in an automated way like the remaining test suite.

In the remaining of this article, I’m going to use one of them (open-source, of course) and try to integrate it with a RoR project.

Meet Zed Attack Proxy (ZAP)

As described in the tool homepage, ZAP is a “penetration testing tool for finding vulnerabilities in web applications”. It works as a proxy that stands in the middle of the communication between the browser and the website, analysing the requests and responses made during a session in search of vulnerabilities.

It has many integrated features such as crawlers to automate the navigation and collect information about the target, support for web sockets, fuzzers, etc.

It also has a REST API, that lets the user interact with it and automate the jobs through other tools.

Despite being easy to use, it is a powerful and complex program that may require a lot of expertise to maximize its utility and achieve better results. In spite of this, a lot of value can be acquired even through a basic utilisation.

Running a vulnerability scan

ZAP GUI

In this article, I’m not going through the graphical user interface and the manual testing capabilities. My objective here is to show up what can be done through the API.

Ideally, the first thing you should do is configure the browser you use to do your tests, to make all communications through ZAP (by default the proxy is started at localhost:8080). However, I will leave it to a later stage and begin by showing how to perform a simple scan through the API.

To explore the available features and rest endpoints you can launch zap:

$./[pathToYourInstallation]/zap.sh -daemon

and visit http://localhost:8080.

To make a scan, you just need to make a GET request to: http://localhost:8080/json/ascan/action/scan/?url=http://UrlToYourSite/.

When it is finished you will be able to fetch the results here: http://localhost:8080/json/core/view/alert/?zapapiformat=json&id=1

Of course, there are many options and ways to improve these results, but you will need to dig a little into the configuration and settings of ZAP, which is out of the scope of this article.

Automating the tests

Now that we have seen how it works, it would be nice to add this to our test suite in any project, so that we could run ZAP along other tests with a single command.

I will use a sample Ruby on Rails app, but this could be done using any other technology stack.

For this post I wrote a simple application with some common vulnerabilities built-in, to test whether or not they are detected by ZAP. If you would like to test it for yourself, you can find it on Github. Follow the readme file and run the test suite (bundle exec rspec).

In this demonstration project, I use rspec and capybara to write and run the integration tests and all of them run in the selenium driver, which I think is a popular and easy approach to demonstrate the concept.

Using the gem owasp_zap is just as easy as setting the proxy information and then when all tests finish, maintain the test server and environment running, while a call is made to start ZAP’s active scan. In the end, when it is done, just close everything gracefully.

Like this:

Environment configuration file: config/environments/test.rb

  Capybara.register_driver :selenium do |app|
    profile = Selenium::WebDriver::Firefox::Profile.new
    proxy = Selenium::WebDriver::Proxy.new({
      type: :manual,
      http: "localhost:8080",
    })
    profile.proxy = proxy
    Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
  end
  Capybara.server_port = 30000

Testing file: spec/spec_helper.rb

  z = Zap.new :target=>'http://127.0.0.1:30000', :zap=>"zap/zap.sh"
  config.before(:suite) do
    z.start :daemon=>true
    sleep(5.0)
    DatabaseCleaner.clean_with(:truncation)
  end

  config.after(:suite) do
    z.ascan.start
    while z.ascan.running?
      sleep(5.0)
    end
    puts z.xml_report
    z.shutdown
    sleep(1.0)
  end

In this example, we use the daemon mode, but if you open the ZAP’s GUI you should see all activity showing up. In this example, we print the XML version of the results when the scan is done but you can retrieve them in other formats.

The results

After running this in our flawed project, ZAP was able to detect almost all the vulnerabilities we introduced, plus other less critical settings that could be improved. The CSRF vulnerability was the only one that wasn’t detected.

I expect that with some more tweaks and extensive test suite the results would improve greatly.

The current results can be checked here

Conclusion

In this post, we have seen that this approach works and can provide us with some useful information. However, this implementation seems clumsy and with external dependencies that aren’t handled by the gemfile.

It would be great if we could have it all bundled with the project, so after the initial setup everything could run independently of its location and be used with our continuous integration process.

Another issue is that we might not want to run security tests every time and with these settings that are simply not possible. Both issues don’t look hard to solve but that will be a topic for another post.

Even though this only scratches the surface of what is needed to run and maintain a secure application, it is a start. Giving you lots of valuable information about potential flaws, when having a security expert on the team is not a possibility.

We hope this information was useful and would like to hear from you about your strategies and tools, so we can make the web a more secure place.

#the-forge

Gonçalo Valério

More posts

Share This Post

The Non-Technical Founders survival guide

How to spot, avoid & recover from 7 start-up scuppering traps.

The Non-Technical Founders survival guide: How to spot, avoid & recover from 7 start-up scuppering traps.

Download for free