• Stars
    star
    142
  • Rank 257,715 (Top 6 %)
  • Language
    PHP
  • Created about 12 years ago
  • Updated almost 12 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Shield - A Security Minded Microframework

Shield : A Security-Minded Microframework

Build Status

In my efforts to learn more about security best practices in PHP, I noticed that most of the PHP frameworks out there left it up to the developer to correctly handle input/output/etc themselves. Unfortunately, this has been a sticking point in PHP apps, so I decided to work on a microframework that was designed with security in mind.

This project is under a MIT license.

shieldframework.com

Disclaimer

Please note: This framework is a work in progress and is serving as a resource to learn more about PHP and web application security. Use of this framework will not provide the perfect security for your application, nor should it be considered an ultimate resource for security best practices.

Features:

  • Output filtering on all values (preventing XSS)
  • Logging on all actions
  • Input filtering functionality for accessing all superglobal information
  • Uses PHP's own filtering for data sanitization
  • Encrypted session handling (RIJNDAEL_256/MCRYPT_MODE_CBC, uses IV)
  • Custom cookie handling (including httpOnly)
  • Customized error handling to avoid exposing filesystem information
  • Basic templating/view system
  • IP-based access control
  • Session fixation prevention

Requires

  • PHP 5.3.x
  • mcrypt extension (for sessions)

The Code

I'm a big fan of the Slim microframework, so anyone that's used that will feel at home with Shield. Here's some example code of it in use:

<?php
include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/',function(){
    echo 'website root! woo!';
});

$app->run();

The above example is super simple - all it does is handle (thanks to the included .htaccess file) the request for the root level route "/" as a GET request. When it matches the route, it executes the closure callback and echos out "website root! woo!" Easy right?

Let's take a look at something a bit more complicated to introduce you to a few other handy tools at your disposal:

<?php
include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/',function() use ($app){

    $app->filter->add('test','email');

    echo 'from the URL: '.$app->input->get('test').'<br/>';

    $app->view->set('test','<a href="">foodles</a>');
    return $app->view->render('index1 [test]');
});

$app->run();

First off, there's one key difference between this example and the first one. In this example we pass in the $app object itself so we have access to some special features. Here's a quick overview:

  • $app->view: An instance of the View object that can be used to do some more complex view handling
  • $app->filter: A filtering object that lets you add and execute filters on the given data
  • $app->input: A feature to pull in values from the PHP superglobals ($_GET, $_POST, etc)
  • $app->log: A logging instance (what the framework uses too)
  • $app->config: Access to the configuration options, reading and writing

There's also one other thing that could help in more complex development - the DI container. The framework makes heavy use of a Dependency Injection Container (DIC) to work with its resources. This is exposed back to the user as well, so you can access $app->di and use it to manage your own object instances as well.

Regular Expression Routing

Besides the ability for Shield to match exact routes (like /foo), there's also a feature included allowing you use regular expresions in your routing. For example:

<?php
include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/foo([0-9]+)', function($matches) {
    print_r($matches);
});

Shield will try to match exact routes first, but then fall back on the regex routing checks. In th eabove example we're matching a route like /foo123. You'll notice that the first argument for the method is the routing matches as pulled from the preg_match PHP method. You can use whatever preg-based expression you want to use and have the values returned to you in the $matches value. So:

<?php
include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/foo([0-9]+)', function($matches){
    print_r($matches);
});

You would get Array ( [1] => 123 ) in the $matches variable.

You can also use named parameters in your routes too:

include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/params/[:t1]/[:t2]', function($matches){
    return $app->view->render('First Parameter: '.$matches['t1']);
});

If your route is /params/123/456 you'll get:

Array ( [t1] => 123, [t2] => 456 ) in the $matches variable.

NOTE: DO NOT directly use the values from this array - there is currently no filtering on these values so there is potential for exploitation.

Bound Configuration

You can also specify some configuration options linked directly to the route/closure combination. Here's an example:

<?php
include_once '../Shield/Shield.php';
$app = new Shield\Shield();

$app->get('/xml', function() use ($app){
    return $app->view->render('<test>this is xml</test>');
}, array(
    'view.content-type' => 'text/xml'
));

In the above example, we're overriding the view.content-type setting, but only for the / route, not everything. This gives us a bit more control over the application, making it easier to customize the request handling. Note this uses the dot notation to specify the value (the key). Most configuration options should be available for reconfiguration via this method.

Documentation

Shield

The Shield class is the main class you'll use and really only has a handful of methods:

  • run(): execute the application, no parameters
  • Each of the routing methods like get() and post(). Two parameters: route and closure/callback

Config

