Month: April 2015

Social Security

Let me preface this by saying I think that sharing knowledge and experiences is a great thing. I love that there’s so many tutorials out there from people showing good practices in security and things they’ve learned along the way. Unfortunately, this is the same place where I see a major downfall. This kind of “social security” is a problem and it needs fixing so secure application development can really thrive.

Technology is great, especially PHP. Sure, there’ll be haters out there and they’ll throw stones at the glass house that is PHP hoping to break down the walls and push it off away from the public eye and into the “Not A Real Language” world. Fortunately, this will never happen especially with more recent improvements to the language and its consistent popularity among web developers. PHP is both easy to pick up but difficult to master, especially when it comes to the security of the applications written with it. Along with this low barrier for entry comes people sharing things either in tutorials or just articles that they’ve found to be useful or think is a good practice. The web is littered with articles like these, some being a bit more factual than others. *This is where the real problem is.*

Well-meaning developers post tutorials about things like preventing XSS with just htmlspecialchars or only fixing SQL injection with prepared statements and bound parameters. While these are good practices in themselves, they’re not the only thing that needs to be done to prevent these issues. Security is a complicated subject and there’s no one answer to any problem. Usually a robust solution involves multiple layers (defense in depth anyone?) to ensure the problem doesn’t pop up again or in another location. Even worse are the numerous older articles posted around the internet that have bad or old information. Sadly I see some of these that are *years* old being recommended as good resources to learn from.

I see two kinds of resources out there:

  • Those that are posts from individuals or groups and are wholly maintained by them
  • community resources such as the OWASP wiki

I’ve done some picking on OWASP in the past about the quality of their PHP materials and what seems to be their general feel around PHP and PHP-centric security. This time, though, I don’t want to talk as much about their content itself but about the process they follow for generating that content.

I appreciate what OWASP is going for application security, I really do, but I think the “everyone can edit” mentality of their content is very flawed. I know it’s just not feasible for a single organization largely made up of volunteers to manage and audit all of the content on their site. I get that, I really do, but when I see people referring to PHP resources that haven’t been updated since 2006 or 2007 it makes me cringe. And, because of the visibility of the group, those are the resources people find and recommend not knowing any different.

I think this is the crux of my opinion – having resources where anyone can contribute and not auditing those resources is a “Bad Thing” in my book. Unfortunately, in the case of the masses of tutorials posted out on the web, there’s not much that can be done about that. Those are there to stay and search engines will continue to ensure they show in results regardless of their quality or relevance to the current state of things.

I’m not saying I want people to stop contributing here, I just think there needs to be a balance. There’s a lot of regurgitation of the same kinds of advice out there (“let’s rehash the Top 10 again…”) but there’s also a lot of more innovative content that gets deeper into PHP security matters beyond just the prevention of the most common issues. In my experience, PHP developers are becoming more and more savvy about the security of their applications (even if it is a “negative deliverable” so to speak) and require tips and techniques beyond these simple ten point checklists.

Unfortunately, there’s just not a good answer here. As long as the web continues to be a free for all in terms of posting content developers will keep posting the same things or they’ll post bad suggestions (or ones that just don’t make any sense). The only thing I can think to do is to offer advice to those doing research or reading through PHP security content to ensure they’re getting the best information they can:

  1. Check the article date. If it’s older than 9-12 months, close the tab and move on. That’s not content you need to be reading.
  2. If the content talks about “preventing the most common vulnerabilities” in PHP applications, chances are it’s just another Top 10 article. If you know those already, skip it.
  3. Favor articles with links from things other than search engine results. If you come across an article from a recommendation on another non-linkbait site chances are the content is at least mildly useful.
  4. Consider the source. Do a little research on the author, if they don’t have much of a presence on the web around PHP-related things either take the advice with a large grain of salt or move on.
  5. Look for things that are well-written. Chances are if something is easy to understand or provides plenty of technical detail (and less hand waving “do this not that”) you’ve found something worth reading through.

