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

Modern and Secure PHP (SoutheastPHP 2018)

Modern and Secure PHP (SoutheastPHP 2018)

This is not the PHP of old. Learn what's changed in the PHP world over the last few years. Classes, objects, statics, traits, unit testing, composer, password hashing, standards; it's a whole new ballgame.

Ben Edmunds

August 17, 2018
Tweet

More Decks by Ben Edmunds

Other Decks in Technology

Transcript

  1. PHP
    modern
    & secure

    View Slide

  2. Who is this guy?
    Ben Edmunds
    Open Source
    Author
    PHP Town Hall Podcast
    CTO at Mindfulware

    View Slide

  3. Who is this guy?
    Ben Edmunds
    @benedmunds
    http://benedmunds.com

    View Slide

  4. Welcome to
    the Future

    View Slide

  5. Great Scott!

    View Slide

  6. Welcome to the Future
    PDO

    Closures

    Namespaces

    View Slide

  7. Welcome to the Future
    Anonymous Classes

    Traits

    Interfaces

    View Slide

  8. Welcome to the Future
    Null Coalescing

    Scalar Type Hints

    Return Type Declarations

    View Slide

  9. Welcome to the Future
    Variadic Functions

    Authentication

    Password Hasing

    View Slide

  10. Welcome to the Future
    SQL Injection

    HTTPS

    View Slide

  11. Welcome to the Future
    Common Hacks

    View Slide

  12. Legit Tools
    Built-in Server

    Composer

    Unit Testing

    View Slide

  13. Standards
    PHP-FIG
    PSRs

    View Slide

  14. Exceptions

    View Slide

  15. View Slide

  16. Exceptions
    try {

    //your code goes here

    }

    catch (Exception $e) {

    die($e->getMessage());

    }

    View Slide

  17. Exceptions
    try {

    //your code goes here

    }

    catch (Exception $e) {

    die($e->getMessage());

    }

    View Slide

  18. Errors
    Exception implements Throwable
    Error implements Throwable

    View Slide

  19. Errors
    try {

    //error thrown here

    }

    catch (Error $e) {

    die($e->getMessage());

    }

    View Slide

  20. Errors
    try {

    //error thrown here

    } catch (Error $e) {

    die($e->getMessage());

    } catch (Exception $e) {

    die($e->getMessage());

    }

    View Slide

  21. Errors
    try {

    //err or excpt thrown here

    } catch (Throwable $t) {

    die($t->getMessage());

    }

    View Slide

  22. Errors
    try {

    //error or excpt thrown here

    } catch (Error | Exception $e) {

    die($e->getMessage());

    }

    View Slide

  23. Namespaces

    View Slide

  24. View Slide

  25. Namespaces
    namespace Illuminate\Console;

    class Command

    {

    //…

    View Slide

  26. Namespaces
    use Illuminate\Console\Command;
    namespace Illuminate\Console;

    class Command

    {

    //…

    View Slide

  27. Namespaces
    use Illuminate\Console\Command;
    namespace Illuminate\Console;

    class Command

    {

    //…

    View Slide

  28. PDO

    View Slide

  29. View Slide

  30. PDO
    Cross System
    Safe Binding

    View Slide

  31. PDO
    $stmt = $db->prepare(‘

    SELECT * FROM users

    WHERE id=:id

    ’);

    $stmt->bindParam(‘:id’, $id);

    $stmt->execute();

    View Slide

  32. Traits

    View Slide

  33. Traits
    // grouping without

    // strict inheritance

    trait baseUser {

    function getName() {

    return ‘Jon Snow’;

    }

    }

    View Slide

  34. Traits
    class adminUser {

    use baseUser;

    }

    View Slide

  35. Traits
    $adminUser = new adminUser;

    echo $adminUser->getName();

    //output = ‘Jon Snow’

    View Slide

  36. Traits
    trait Loggable {

    function log($msg) {

    echo $msg;

    }

    }

    View Slide

  37. Traits
    class Post {

    function get($id) {

    return $this->db->get($id);

    }

    }

    View Slide

  38. Traits
    class Post {

    use Loggable;

    function get($id) {

    $this->log('Getting post ' . $id);

    return $this->db->get($id);

    }

    }

    View Slide

  39. Traits
    $postModel = new Post;

    $myPost = $postModel->get(1);

    //output = ‘Getting post 1’

    View Slide

  40. Traits
    class Post extends Model

    {

    use SoftDeletes;

    }

    View Slide

  41. Interfaces

    View Slide

  42. Interface
    Class myLogger

    {

    public function log($msg) {

    echo $msg;

    }

    }

    View Slide

  43. Interface
    interface Logger

    {

    public function log($msg);

    }

    View Slide

  44. Interface
    Class myLogger implements Logger

    {

    public function log($msg) {

    echo $msg;

    }

    }

    View Slide

  45. Closures

    View Slide

  46. View Slide

  47. Closures
    Route::get(‘/', function(){



    return View::make(‘index');

    });

    View Slide

  48. Closures
    Route::get(‘/', function(){



    return View::make(‘index');

    });

    View Slide

  49. Closures
    $input = [1, 2, 3, 4, 5, 6, 7, 8];

    $output = array_filter($input, function($v){

    return $v > 5;

    });

    // [6,7,8]

    View Slide

  50. Closures
    $input = [1, 2, 3, 4, 5, 6, 7, 8];

    $output = array_map(function($n){

    return number_format($n * 10, 2) . '%';

    }, array_filter($input, function($v){

    return $v > 5;

    }));

    // ['60.00%', '70.00%', '80.00%']

    View Slide

  51. Anonymous
    Classes

    View Slide

  52. Anonymous Classes
    trait Loggable {

    function log($msg) {

    echo $msg;

    }

    }

    View Slide

  53. Anonymous Classes
    interface Logger

    {

    public function log($msg);
    }

    View Slide

  54. Anonymous Classes
    trait Loggable {

    protected $logger;

    function setLogger(Logger $logger) {

    $this->logger = $logger;

    }

    function log($msg) {

    $this->logger->log($msg);

    }

    }

    View Slide

  55. Anonymous Classes
    class Post { use Loggable; }

    $post = new Post;

    View Slide

  56. Anonymous Classes
    class Post { use Loggable; }

    $post = new Post;

    $post->setLogger(

    new class implements Logger {

    public function log($msg) {

    echo date('m/d G:i') . ': ' .$msg;

    }

    });

    View Slide

  57. Anonymous Classes
    $postModel = new Post;

    $myPost = $postModel->get(1);

    //output = ‘09/08 16:20: Getting post 1’

    View Slide

  58. Null
    Coalescing
    Operator

    View Slide

  59. Null Coalescing
    $val = isset($_GET[‘val’]) ?

    $_GET[‘val’] : 'default';

    View Slide

  60. Null Coalescing
    $val = $_GET['val'] ?? 'default';

    View Slide

  61. Null Coalescing
    $val = $_GET['val'] ?? 'default';

    View Slide

  62. Types!

    View Slide

  63. View Slide

  64. Scalar Type
    Hinting

    View Slide

  65. Types
    declare(strict_types=1);

    function addNums(float $a, float $b) {

    return $a + $b;

    }

    View Slide

  66. Types
    declare(strict_types=1);

    function addNums(float $a, float $b) {

    return $a + $b;

    }

    addNums(2, "1 week");

    // Fatal error: Uncaught TypeError:
    Argument 2 passed to addNums() must
    be of the type float, string given

    View Slide

  67. Types
    function addNums(float $a, float $b)

    addNums(2, "1 week”);

    // Fatal error: Uncaught TypeError:
    Argument 2 passed to addNums()
    must be of the type float, string given

    View Slide

  68. Types
    try {

    addNums(2, "1 week”);

    }

    catch(TypeError $e) {}

    View Slide

  69. Types
    try {

    addNums(2, 1);

    }

    catch(TypeError $e) {}

    //3

    View Slide

  70. Types
    class/interface

    array

    callable

    bool

    float

    int

    string

    object

    View Slide

  71. Return Type
    Declarations

    View Slide

  72. Types
    function addNums(float $a, float $b) : int {

    return $a + $b;

    }

    View Slide

  73. Types
    function addNums(float $a, float $b) : int {

    return $a + $b;

    }

    View Slide

  74. Types
    function addNums($a, $b) : int {

    return $a + $b;

    }

    addNums(1.5, 1);

    // Fatal error: Uncaught TypeError: Return value of
    addNums() must be of the type integer, float
    returned

    View Slide

  75. Types
    function addNums(float $a, ?float $b) : int {

    return $a + $b??0;

    }

    addNums(1, null);

    // int(1)

    View Slide

  76. Types
    function addNums(float $a, ?float $b) : ?int {

    return $a + $b??0;

    }

    addNums(1, null);

    // int(1)

    View Slide

  77. Types
    public function log($msg) : void {

    Logger::write($msg);

    }

    View Slide

  78. Variadic
    Functions

    View Slide

  79. Scalar Types
    function addNums(float $a, float $b) : int {

    return $a + $b;

    }

    View Slide

  80. Variadic Functions
    function addNums(...$numbers) : int {

    return array_sum($numbers);

    }

    addNums(1, 2, 3, 4);

    // int(10)

    View Slide

  81. Variadic Functions
    function addNums(float …$numbers) : int {

    return array_sum($numbers);

    }

    addNums(1, 2, 3, 4);

    // int(10)

    View Slide

  82. Security

    View Slide

  83. View Slide

  84. HTTPS

    View Slide

  85. HTTPS
    Encrypts traffic across the wire

    Trusted send and receiver

    Required by OAUTH 2

    View Slide

  86. HTTPS
    https://letsencrypt.org/

    View Slide

  87. Authentication

    View Slide

  88. Security
    //authentication - access control

    if (!$user->inGroup(‘admin’)) {

    return ‘ERROR YO’;

    }

    View Slide

  89. Security
    //authentication - brute force

    if ($user->loginAttempts > 5) {

    return ‘CAUGHT YA’;

    }

    View Slide

  90. Passwords

    View Slide

  91. Passwords
    //safe password hashing

    password_hash($_POST['pass'], ALGO);

    View Slide

  92. Passwords
    //safe password hashing

    password_hash($_POST['pass'], ALGO);
    //password verification

    password_verify($_POST['pass'], $u->pass);

    View Slide

  93. Passwords
    //safe password hashing

    password_hash($_POST['pass'], ALGO);
    //password verification

    password_verify($_POST['pass'], $u->pass);
    //password rehashing

    password_needs_rehash($u->pass, ALGO);

    View Slide

  94. Passwords
    if (password_verify($_POST['pass'], $u->pass)) {

    if (password_needs_rehash(

    $u->pass,

    PASSWORD_DEFAULT

    )) {

    $u->pass = password_hash(

    $_POST['pass'],

    PASSWORD_DEFAULT

    );

    $u->save();

    View Slide

  95. Safe Defaults

    View Slide

  96. Security
    //safe defaults

    class Your Controller {

    protected $var1 = ‘default value’;

    function __construct() { … }

    }

    View Slide

  97. Security
    //safe defaults

    $something = false;

    foreach ($array as $k => $v) {

    $something = $v->foo;

    if ($something == ‘bar’) { … }

    }

    View Slide

  98. Security
    function addNums(float $a, float $b) : int {

    return $a + $b;

    }

    $something = [];

    foreach ($array as $v) {

    $something[] = addNums($v[0], $v[1])

    }

    View Slide

  99. Common
    Hacks

    View Slide

  100. Security
    //Non-Persistent XSS

    http://www.yourSite.com/

    ?page_num=2&per_page=50

    Send the link to someone, boom


    View Slide

  101. Security
    //Persistent XSS

    Same idea, except with data that is
    saved to the server and

    re-displayed


    View Slide

  102. Security
    //escaping input

    $stmt->bindParam(‘:id’, $id);

    View Slide

  103. Security
    //escaping input

    $stmt->bindParam(‘:id’, $id);
    //escaping output

    htmlentities($_POST[‘name’]);

    View Slide

  104. Security
    //escaping input

    Class myModel extend Model {

    function save($id) {

    $stmt = $this->query->insert();

    $stmt->bindParam(‘:id’, $id);

    $stmt->execute();

    }

    }

    View Slide

  105. Security
    //escaping output

    Title

    Hello =htmlentities($name)?>

    View Slide

  106. Security
    //Cross Site Request Forgery

    //(CSRF)

    http://yourSite.com/

    users/12/delete

    View Slide

  107. Security
    //CSRF Protection

    POST / PUT / UPDATE / DELETE

    behind forms with one-time use
    tokens

    View Slide

  108. Security
    //CSRF Protection

    function generateCsrf() {

    $token = mcrypt_create_iv(

    16,
    MCRYPT_DEV_URANDOM);

    Session::flash('csrfToken', $token);

    return $token;

    }

    View Slide

  109. Security
    //CSRF Protection

    function generateCsrf() {

    $token = bin2hex(random_bytes(16));

    Session::flash('csrfToken', $token);

    return $token;

    }

    View Slide

  110. Security
    //CSRF Protection

    if (

    $_POST['token'] == Session::get(‘csrfToken')

    ) { … }

    View Slide

  111. Legit Tools

    View Slide

  112. View Slide

  113. Built-in
    Web Server

    View Slide

  114. Built-in Server
    $ php -S localhost:8000

    PHP 5.7.0 Development Server started…
    Listening on localhost:8000

    Document root is /home/ben/htdocs

    Press Ctrl-C to quit

    View Slide

  115. Composer

    View Slide

  116. Another
    Package Manager!?

    View Slide

  117. Composer
    Sane Package

    Management

    Autoloading via PSR4

    View Slide

  118. Composer
    / composer.json

    {

    "require": {

    "stripe/stripe-php": "dev-master",

    "twilio/sdk": "dev-master"

    }

    }

    View Slide

  119. Composer
    $ php composer.phar install
    -> composer.lock

    View Slide

  120. Composer
    $ php composer.phar install
    -> composer.lock
    Commit it ^

    View Slide

  121. Composer
    $ php composer.phar install
    /composer.lock

    View Slide

  122. Composer
    $ php composer.phar update
    /composer.json

    View Slide

  123. Composer
    $client =

    new Services_Twilio($sid, $tkn);
    $client->account

    ->messages

    ->sendMessage(…)

    View Slide

  124. Unit Testing

    View Slide

  125. View Slide

  126. Unit Testing
    PHPUnit

    Behat

    Mink
    Selenium

    CodeCeption

    PHPSpec

    View Slide

  127. Unit Testing
    class ApiAuthTest extends PHPUnit_Framework_TestCase {

    public function testVerify() {

    $auth = new apiAuth();



    $this->assertTrue($auth->verify());

    View Slide

  128. Unit Testing
    class ApiAuthTest extends PHPUnit_Framework_TestCase {

    public function testVerify() {

    $auth = new apiAuth();



    $this->assertTrue($auth->verify());

    View Slide

  129. Unit Testing
    $ phpunit tests

    PHPUnit 3.3.17 by Sebastian Bergmann.

    Time: 0.01 seconds

    OK (1 tests, 1 assertions)

    View Slide

  130. Standards

    View Slide

  131. View Slide

  132. Standards
    PHP-FIG
    Framework

    Interop

    Group

    View Slide

  133. Standards
    Member Projects
    Zend

    Symfony

    CakePHP
    Magento

    Joomla

    Drupal

    View Slide

  134. Standards
    PSRs
    PHP

    Standards

    Recommendation

    View Slide

  135. Standards
    PSRs
    Autoloading

    Interfaces

    Style Guides

    View Slide

  136. Standards
    PSRs
    PSR-4: Autoloading

    PSR-1: Basic Coding Standards

    PSR-2: Coding Style Guide

    PSR-7: HTTP Message Interface

    PSR-6: Caching Interface

    PSR-3: Logger Interface

    View Slide

  137. Resources

    View Slide

  138. View Slide

  139. Resources
    PHP.net

    View Slide

  140. Resources
    Modern Frameworks
    Laravel

    Symfony2
    SlimPHP

    Cake PHP

    View Slide

  141. Resources
    leanpub.com/

    phptherightway
    PHPtheRightWay.com

    View Slide

  142. Resources
    Give Me $$$
    SecuringPhpApps.com SecuringNodeApps.com

    View Slide

  143. Q/A TIME!
    https://joind.in/talk/83929
    Ben Edmunds
    @benedmunds

    View Slide