En este artículo veremos cómo realizar una automatización de pruebas de seguridad con Selenium y OWASP ZAP. Para ello, necesitaremos previamente descargar la herramienta ZAP y proceder a su instalación. Podemos descargarlo aquí.
¿Qué es ZAP?
ZAP es una herramienta de pruebas de seguridad, más específicamente de penetración (pentesting), para aplicaciones web.
Se comporta como un "man in the middle proxy", de forma que se ubica entre el navegador y la aplicación a probar, y de ese modo por él pasa toda la información. Incluso puede alterar esa información, con el propósito de hacer esas pruebas de pentesting.
Nuestro objetivo
La prueba que desarrollaremos en este post será una conexión con nuestro Jenkins local, ubicado en http://localhost:8080 y probaremos el login a través de Selenium. A su vez, mientras navegamos iremos analizando la aplicación en tiempo real dentro de ZAP.
Al finalizar generaremos el informe HTML con los resultados de las alertas generadas.
Configuración del Proxy en OWASP ZAP
Abrimos la aplicación ZAP y vamos al menú Heramientas > Opciones. Vamos a la opción Proxies locales y configuramos un puerto que tengamos disponible, el cual lo utilizaremos como proxy para ejecutar los tests. En este caso, seleccionamos el puerto 8050:
Opcionalmente podemos desactivar la API KEY, de manera que podamos conectar con ZAP sin tener que introducir la key asignada:
Proyecto de automatización
Creamos un proyecto de automatización de tipo Maven y establecemos estas dependencias en el pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SeleniumOWASP</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.zaproxy</groupId>
<artifactId>zap-clientapi</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.zaproxy</groupId>
<artifactId>zap</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.reporting.outputEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Creamos una nueva clase Java y creamos la siguiente clase, la cual iremos explicando a continuación:
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.zaproxy.clientapi.core.ClientApi;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SeleniumScan {
private static final String ZAP_PROXYHOST = "localhost";
private static final int ZAP_PROXYPORT = 8050;
private static final String ZAP_URL = "http://localhost:8080/";
static WebDriver driver;
public static void main(String args[]) throws Exception {
Proxy proxy = new Proxy();
proxy.setHttpProxy(ZAP_PROXYHOST + ":" + ZAP_PROXYPORT)
.setSslProxy(ZAP_PROXYHOST + ":" + ZAP_PROXYPORT);
WebDriverManager.firefoxdriver().setup();
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.addArguments("--ignore-certificate-errors");
firefoxOptions.setCapability(CapabilityType.PROXY, proxy);
firefoxOptions.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
firefoxOptions.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
driver = new FirefoxDriver(firefoxOptions);
driver.get(ZAP_URL);
driver.findElement(By.name("j_username")).sendKeys("admin");
driver.findElement(By.name("j_password")).sendKeys("admin");
driver.findElement(By.name("Submit")).click();
waitMS(3000);
driver.quit();
ClientApi api = new ClientApi(ZAP_PROXYHOST, ZAP_PROXYPORT);
String Report = new String(api.core.htmlreport(), StandardCharsets.UTF_8);
System.out.println(System.getProperty("user.dir"));
Path filePath = Paths.get(System.getProperty("user.dir") + "/scan-results/seleniumTests.html");
if (!Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) {
Files.createFile(filePath);
}
Files.write(filePath, Report.getBytes());
}
public static void waitMS(int ms) throws Exception {
Thread.sleep(ms);
}
}
En primera instancia definimos las variables del proxy, las mismas definidas dentro de ZAP y definimos la URL que queremos probar, en este caso, la URL de Jenkins:
private static final String ZAP_PROXYHOST = "localhost";
private static final int ZAP_PROXYPORT = 8050;
private static final String ZAP_URL = "http://localhost:8080/";
Instanciamos un objeto Proxy con el proxy y puerto definidos:
Proxy proxy = new Proxy();
proxy.setHttpProxy(ZAP_PROXYHOST + ":" + ZAP_PROXYPORT)
.setSslProxy(ZAP_PROXYHOST + ":" + ZAP_PROXYPORT);
Instanciamos el WebDriver con la configuración de Firefox y le establecemos el proxy definido, además de establecer a true la aceptación de certificados (opcional):
WebDriverManager.firefoxdriver().setup();
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.addArguments("--ignore-certificate-errors");
firefoxOptions.setCapability(CapabilityType.PROXY, proxy);
firefoxOptions.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
firefoxOptions.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
Abrimos el navegador con la URL de Jenkins y hacemos login mediante Selenium. Una vez finalizamos el test, cerramos el driver:
driver = new FirefoxDriver(firefoxOptions);
driver.get(ZAP_URL);
driver.findElement(By.name("j_username")).sendKeys("admin");
driver.findElement(By.name("j_password")).sendKeys("admin");
driver.findElement(By.name("Submit")).click();
waitMS(3000);
Assert.assertEquals(verifyUserLogged(), true);
driver.quit();
Finalmente, conectamos con ZAP y extraemos el informe HTML de resultados:
ClientApi api = new ClientApi(ZAP_PROXYHOST, ZAP_PROXYPORT);
String Report = new String(api.core.htmlreport(), StandardCharsets.UTF_8);
System.out.println(System.getProperty("user.dir"));
Path filePath = Paths.get(System.getProperty("user.dir") + "/scan-results/seleniumTests.html");
if (!Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) {
Files.createFile(filePath);
}
Files.write(filePath, Report.getBytes());
Si abrimos el fichero HTML generado, podremos ver las alertas:
En ZAP, mientras ejecutamos el test, podremos ver la evolución de las pruebas de seguridad:
Conclusión
En resumen, gracias a la automatización de pruebas de seguridad con Selenium, podremos analizar la seguridad de nuestras aplicaciones, reduciendo el tiempo de pruebas y, asimismo, verificando el correcto funcionamiento funcional de las mismas.
Si te ha gustado, ¡síguenos en Twitter para estar al día de nuevos posts!