These are just guidelines, obviously. Ultimately it’s up to your best judgement and research skills to determine the validity of the content and if it applies to your situation.

Advertisements

Invoke and Gatekeeper for Route Authentication & Authorization

As a part of a new project I’m working on (personal, not work) I came across a common need to enforce authentication and authorization handling in a bit more automated way based on the URL requested. I looked around for options and didn’t really find many that could be implemented somewhat simply but I did like the way Symfony defines their YAML to enforce auth* on the various endpoints. I set out to make something similar but a little simpler and ended up making Invoke.

It’s a super simplified version of the YAML-based routing and only has functionality for checking groups and permissions right now, but that’s not what I really wanted to talk about in this post. Invoke is fun and all, but I wanted to show how I’ve integrated it with another more robust tool I’ve written, Gatekeeper. The goal of Gatekeeper is to make a simple drop-in authentication system for applications to take care of a lot of the boilerplate user management needs. It comes with the usual CRUD handling for users, groups and permissions (RBAC) and also supports password resets, security questions and “remember me” functionality. Again, Gatekeeper is a cool library but it’s not the primary focus here. I wanted to integrate the two libraries so I could let each do what they do best – Invoke to check the current user against a set of criteria and Gatekeeper to provide the data for this validation.

Invoke lets you hook in your own users via a `UserInterface` that you can implement in your own application. In this case Gatekeeper has a concept of users too, but they don’t exactly mesh with what Invoke is expecting. So, let’s make an Invoke-compatible user object that it can use for it’s checks. This is the real key to the integration:

<?php
use \Psecio\Gatekeeper\Gatekeeper as Gatekeeper;

class InvokeUser implements \Psecio\Invoke\UserInterface
{
  private $details = array();

  public function __construct(array $details)
  {
    $this->details = $details;
  }

  public function getGroups()
  {
    $groupSet = array();
    $groups = Gatekeeper::findUserById($this->details['id'])->groups;
    foreach ($groups as $group) {
      $groupSet[] = new InvokeGroup($group);
    }
    return $groupSet;
  }

  public function getPermissions()
  {
    $permSet = array();
    $permissions = Gatekeeper::findUserById($this->details['id'])->permissions;
    foreach ($permissions as $permission) {
      $permSet[] = new InvokePermission($permission);
    }
    return $permSet;
  }
}
?>

Then, we’ll define the Invoke configuration in a YAML document:

event/add:
  protected: on
  groups: [test]
  permissions: [perm1]

In this case we’re telling Invoke that when it sees the requested URL of `/event/add` it should check a few things:

  • That the user is authenticated (protected: on)
  • That the user has a group with the “name” attribute of “test”
  • That the user has a permissions with the “name” attribute of “perm1”

If the user passes all of these checks, they’re good to go. Here’s how that would look in the execution of the Invoke code:

<?php

$en = new \Psecio\Invoke\Enforcer(__DIR__.'/config/routes.yml');

// If you're already using Gatekeeper for user management, you
// can just use this:
$userData = Gatekeeper::findUserById(1)->toArray();

// Otherwise you can push in your own user data
$userData = array(
  'username' => 'ccornutt',
  'id' => 1,
  'email' => 'ccornutt@phpdeveloper.org'
);

$allowed = $en->isAuthorized(
  new Confer\InvokeUser($userData),
  new \Psecio\Invoke\Resource()
);

if ($allowed === false) {
  // They're not allowed on this resource, forward to an error!
}

?>

The Invoke Resource by default looks at the current REQUEST_URI value so no options are needed when it’s created.

I’ve found this a pretty simple way to integrate these two libraries while still maintaining the correct separation of concerns enough to let each tool do their job. I’m always welcome to feedback on both projects or, of course, PRs if you find something that needs improving or a bug to fix.

Here’s more information about each of them: