Intro to Shield (A Security-Minded Microframework)

Recently I’ve become more interested in something that, despite the wealth of resources out there, still seems to be lacking in a lot of web-based applications – good security. I’m not talking just about the “filter input, escape output” kinds of things. I’m digging a little deeper than that and looking and encryption, hashing, authentication methods and network/server configurations that could open your app wide open to malicious people.

So, in an effort to learn more about the security for PHP based applications, I’ve started up a new project that I hope can serve as a good tool (and maybe a guide) to those looking to create secure applications – the Shield microframework. It’s a small framework in the spirit of Slim framework that has a focus on security aspects and tries to help keep the user’s app a little safer by including things like:

  • 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

It’s an open source project and it’s already seen some great contributions from people all across the community. I wanted to provide a quick guide to getting started with this handy little framework so you could give it a shot in your own apps.

  • 1. First off, you’ll need to download the framework from github: https://github.com/enygma/shieldframework
  • 2. Once you’ve got it, check out the `app/index.php` file for an example of how to use it (pretty easy, right?)

At its most basic, all you need to do is make a route for the default page (this assumes you’re putting it in that same `app/` directory:

[php]
<?php
include_once ‘../Shield/Shield.php’;
$app = new Shield();

$app->get(‘/’,function() use ($app){
echo ‘It works!’;
});

$app->run();
?>
[/php]

That’s really all there is to it…this sets up a route for handling the main page of your app and echoes out the “It works!” message when you hit the page. You might see some other warnings and errors pop up about various settings and directories too. These are there to help you make things more secure, so be sure to make an effort to correct them.

There’s a lot more interesting things you can do with the frame work (it’s all in the README in the checkout) to work with filtering of user input, setting up custom filters, using the View object to add values to and display a rendered view and more.

I hope to make this project even better over time while trying to keep it small and flexible. I’m always looking for new ideas to help make it more secure and user friendly, so if you have any suggestions, please either leave them in the comments or email them over!.

8 comments

  1. Just curious: you mention “Output filtering on all values.” Does this take into context the _context_ in which the value is used? For instance, escaping for a URI is different than escaping for an HTML attribute, as is escaping JSON and CSS — and each is different than HTML. We found in ZF2 that it makes no sense to filter by default, as the developer needs to indicate the context to ensure proper escaping occurs. How are you approaching this?

    Like

    1. The default filtering is a call to strip_tags to remove possible XSS issues, but other than that it’s all up to the dev to apply filters – either included ones or custom ones via closures. It doesn’t try to guess on the context….that’s way too difficult (as you’ve seen heh)

      Like

  2. @Matthew you have the option to get something from the filter, unfiltered by passing true as the second param when getting, even setting has the same functionality.

    Like

  3. Oh, great! Yet another bad framework!

    I first had a look at the View class: Boom, first security issue. The filter class? Yet another security issue.

    Then, I had a look at the Di class: Oops, it is just a registry and it has nothing to do with a proper DI solution (not even talking about the createInstance() method here).

    “I noticed that most of the PHP frameworks out there left it up to the developer to correctly handle input/output/etc themselves”

    This is a joke, right? Have you even had a look at what current frameworks do to ensure proper security? Probably not. Have another look at Zend Framework for instance. Actually, any popular framework out there does a better job than what you are doing here.

    “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.”

    Please, do yourself a favor and stop that, now. PHP does not need yet another bad solution. Analyse and learn from existing frameworks, that would be a better investment of your time.

    Like

    1. Thanks for the comments – I’d appreciate to know what these issues are you’ve mentioned so I can learn how to handle them better. As is mentioned in the README, this is a learning process for me too. I want to not only expand in my security-related knowledge but also provide it as a resource for others to reference. Without knowing what’s wrong (and just getting “it’s broken”) I can’t improve as a developer.

      Like

  4. @random-php-dev Your comments would be more useful if you included constructive criticism. Rather than just saying “bam that’s wrong!” maybe you could say “I see you did *this* when maybe you should have done *this* because of *this reason*”

    Like

  5. A few notes about session encryption (and security/cryptgraphy in general).

    First of all, you should use AES (MCRYPT_RIJNDAEL_128). AES accepts keys that are either 128 or 192 or 256 bits in length. You must make sure the final key you are going to input to MCrypt is in correct size (it must not be hex-encoded etc.).

    You are using the cipher in CBC mode, which is a good and safe choice. However, you should not use weak randomness when you generate initialization vectors. Instead of MCRYPT_RAND, use MCRYPT_DEV_URANDOM.

    There is no ciphertext authentication at all. If the system is under an active attack, CBC mode encryption can lead to different kind of problems. Since there is no mode in MCrypt that takes care of authentication, you must authenticate the ciphertext and all the related data by yourself. Use HMAC to do this (with a separate key). Say, HMACH-SHA-256 (and make sure you don’t leak information when verifying the MAC). Use “Encrypt-then-MAC” composition.

    It is also good to acknowledge that in CBC mode, there could be information leakage if you encrypt using the same key “forever”. It is recommended that you do not encrypt more than 2^32 blocks or so with a given key (no matter if it is one huge message or many smaller messages).

    Since there is no key rotation in Shield, you could hash the encryption key with IV before inputting it to MCrypt (this way you are effectively using a fresh encryption key for each encryption dispatch).

    It looks like Shield is going to use a hard coded encryption key if it fails to get a key from config. This is an absolute no. If there is no key set, exit immediately. You could demand users to make the keys have at least, say, 40 bytes of data. And then derive the actual encryption key from this “base key”. Remember the actual encryption/authentication keys must not be hex-encoded. Instead derive them how ever appropriate and use as “raw output”.

    Also, as you are dealing with sessions, I would add timestamps to indicate when the data was saved and how long it can be used. If the timestamps are not correct, discard the data.

    Here is some code to demonstrate how to apply these “cryptographic quirks” to your code:
    https://github.com/timoh6/TCrypto

    Like

  6. Hi!

    Why just not contributing to Slim framework as quoted?
    Instead of building another one from scratch?

    You could enhance security of an existing framework there are so many on the market.
    And as mentionned in some blogs php developers are lost when choosing a micro framework as they are all the same or just with a slight different way.

    Like

Leave a comment