Access the values loaded from the configuration file or set/read your own.

  • set($keyName,$value): Set a configuration value
  • get($keyName): Get a configuration value
  • load($path): Load the values from the path into the app (overwrites), default looks for "config.php"
  • getConfig(): Get all of the config options as an array
  • setConfig($configArr): Set the array of options to the configuration (overwrites)

Di

Access to the dependency injection container (getting & setting)

  • register($obj,$alias): Register an object in the container, $alias is optional. Uses classname as name if not defined
  • get($name): Get the object with the given name from the container

Filter

Filter values based on filter types (supported are: email, striptags). Filters are applied when get() is called.

  • add($fieldName,$type): Add a filter of the $type when the $fieldName is fetched
  • filter($fieldName,$value): Looks for the filter(s) on the object and executes them in order (FIFO) on the $value

NOTE: If no filters are specified, it will execute a "strip_tags" on the data by default.

The $type parameter for the add() method can either be a string for the filter type or it can be a \Closure that will be given the value of the field as a parameter - for example:

<?php

$app->filter->add('myField', function($value) {
    return 'returned: '.$value;
});

You must be sure to return from this closure, otherwise the filtering will return null.

Input

Pull values from the PHP superglobals (filtered)

  • get($name): Pull from the $_GET, $name is name of variable
  • post($name): Pull from the $_POST, $name is name of the variable
  • request($name): Pull from the $_REQUEST, $name is name of the variable
  • files($name): Pull from the $_FILES, $name is the name of the variable
  • server($name): Pull from the $_SERVER, $name is the name of the variable
  • set($type,$name,$value): Push a $value into the property $name of $type ('session','get','post',etc)

NOTE: Superglobals are unset following a creation of an Input object.

Log

Logging to a file

  • log($msg,$level): Message to log to the file, $level is optional (default "info")

View

Handle output to the page

  • set($name,$value): Sets a variable into the view to be replaced in a template
  • render($content): Renders and returns the content, any variables set to the object are replaced using the notation "[name]"

NOTE: All values are escaped/filtered by default to prevent XSS. This can be overridden if desired.

Template

A basic templating engine included in the framework. By default it looks for a file named with the string given (in views/) or falls back to a str_replace method treating it as a string.

  • render($template): Either the name of the template file (no .php) or the string to use as a template

NOTE: If you choose to use the string as a template (no file), you must use the "[varName]" notation to get the values to substitute. Values can be set directly to the template instance (ex. $app->view->template->test = 'foo';)

Configuration

An optional config.php file can be placed in the same root as your front controller (probably index.php) so it can be found by the framework. This configuration file is a PHP array returned with your settings. These values can be accessed through the $di->get('Config')->get() method call. Here's an example config:

<?php
return array(
    'log_path' => '/tmp'
);

Additionally, you can use a "dotted notation" to find configuration options. So, for example, to find the value below:

<?php
return array(
    'foo' => array(
        'bar' => array(
            'baz' => 'testing this'
        )
    )
);

You can use $app->config->get('foo.bar.baz'); to get the value "testing this".

Available Config options

  • log_path: Set the default logging path
  • session.path: Set the path on the local filesystem to save the session files to
  • session.key: Customize the key used for the session encryption
  • session.lock: Enable/disable session locking (binds session to the IP+User Agent to help prevent fixation)
  • allowed_hosts: Array of hosts allowed to make requests (whitelisting)
  • force_https: Allows you to force the use of HTTPS. Will redirect if enabled and HTTP is detected

How To Contribute

First off, thanks for considering submitting changes for the project - help is always appreciated! If you're going to contribute to the project, here's a few simple steps to follow:

  • When contributing, please make a branch on your clone of the repo and commit your changes there ( this makes it much simpler when the time comes to merge)
  • Submit a pull request with good detail on what changed - reading through code is fun, but a summary is better
  • Contact information is below - feel free to email or send a message on github if you have questions!

Shield and the OWASP "Top Ten"

One of the "gold standards" in the web application security community is the infamous "Top Ten" list of common security issues that web apps have. Shield, being the nice framework that it is, tries to help protect you and your app from these problems. Here's how:

  • A1: Injection - All user input is filtered with at least one filter (including all PHP superglobals).
  • A2: Cross-Site Scripting - Before any information is accessed it is passed through at least one filter. Additionally, you can provide custom filtering via closures.
  • A3: Broken Authentication & Session Management - All session information is encrypted as it is stored using a Rijdael (256) method with an initialization vector.
  • A4: Insecure Direct Object References - Currently there's no permissioning system (and no auth system) in the framework.
  • A5: Cross-Site Request Forgery - Currently not prevented.
  • A6: Security Misconfiguration - The framework checks different PHP configuration settings to ensure that common security issues are mitigated.
  • A7: Insecure Cryptographic Storage - As previously mentioned, the only storage the framework does - sessions - stores the values encrypted.
  • A8: Failure to Restrict URL Access - Included in the framework is the ability to restrict based on IP. More fine-grained restriction is coming soon.
  • A9: Insufficient Transport Layer Protection - The framework currently does not prevent the use of HTTP over HTTPS.
  • A10: Unvalidated redirects & Forwards - The framework does not provide a mechanism for redirecting/forwarding.

Contact

Chris Cornutt [email protected]

@enygma

More Repositories

1

expose

An Intrusion Detection System library loosely based on PHP IDS
PHP
266
star
2

yubikey

PHP library to interface with the Yubikey REST API
PHP
76
star
3

gauth

Google Authenticator Code Validation and Generation
PHP
75
star
4

xacmlphp

An OASIS/XACML library for creating XACML-based PHP objects
PHP
36
star
5

usher

Task execution system (general)
PHP
24
star
6

composerclean

An additional command for Composer that removes configured files/directory
PHP
18
star
7

behat-fuel-rest

Behat & FuelPHP Examples for RESTful testing
PHP
18
star
8

modler

A generic model layer for PHP
PHP
15
star
9

frisk

An automated front-end unit testing testing tool written in PHP designed to mimic web requests and evaluate the response
PHP
14
star
10

duoauth

PHP Library for easy integration with Duo Security's Two-Factor REST API
PHP
13
star
11

Agile-ExtJS-ZF

DPC12 ExtJs+ZF Examples
JavaScript
13
star
12

impress-gen

Generator for Markdown to Impress.js Slideshow
PHP
12
star
13

offline-issues

A command-line script to pull the latest issues list from github and cache it locally
PHP
12
star
14

ci

Command-line tool for rapid development with CodeIgniter
10
star
15

h2-json-injection

H2 JSON Header Injection
HTML
10
star
16

pentesting-for-devs

Resources for topics mentioned in the "Pentesting for Developers" training
9
star
17

cmd

Simple tools for command line handling in PHP
PHP
7
star
18

php53-examples

Examples of several new features of PHP 5.3
PHP
6
star
19

jobtrack

JobTrack : A Sample Job Tracking App with FuelPHP + Backbone.js
PHP
5
star
20

backbone-testing

PHP
3
star
21

pv

pv: php objects
PHP
3
star
22

ci-models

CodeIgniter-based ORMish model things
PHP
3
star
23

twilio-auth

An example of sending an SMS through the Twilio API
PHP
3
star
24

phpdeveloper

Source for PHPDeveloper.org
PHP
3
star
25

tfauth

TFAuth is a unified two-factor authentication system (Duo Security, GAuth, Yubikey)
PHP
2
star
26

moviedb

The Movie Database connection PoC
PHP
2
star
27

slim-app-skeleton

A skeleton of a Slim application (with extras)
PHP
2
star
28

datamapper

Data Mapping tool
PHP
2
star
29

adventofcode2022

Solutions for the Advent of Code 2022
PHP
1
star
30

stormpath

Example API interface for the Stormpath user auth REST API
PHP
1
star
31

phpdeveloper-fuel

A Fuel-based version of PHPDeveloper.org
PHP
1
star
32

phpunit-article-3

Code for the SitePoint Unit Testing Article #3
PHP
1
star
33

phpdallas

DallasPHP Website
PHP
1
star
34

slsoap

A Python SOAP Client for the SoftLayer API
Python
1
star
35

travis-ci-ssl

A test repo for Travis-CI SSL testing
PHP
1
star
36

frisk-v2

An automated front-end unit testing testing tool written in PHP designed to mimic web requests and evaluate the response. Requires PHP 5.3+
PHP
1
star
37

clef

A client for the Clef 2FA service
PHP
1
star
38

usherapp

Usher website
PHP
1
star
39

fuzzing-101-template

The template repository for the Fuzzing 101 course on Learning Lab.
1
star
40

enygma

Profile repository
HTML
1
star
41

clonetest

just a test repo
PHP
1
star
42

adventofcode2016

1
star
43

conftrack

A conference tracking system
JavaScript
1
star
44

ar-js-site

A simple web application using AR.js to drop a Pokemon next to you
JavaScript
1
star
45

adventurelib

A PHP port of the Python "adventurelib" text-adventure library
PHP
1
star
46

enygma.github.io

Pages repo
HTML
1
star
47

fetch-team-avatars

Grab the avatars for a team from GitHub and output a Markdown table of their avatars
PHP
1
star
48

code-advent

Code Advent Solutions
PHP
1
star
49

phpdev

Source for the PHPDeveloper.org website
PHP
1
star
50

property-auth

A property-based auth* system using policies
PHP
1
star
51

github-projectv2

A Python package for working with GitHub's Projects API (including V2)
Python
1
star
52

adventofcode2020

Solutions to the 2020 Advent of Code challenges
PHP
1
star