static analysis saved my code tonight
TRANSCRIPT
STATIC ANALYSIS SAVED MY CODE TONIGHT
PHP UK, LONDON, FEBRUARY 2017.
PHPUK 2017
AGENDA
‣ Under the hood of a static analyzer
‣ What can analyzers do for you
‣ Adopt them now!
‣ Damien Seguy
‣ CTO at exakat
‣ Static code analysis for PHP
‣ Retiring house for oldest elephpant
PHPUK 2017
SPEAKER
Elephpant in the death valley
‣ IS IT FAST?‣ IS THIS BACKWARD COMPATIBLE?
‣ IS THIS SECURE? ‣ IS THIS COMPATIBLE WITH PHP 7?
‣ SHOULD I USE ++$I OR ARRAY_MERGE_RECURSIVE() ?
‣ IS IT TIME FOR LUNCH ?
‣ WHY NOT USE A FRAMEWORK?
PHPUK 2017
STATIC ANALYSIS IS AN EXTRA STEP
EXECUTION
TEXT FILE
OPCODE
CODING CONVENTIONS
PHPUK 2017
STATIC ANALYSIS IS AN EXTRA STEP
EXECUTION
TEXT FILE
OPCODE STATIC ANALYSIS
OPCODE
PHPUK 2017
STATIC ANALYSIS IS AN EXTRA STEP
EXECUTION
TEXT FILE
STATIC ANALYSIS
PHPUK 2017
SWITCH STATEMENTS MAY ONLY CONTAIN ONE DEFAULT CLAUSE
<?php
switch($x) { case '1' : break; default : break; default : break; case '2' : break; }
PHP Lint
PHPUK 2017
SWITCH STATEMENTS MAY ONLY CONTAIN ONE DEFAULT CLAUSE
switch($x) { case 1 : break; case 0+1 : break; case '1' : break; case true : break; case 1.0 : break; case $y : break; }
PHPUK 2017
STATIC ANALYSIS UNDER THE HOOD
PHP 5 / 7 Calisthenics ClearPHP Performance Metrics Couplings
PHPUK 2017
PHP TOKENS [248] => Array ( [0] => 382 [1] => [2] => 167 )
[249] => Array ( [0] => 319 [1] => define [2] => 167 )
[250] => ( [251] => Array ( [0] => 323 [1] => 'EXT' [2] => 167 )
[252] => , [253] => Array ( [0] => 382 [1] => [2] => 167 )
‣ Comments, Doc, whitespace
‣ Delimiters : " () {} [] `
‣ 2/3 of the tokens are removed
<?php //.... define('EXT', '.php');
PHPUK 2017
AST
‣ PHP 7.0 : ext/ast
‣ nikic/php-parser
PHPUK 2017
AST
<?php
class Foo { function bar($arg) { return \StrToUpper($arg + 2); } }
$foo = new Foo(); $foo->bar(__FILE__);
TEXTE
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
FLOW CONTROL
TEXTE
FLOW CONTROL GRAPH
$x = source();
if ($x < 10)
$y = $x + 1;
$x = corrige($y);
$y = $x;
PHP
Exit
ElseThen
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
PHPUK 2017
PROGRAM DEPENDENCY GRAPH
$x = source();
if ($x < 10)
$y = $x + 1;
$x = corrige($y);
$y = $x;Depend de $x
Depend de $x
Depend de $y
Depend de $x
Depend de $x
Depend de $x
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
PHPUK 2017
PHP AS A CODE DATABASE
‣ Source code is a highly organized dataset
‣ We need a way to query it
‣ There are over 68 static analysis tools for PHP
‣ https://github.com/exakat/php-static-analysis-tools
PHPUK 2017
STATIC ANALYSIS TOOLS
▸ Migration tools
▸ Code quality
▸ Security tools
▸ Metrics
▸ Inventories
PHPUK 2017
MIGRATION TOOLS
‣ Exakat
‣ php7mar
‣ php7cc
EXAKAT REPORT FOR PHP 7.2 COMPATIBILITY
PHPUK 2017
CODE QUALITY
‣ PHPstan
‣ Phan
‣ Psalm
‣ Exakat
PHPSTAN REPORT ------ ---------------------------------------------
Line code/functions/scripts/pingCheck.php
------ ---------------------------------------------
362 Instantiated class phpipam_mail not found.
415 Function create_link not found.
446 Catched class phpmailerException not found.
------ ------------------------------------
Line code/index.php
------ ------------------------------------
228 Undefined variable: $heredoc
------ ----------------------------------------
Line library/Exakat/Tasks/Files.php
------ ----------------------------------------
197 Undefined variable: $toRemoveFromFiles
------ ------------------------------------------------
Line code/functions/scripts/resolveIPaddresses.php
------ ------------------------------------------------
236 Undefined variable: $returnPath
[ERROR] Found 1846 errors
PHPUK 2017
SECURITY TOOLS
‣ psecio:parse
‣ php vuln hunter
‣ RIPS 0.5 / Ripstech saas$x = source();
if ($x < 10)
$y = $x + 1;
$x = corrige($y);
$y = $x;Depend de $x
Depend de $x
Depend de $y
Depend de $x
Depend de $x
Depend de $x
PSECIO REPORT55) projects/phpipam/code/app/dashboard/widgets/inactive-hosts.php on line 40
Avoid the use of $_REQUEST (know where your data comes from)
> if(!$widget = $Tools->fetch_object ("widgets", "wfile", $_REQUEST['section'])) { $Result->show("danger", _("Invalid widget"), true); }
For more information execute 'psecio-parse rules RequestUse'
296) functions/classes/class.Tools.php on line 2762
Avoid the use of `exit` or `die` with strings as it could lead to injection issues (direct output)
> $outFile = file_get_contents(dirname(__FILE__) . '/../../app/subnets/import-subnet/upload/import.csv') or die ($this->Result->show("danger", _('Cannot open upload/import.csv'), true));
For more information execute 'psecio-parse rules ExitOrDie'
448) index.php on line 284
'header()' calls should not use concatenation directly
> if (!in_array($_GET['section'], $tools_menu_items)) { header("Location: ".create_link("error","400")); die(); }
For more information execute 'psecio-parse rules SetHeaderWithInput'
PHPUK 2017
METRICS
‣ PHP Metrics
‣ PHP MD
‣ PHP LOC
PHPMETRICS REPORT
PHPMETRICS REPORT
PHPUK 2017
INVENTORIES
‣ Collection of names, literals, features
‣ Magic number syndrome
‣ PHP compilation directives
‣ Error messages check
‣ Spelling, consistency…
‣ Exakat
INVENTORY REPORT
PHP COMPILE SCRIPT;;;;;;;;;;;;;;;;;;;;;;;; ; PHP configure list ; ;;;;;;;;;;;;;;;;;;;;;;;;
./configure --with-apxs2 --enable-bcmath --with-curl=DIR --disable-dom --enable-exif --disable-fileinfo --with-gd --with-jpeg-dir=DIR --with-png-dir=DIR --with-xpm-dir=DIR --with-vpx-dir=DIR --with-freetype-dir=DIR --enable-gd-native-ttf --with-gettext=DIR --with-gmp --with-ldap[=DIR] --with-ldap-sasl[=DIR] --disable-libxml --enable-mbstring --with-libmbfl=DIR --enable-mbstr-enc-trans --disable-mbregex --with-mcrypt=[DIR] --with-openssl[=DIR]
; Duration of time (in seconds) for which to cache realpath information for a ; given file or directory. If the application's code doesn't change too often, you ; may set this directive to 3600 (one hour) or even more. realpath_cache_ttl = 3600
; More information about file : ;http://php.net/manual/en/filesystem.configuration.php
[File Upload] ; This is the maximum uploaded size. It is recommended to keep this value as low ; as possible. upload_max_filesize = 2M
; This is the maximum number of uploaded files in a single request. max_file_uploads = 1
; Upload directory where PHP stores the temporary files. It is recommended to set ; this value, and separate it from other temporary directories. upload_tmp_dir = /tmp/php_upload
; This is the maximum amount of data that PHP will accept in a POST request. It ; has to be higher or equal to upload_max_filesize. For security reasons, it ; should be as low as possible, to prevent PHP using too much memory. post_max_size = 2M
PHP DIRECTIVES CHECKLIST
PHPUK 2017
OTHER USAGE
▸ Dependency graph
▸ Namespaces graph
▸ Deptrack
▸ Taint analysis
PHPUK 2017
WRITE YOUR OWN STATIC ANALYSER
▸ ext/ast : Access the internal AST
▸ nikic/php-parser : for PHP 7
▸ BetterReflection
▸ Fork an existing tool
▸ Use regex
PHPUK 2017
MORE IDEAS
▸ Static analysis for frameworks
▸ Class diagram extractors
▸ Definition / usage paradigm
▸ More coding references
▸ East-programming, SOLID
▸ ~40% of PHP code is static
TEXTE
NEVER CODE ALONE AGAIN
▸ Use experience from others
▸ Use some one else point of view
▸ Prepare for the future
▸ Learn, Find, Capitalize