views:

58

answers:

4

I've been working on an application that will allow for third-party extensions to be built to expand the application's functionality. All this in PHP, of course. I wanted to add a bit of security padding by running files in a certain directory through a checksum function. If the file doesn't pass the checksum, the file isn't "included", the administrator for that installation is notified, and the module is disabled until the administrator acts (re-enables and records the exception, or reinstalls the module).

The problem I'm having right now is being able to run that checksum whenever a user runs the include() function. I'd rather not have them run two functions back to back just to include a file, but if I have to I will. Not all third-party extensions will be very willing to run two functions (something like if(checksum_function($bleh)) include($bleh); ), and even if they were, it'd be so much easier (and more secure) to run the checksum whenever include() is executed, instead of doubling the line count for include() statements.

I've done some searching around and haven't found much. Ideas? Thanks in advance!

A: 

If your includes are classes named after a certain system (e.g. MyPlugin_Text) you could make use of PHP's autoloading. Autoloading can be used to automatically include a file when an object of a class is first created.

Extremely simplified example:

function __autoload($class_name) {

  require_once $class_name . '.php';
}

$myTextPlugin = new MyPlugin_Text(); 

Obviously, you will want to extend the autoloader, e.g. to do the preloading only for classes starting with MyPlugin_ and load those from a specific folder.

I know of no other way to achieve what you want to do, except writing a custom wrapper function.

I like your idea in general. However, calculating a checksum - e.g. using crc32() - is relatively expensive. There shouldn't be too many, and not too big, includes loaded this way. Also, it stands to reason that if an attacker is able to modify PHP files on your system, they are also able to execute them directly without needing your central application. The actual security gain of this exercise is likely to be small.

Pekka
A crc collision can be calculated using algebra.
Rook
Thank's a lot Pekka. I was going to use md5 for my checksums, but I imagine this would be even more expensive. I hadn't thought about using __autoload(). I might put aside this idea, since it may actually be quite costly once everything else is implemented. However, I'm definitely going to play with __autoload() a bit. Thanks!
Swivelgames
@The Rook you mean for a malicious script to fix the file so it passes the check? In most cases, I think, that is not going to be a danger because if an attacker is a) aware of the security mechanism and b) can write files on the web space in question, all is lost anyway. Still, good point.
Pekka
@Swivelgames you're welcome! Autoloading can make things very convenient. As I said, I like the idea of protecting a PHP app against manipulated files, but it's impossible to do this really safely in PHP: There are no "bulkheads", once an attacker gains access to only one include, they usually can read and write the whole application.
Pekka
@Swivelgames md5 is really bad for this, it opens the door for collision generation and in practice the attacker can perform a prefixing attack because he could easily control the beginning of the file without interfering with its ability to be executed.
Rook
A: 

Consider writing a wrapper for include:

function include_safe($library) {
    if(checksum_function($library))
        include($library);
}

You're not going to find many developers that are "happy" to use features like this, but you also can't override PHP language constructs (like include and require). Having a function that wraps everything is convenient and fast, so developers are likely to use it.

mattbasta
What checksum do you purpose? How do you go about verifying that this checksum relates to something that you want to include? How about this i'll just use this function `make_everything_secure_ever()` and then no one will hack me. Wouldn't you like to know what this function does? So would I.
Rook
@Rook The OP is looking for an appropriate syntax for the solution, not a security implementation. In fact, the OP even provided the name `checksum_function`, if you were to actually read the question. A more proper answer on my part would be to advise the OP to use decorators, though they are sadly not present in PHP. I can understand that you're bitter, but childishly voting down answers and leaving blatantly ignorant comments is what I would call "unprofessional".
mattbasta
Thank you, mattbasta.
Swivelgames
A: 

In many mobile code platforms it is common to see executable code signed with an RSA Digital Signature. This allows an authority to "ok" a piece of code that can then be distributed 3rd parties and customers know that the code is safe. Digital signatures are used to help prevent piracy of modern console video games. They are also used to verify that a software update came from the vendor, and not an attacker.

This php application could have the public key (or even distributed with this public key). The administrator has access to both the public and private key, using this he can sign a .php file. Upon include the signature could be checked. If the php file is modified or damaged the signature will not pass the check.

In practice, PHP applications perform many includes and thus any validation function would be a massive bottle neck. Anything that is secure, is also going to be very expensive. It would be better to check the signature once, and then transfer it to a white-listed directory or database. Another way to improve speed you could use a smaller RSA key for the signature. For instance a 512bit RSA key is good enough for SSLv3, so its probably good enough for this.

MD5 is very bad. If you store a white list of "safe" md5 file hashes, then this opens the door for collision generation. This is an ideal situation to use the md5 prefixing attack because specially crafted binary data a the beginning of the file will not prevent the include() for executing the code within the php tags <?php ?>.

CRC is even worse than md5. CRC is not intended to make hash collisions more difficult. CRC is only to detect damage from random noise. Using the similar attack to md5 by appending data a to a message a CRC collision can be generated.

sha1 is a secure and fast hash function that you can use. There is a similar hash collision attack that affects sha1. However unlike md5 no one has generated a sha1 collsion and NIST still considers its use to be safe. Although sha256 would be a more secure choice.

Rook
Thanks. I've been thinking about using sha256 for public and private keys. I already have public and private keys implemented. The public key is stored in the public repository and upon download and installation the key is checked. After installation a new, private key is generated for each instance, and that is checked for integrity as well.SHA1 was originally what I had in mind but defaulted to md5. I guess that was naïve of me, especially given the fact I've known about md5's recent lack of integrity. I'll use SHA256 for for the keys, and if I end up implementing a checksum I'll use SHA1.
Swivelgames
Thanks again for the answer. I like the idea of public and private keys, but I was somewhat hesitant because if I could run checksums on files before they were included in a cost-effective way, I would have preferred that more. I'll be sticking with SHA-hash algorithms. However, given the caliber of my application, RSA key signatures would be a bit much! :P
Swivelgames
A: 

I think checking a checksum on every load is a bad idea because it will slow down your application for sure.

A different approach would be that you put something in your applications admin interface to install or enable the plugin.

Then you could check the plugin one time when it is installed and add it to the list of enabled plugins before it can be used.

You could also check all plugins once a day to check if one was altered... but it's difficult to make that secure because whatever changed the plugin while it was installed could also change your security functions.

Bastian