Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical PHP Security

Practical PHP Security

PHP has a pretty bad track record of insecure applications. Fortunately, today we use components like Doctrine and Twig to make our applications secure by default (for the most part) from SQL Injection and XSS. But there are still plenty of other gotchas and sources of vulnerabilities that are written everyday. This talk will cover some common insecure practices that are perhaps less well known than SQL injection and cross-site scripting (XSS), and how to fix them.

Will Donohoe

August 18, 2015
Tweet

More Decks by Will Donohoe

Other Decks in Programming

Transcript

  1. SQLi and XSS • SQL Injection and Cross Site Scripting

    • #1 and #3 respectively on OWASP Top 10 • https://secure.php.net/manual/en/ security.database.sql-injection.php • http://www.sitepoint.com/php-security-cross-site- scripting-attacks-xss/
  2. $input = json_decode($_GET['data'], true); if ($input['auth_token'] == 'my_secret_auth_token') { echo

    'Authorised!'; } else { echo 'You are not authorised'; } int(0)== any string that isn’t a number data={"auth_token": 0}
  3. Route::filter('csrf', function() { if (Session::token() != Input::get('_token')) { throw new

    Illuminate\Session\TokenMismatchException; } }); Speaking of Laravel… “On November 7th, Chris Smith (@chrismsnz) of Insomnia Security alerted the Laravel development team of a method of bypassing the CSRF verification in Laravel 4 applications.”
  4. Comparison is hard • Lots of stuff == lots of

    other weird stuff • Use === by default, typecast if you need to • Use hash_equals for hashes or tokens • Use == only if you have a really good reason • https://php.net/manual/en/types.comparisons.php • See Natas Level 24 in OTW (strcmp)
  5. Doctrine is great but… $search = $_GET['search']; if (strlen(trim($search)) <

    3) { die('Invalid'); } $qb = $entityManager->createQueryBuilder(); $qb->select('u') ->from('User', 'u') ->where($qb->expr()->like('u.name', ':search')) ->orderBy('u.name', 'ASC') ->setParameter('search', $search . '%'); $result = $qb->getQuery()->getResult(); search=%%%
  6. The Fix • Docs will not help you: make no

    reference to this problem when using LIKE • So just use addcslashes to escape % and _ • https://doctrine-orm.readthedocs.org/en/latest/ reference/query-builder.html#high-level-api- methods • https://doctrine-orm.readthedocs.org/en/latest/ reference/query-builder.html#the-expr-class
  7. $search = $_GET['search']; if (strlen(trim($search)) < 3) { die('Invalid'); }

    $search = addcslashes($search, '%_'); $qb = $entityManager->createQueryBuilder(); $qb->select('u') ->from('User', 'u') ->where($qb->expr()->like('u.name', ':search')) ->orderBy('u.name', 'ASC') ->setParameter('search', $search . '%'); $result = $qb->getQuery()->getResult(); The Fix
  8. https://www.sektioneins.de/en/blog/15-07-31- php_challenge_2015.html <?php $users = array( "0:c42d47602bc29f89644841702ca0ebf6", // UserID, md5

    of pass "1:084e0343a0486ff05530df6c705c8bb4" // md5('guest') ); $input = $_COOKIE['user']; $input[1] = md5($input[1]); foreach ($users as $user) { $user = explode(":", $user); if ($input === $user) { $uid = $input[0] + 0; } } if ($uid === 0) { die("Hello admin, have some secrets"); } http://3v4l.org/sELBf
  9. Why? • PHP 5.5.27/5.6.11 was released on 10 July 2015

    (http://www.php.net/ChangeLog-5.php) • "Fixed bug #69892 (Different arrays compare indentical due to integer key truncation).” • 4294967296 == 0x100000000 (larger than 32 bits, but least significant 32 bits are 0)
  10. serialize/unserialize • More harmful than it looks • Except if

    you read the entire doc page on it But how?
  11. class Logger { public $logFile; public $buffer; public $fh; public

    function __destruct() { $this->WriteBuffer(); } public function WriteBuffer() { if (!$this->fh) { $this->fh = fopen($this->logFile, 'w'); } fwrite($this->fh, $this->buffer); } // ... } // ... $cookieData = unserialize($_COOKIE['data']); // ...
  12. Other Problems • CSRF • .git folder accessible publicly
 https://github.com/jkingsman/get-git

    • nginx + php-fpm misconfiguration - mistakenly running code in uploaded files • Local file inclusion with PHP filters • Remember that $_GET, $_POST, $_COOKIE can contain arrays! (Watch out for hash functions)
  13. • Length extension • HEAD request stops execution on output

    • app_dev.php for Symfony • Stop execution by closing connection Other Problems
  14. In Summary • Validate your inputs • Validate your outputs

    • Be aware of the oddities of the tools you use • Update early and often