Friday, 16 October 2015

ZAP and Selenium - Security testing in continuous integration

When you are working in an agile environment where the builds are rapidly delivered, it becomes very difficult to perform a security scanning on the application on every build that gets delivered. Integrating ZAP scanning tool eliminates the need of manually performing security tests. ZAP can be easily integrated with the existing UI automation framework, by which you would be extending your UI automation test suites to perform security scanning as well.
 
This blog shows how ZAP can be integrated with UI automation framework. This blog gives only a high level information or overall structure for integrating security testing in UI automation framework. We will be using ZAP's java APIs in this example.


1. Installing ZAP in the SUT.
Install ZAP application in the system where security testing has to be executed. You can go to the OWASP site to download the latest version of ZAP.
https://github.com/zaproxy/zaproxy/wiki/Downloads?tm=2

2.Configure ZAP libraries in the project.
Download the ZAP java libraries and configure the same in the build path.
https://github.com/zaproxy/zaproxy/releases
Some of the important libraries that should be present are
zap-api-v2-6.jar
zap.jar
client-demo-1.2-jar-with-dependencies.jar

3. Integrate ZAP APIs in the automation code.
Step 1:
Start the ZAP Process. 

ZAP_LOCATION = "<Location of ZAP>";
SAVE_SESSION_DIRECTORY = "<Path to save sessions">

    String line;
       if(<You are in a windows machine>) {
                String[] command = { "CMD", "/C", this.ZAP_LOCATION + "ZAP.exe" };
                ProcessBuilder buildProc = new buildProcessBuilder(command);
                buildProc.directory(new File(this.ZAP_LOCATION));
                buildProcess p = buildProc.start();
                p.waitFor();
                BufferedReader ipBuf = new BufferedReader(new ipBufStreamReader(
                        p.getipBufStream()));
                OutputStreamWriter oStream = new OutputStreamWriter(
                        p.getOutputStream());
                oStream.write("buildProcess where name='ZAP.exe'");
                oStream.flush();
                oStream.close();
                while ((line = ipBuf.readLine()) != null) {
                //kludge to tell when ZAP is started and ready
                if (line.contains("INFO") && line.contains("org.parosproxy.paros.control.Control") 
                &&   line.contains("New Session")) {
                ipBuf.close();
                break;
              }
     } else {
String[] command = { "/usr/bin/xterm","-e","/home/user/jdk1.7.0_13/bin/java","-jar",this.ZAP_LOCATION + "zap.jar" };
ProcessBuilder proc = new ProcessBuilder(command);
proc.directory(new File(this.ZAP_LOCATION));
Process p = proc.start();
Thread.sleep(20000);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
OutputStreamWriter oStream = new OutputStreamWriter(p.getOutputStream());
oStream.write("process where name='ZAP.exe'");
oStream.flush();
oStream.close();
Thread.sleep(5000);
}

 Step 2:
Start the ZAP session: 
public void startSession(String zapaddr, int zapport) {
        ClientApiMain.main(new String[] { "newSession", "zapaddr=" + zapaddr, "zapport=" + zapport  });
        System.out.println( "session started" );
        System.out.println("Session started successfully.");
}

At this point ZAP session will be open. All the actions performed in the UI will be recorded in the ZAP session. These recorded URLs will be later used for security testing.

Step 3:
Open the browser and your website with a predefined proxy configured in the ZAP:
Example for firefox browser:

profile.setPreference("network.proxy.http","localhost");
profile.setPreference("network.proxy.http_port",9443);
profile.setPreference("network.proxy.ssl","localhost");
profile.setPreference("network.proxy.ssl_port",9443);
profile.setPreference("network.proxy.type", 1);
profile.setPreference("network.proxy.no_proxies_on", "");
firefoxDriver = new FirefoxDriver(profile);

Step 4:
Execute the automated test suites using the same firefox driver.
After this step, all the get/post URLs would have recorded in the active ZAP session.

Step 5:
Perform an automated security scan on the recorded URL:

String pattern = "<App URL Host_or_Ip Address>;
if( CommonConfig.zap.ascan( api, "https://"+pattern+":8443" ) == false ) {
   System.out.println( "Scanning Failed - see console for details. Continuing..." );
}

//Method of scanning
public boolean ascan(ClientApi api, String ZAP_URI_PORT) {
        try {
            System.out.println("Active scan starting...");
            api.ascan.scan(ZAP_URI_PORT, null, null);
            while (api.ascan.status().toString(0).contains("100") == false) {
                System.out.println("active scan progress: "    + api.ascan.status().toString(0));
                try {
                    Thread.sleep(300); //basically printing status every 5 seconds
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("progress: " + api.ascan.status().toString(0));
            return true;
        } catch (ClientApiException ex) {
            ex.printStackTrace();
            return false;
        }
    }

Generate a report for the scan:
URL url = new URL("http://localhost:9443/XML/core/view/alerts/?zapapiformat=XML&baseurl=https%3A%2F%2F"+pattern+"&start=&count=");
URLConnection conn = url.openConnection();
org.w3c.dom.Document dom =  docBuilder.parse(conn.getInputStream());

the dom can be now used to filter the false results and generate the final result file as required.

Hope this post is useful for those who are trying to perform automated security scan as part of continues integration. 
Please post you comments and questions.