Controler automatiquement la sécurité de ses dépendances avec SensioLabs security checker, Jenkins et Phing
Aujourd'hui, nous incluons toujours plus de librairies externes dans nos projets. Même si on gagne beaucoup de temps, il n'est pas exclu que nous introduisions des failles de sécurité via ces lib. Ce contrôle n'est malheureusement pas systématique mais surtout rarement automatisé. Depuis quelques temps, SensioLabs propose un service pour réferencer des failles (CVE) dans des librairies ainsi que l'outil Security Checker pour controller les dépendances de son projet via le fichier composer.lock.
Security Checker
On peut trouver cet outil sur Github sous la forme d'un Phar ou en librairie à ajouter à notre projet. Pour l'exemple j'utilise la version Phar que j'ai ajouté dans mon path pour faciliter son utilisation. J'ai créé un projet vide en ajoutant des versions de librairies connues pour avoir une faille. L'utilisation de security checker est simple et le résultat très explicite.
~/blog$ security-checker.phar security:check ./composer.lock Security Check Report ~~~~~~~~~~~~~~~~~~~~~ Checked file: /home/ulrich/blog/composer.lock [CRITICAL] 3 packages have known vulnerabilities doctrine/doctrine-bundle (v1.2.0) --------------------------------- * CVE-2015-5723: Security Misconfiguration Vulnerability in various Doctrine projects http://www.doctrine-project.org/2015/08/31/security_misconfiguration_vulnerability_in_various_doctrine_projects.html doctrine/orm (v2.3.6) --------------------- * CVE-2015-5723: Security Misconfiguration Vulnerability in various Doctrine projects http://www.doctrine-project.org/2015/08/31/security_misconfiguration_vulnerability_in_various_doctrine_projects.html zendframework/zend-json (2.2.1) ------------------------------- * Potential XXE/XEE attacks using PHP functions: simplexml_load_*, DOMDocument::loadXML, and xml_parse http://framework.zend.com/security/advisory/ZF2014-01 This checker can only detect vulnerabilities that are referenced Disclaimer in the SensioLabs security advisories database. Execute this command regularly to check the newly discovered vulnerabilities.
Automatisation
Comme beaucoup (j'espère) j'utilise un outil d'intégration continue, Jenkins dans mon cas. Et pour builder mon projet j'utilise Phing qui est un super outil, si si, même s'il n'est plus tout jeune. C'est donc l'occasion de parler un peu de Phing et de montrer comment faire une tâche un peu plus "intelligente". A la fin de l'article j'ai ajouté les équivalent pour Ant and Jenkins Pipeline.
Basiquement je pourrais créer une tâche ainsi:
<project name="checksecu" basedir="." default="secu"> <target name="secu"> <exec executable="security-checker.phar"> <arg value="security:check" /> <arg path="./composer.lock" /> </exec> </target> </project>
Et l'exécution donne:
~/blog$ phing.phar -f ../jenkinsbuildconf/checksecu.xml Buildfile: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml checksecu > secu: BUILD FINISHED Total time: 0.4584 seconds
Le problème c'est que, d'une part je n'ai aucun retour, et surtout le build n'est pas considéré comme étant en erreur. Pour traiter le premier problème, il me suffit de renvoyer la sortie du script dans une variable via outputProperty et de l'afficher. Pour le second problème je peux utiliser checkreturn, ce qui me donne:
<project name="checksecu" basedir="." default="secu"> <target name="secu"> <exec executable="security-checker.phar" outputProperty="output" checkreturn="true"> <arg value="security:check" /> <arg path="./composer.lock" /> </exec> <echo message="output: ${output}" /> </target> </project>
et mon execution devient:
~/blog$ phing.phar -f ../jenkinsbuildconf/checksecu.xml Buildfile: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml checksecu > secu: Execution of target "secu" failed for the following reason: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:6:60: Task exited with code 1 BUILD FAILED /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:6:60: Task exited with code 1 Total time: 0.9041 seconds
Super mon build failed, mais je n'ai pas la sortie de security-checker.phar ce qui est embettant. Je vais donc remplacer checkreturn par returnProperty pour stocker dans une variable l'exit code de la commande puis le tester avec un if.
<project name="checksecu" basedir="." default="secu"> <target name="secu"> <exec executable="security-checker.phar" outputProperty="output" returnProperty="return"> <arg value="security:check" /> <arg path="./composer.lock" /> </exec> <if> <equals arg1="${return}" arg2="1" /> <then> <echo message="output: ${output}" /> <fail message="Le composer.lock montre que le projet se base sur des libs ayant des CVE." /> </then> </if> </target> </project>
Ce qui me donne à l'exécution:
~/blog$ phing.phar -f ../jenkinsbuildconf/checksecu.xml Buildfile: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml checksecu > secu: [echo] output: Security Check Report ~~~~~~~~~~~~~~~~~~~~~ Checked file: /home/ulrich/blog/composer.lock [CRITICAL] 3 packages have known vulnerabilities doctrine/doctrine-bundle (v1.2.0) --------------------------------- * CVE-2015-5723: Security Misconfiguration Vulnerability in various Doctrine projects http://www.doctrine-project.org/2015/08/31/security_misconfiguration_vulnerability_in_various_doctrine_projects.html doctrine/orm (v2.3.6) --------------------- * CVE-2015-5723: Security Misconfiguration Vulnerability in various Doctrine projects http://www.doctrine-project.org/2015/08/31/security_misconfiguration_vulnerability_in_various_doctrine_projects.html zendframework/zend-json (2.2.1) ------------------------------- * Potential XXE/XEE attacks using PHP functions: simplexml_load_*, DOMDocument::loadXML, and xml_parse http://framework.zend.com/security/advisory/ZF2014-01 This checker can only detect vulnerabilities that are referenced Disclaimer in the SensioLabs security advisories database. Execute this command regularly to check the newly discovered vulnerabilities. Execution of target "secu" failed for the following reason: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:11:12: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:15:30: Le composer.lock montre que le projet se base sur des libs ayant des CVE. BUILD FAILED /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:11:12: /home/ulrich/blog/../jenkinsbuildconf/checksecu.xml:15:30: Le composer.lock montre que le projet se base sur des libs ayant des CVE. Total time: 0.4784 seconds
Et voilà! Il ne me reste plus qu'a ajouter cette tâche dans mon build général de phing pour que Jenkins teste systèmatiquement si mon projet se base sur une version ayant une CVE connue. Pour ceux qui prèfere Ant à Phing, je pense que cette tache peut être très facilement transposable si pas réutilisable tel quel.
Si vous utilisez Ant plutôt que Phing, voici la code de la tache que vous pouvez ajouter à votre fichier de build:
<target name="checks:security" description="Checks if there is some security issues in our back-end dependencies"> <exec executable="security-checker.phar" failonerror="true"> <arg line="security:check composer.lock"/> </exec> </target>
Si vous utilisez Pipeline dans Jenkins, voici la déclaration de mon Jenkinsfile:
stage ('Check Security') { steps { sh 'security-checker.phar security:check composer.lock' } }
Ajouter un commentaire