Automated code audits

25
Automatic code audits Rotterdam, Nederland, October 9th 010PHP

description

Even nowadays, PHP code is mostly manually audited. Expert pore over actual code, in search for bugs or code smells. Actually, it is possible to have PHP do this work itself ! Strengthened with the internal Tokenizer, bolstered by the manual, it is able to scan thousands of lines of code, without getting bored, and bringing pragmatic pieces of wisdom: official manual recommendations, version migration, code pruning and security. In the end, it deliver a global overview of the code, without reading it.

Transcript of Automated code audits

Page 1: Automated code audits

Automatic code audits

Rotterdam, Nederland, October 9th 010PHP

Page 2: Automated code audits

Definition

A kind of code analysis where the code is reviewed without running it.

Just like we would do ourselves!

Page 3: Automated code audits

Who is speaking?

Damien Seguy

CTO at exakat

Phather of the plush toy elePHPant

Back from China

Stepping up automated code audit services

Page 4: Automated code audits
Page 5: Automated code audits

Internals

Code

Analyze Report

AST

Page 6: Automated code audits
Page 7: Automated code audits

<?php!function x($a) {         return $a;} x(1, 2); ?>

Page 8: Automated code audits

Found

Dead code

Undefined structures

Unused structures

Illogical exp.

Slow code

Bad practices

Unsafe code

Maintainability

Bug issue

Ancient style

Uninitialized vars

Taint propagation

Page 9: Automated code audits

<?phpswitch ($this->consume()){     case "\x09":    case "\x0A":    case "\x0B":    case "\x0B":    case "\x0C":    case "\x20":    case "\x3C":    case "\x26":    case false:        break;    case "\x23":        switch ($this->consume())        {            case "\x78":            case "\x58":                $range = '0123456789ABCDEFabcdef';                $hex = true;                break;        }    }{?>

Page 10: Automated code audits

    protected function openString($end, &$out=null, $nestingOpen, $rejectStrs = null) {         $nestingLevel = $count = 0;        $content = array();        while ($this->match($patt, $m, false)) {             $tok = $m[2];            if ($tok == "@{" && $this->interpolation($inter)) {                 $content[] = $inter;                continue;            }            if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {                 $ount = null;                break;            }            $content[] = $tok;            $count += strlen($tok);        }        $this->eatWhiteDefault = $oldWhite;        if (count($content) == 0) return false;        $out = array("string", "", $content);        return true;    }

Page 11: Automated code audits

Spot bugs early

Code Test PreProd Production

Run it at commit Run it as audit

Page 12: Automated code audits

Static audit vs Unit test

No running

100% of the code

Symbolic testing

Little configuration

Has false positive

Mostly internal

Needs dedicated servers

Will only scan a part

Test only provided data

Write scenario

Has false negative

Can be handed to users

Page 13: Automated code audits

When does it help

Help port to a new system

Search for weak code fragments

Audit external libraries

Hint at refactoring

Page 14: Automated code audits

Report

Bugs

Useless code

Suggestions

Page 15: Automated code audits

Bugs

<?php !!  if($content = file_get_contents($file))    {        $content = trim($content);        $content = substr($content, -2) == '?>' ? substr($content, 0, -2) : $content;    } ! return true;!?> !

Page 16: Automated code audits

Useless code<?php!!// inside a legit class $this->module->xmlRequest;$_G['setting']['debug'];$post['usesig'] ? ($_G['setting']['sigviewcond'] ?  (strlen($post['message']) > $_G['setting']['sigviewcond'] ?!! ! ! !  $post['signature'] : '') !! ! ! ! ! : $post['signature']) : '';?> !

Page 17: Automated code audits

Suggestions

<?php !// Nested ternary should be turned into if then structures     $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time( ) : 0) . substr(md5($string . $egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length))    // Multiply by one is useless     SetCache($prefix, $key, $row, 60*60*1);

// Portable syntax     $bits = split('.', $string);    $y = $bits[0];     ! // Modern syntax     $y = split('.', $string)[0];?> !

Page 18: Automated code audits

Where it doesn’t help

Unit tests

Architecture

Old traditions that won’t change

Semantic errors

Page 19: Automated code audits

Architecture

No framework context

Conception is done before coding

Of course!

Static audit will report standards, not norms

Page 20: Automated code audits

Old traditions

<?php    $pna = explode(')(', $pn);    while (list($k, $v) = each($pna)) {        $lst = explode('"', $v);        if (isset($lst[3])) {            $pn[$lst[1]] = $lst[3];        } else {            $pn[$lst[1]] = '';        }    } ?>

10 % of current applications uses this instead of foreach()

Page 21: Automated code audits

Semantic errors

<?php     $babycarriage = new carriage();     $wheel1 = new Racingwheel();     $wheel2 = new Racingwheel();     $wheel3 = new Racingwheel();     $wheel4 = new Rhinoceros();         $babycarriage->installWheels($wheel1, ## # # # # # # # # # # # $wheel2, ## # # # # # # # # # $wheel3, ## # # # # # # # # # $wheel4);     ?>

Undefined classes : Vehicle, Racingwheel, Rhinoceros

Page 22: Automated code audits

Semantic errors

Page 23: Automated code audits

Available analyzers

PHP code sniffer

PHP MD

Scrutinizer-ci

Fortify

insight from Sensio

Page 25: Automated code audits

THE END

http://010php.nl/

http://www.meetup.com/010PHP/