Skip to content
Newer
Older
100644 303 lines (230 sloc) 12.5 KB
284d15a @enygma updating content in README
authored Jul 26, 2012
1 Shield : A Security-Minded Microframework
a245fce @enygma initial commit
authored Jul 25, 2012
2 ===============
a4ea17a adding to the README: update on dot notation in config, adding OWASP …
Chris Cornutt authored Aug 2, 2012
3 [![Build Status](https://secure.travis-ci.org/enygma/shieldframework.png?branch=master)](http://travis-ci.org/enygma/shieldframework)
a245fce @enygma initial commit
authored Jul 26, 2012
4
5 In my efforts to learn more about security best practices in PHP, I noticed that most of the PHP
6 frameworks out there left it up to the developer to correctly handle input/output/etc themselves.
7 Unfortunately, this has been a sticking point in PHP apps, so I decided to work on a microframework
8 that was designed with security in mind.
9
def34ad @enygma updating README with license info and more contact info
authored Jul 26, 2012
10 This project is under a MIT license.
11
08e10e3 @enygma updating README with URL for the framework site
authored Aug 2, 2012
12 [shieldframework.com](http://shieldframework.com)
13
278dbe5 updating the README with a disclaimer about the status of the framework
Chris Cornutt authored Jul 27, 2012
14 Disclaimer
15 ----------------
16 *Please note:* This framework is a work in progress and is serving as a resource to learn more
17 about PHP and web application security. Use of this framework will *not* provide the perfect
18 security for your application, nor should it be considered an ultimate resource for security
19 best practices.
20
a245fce @enygma initial commit
authored Jul 26, 2012
21 ### Features:
22 - Output filtering on all values (preventing XSS)
23 - Logging on all actions
24 - Input filtering functionality for accessing all superglobal information
25 - Uses PHP's own filtering for data sanitization
999ff13 @enygma updating README to reflect use of IV
authored Jul 31, 2012
26 - Encrypted session handling (RIJNDAEL_256/MCRYPT_MODE_CBC, uses IV)
d4a3922 @enygma updating README with info on the config.php file
authored Jul 26, 2012
27 - Custom cookie handling (including httpOnly)
59e7623 @enygma updating README with config options and info about error handling
authored Jul 26, 2012
28 - Customized error handling to avoid exposing filesystem information
be69f8f @enygma updating README with new encryption for Sessions and more features
authored Jul 28, 2012
29 - Basic templating/view system
5e31628 @enygma updating README with doc on new config features
authored Aug 1, 2012
30 - IP-based access control
d7751ae @enygma adding info about the fixation improvement
authored Aug 4, 2012
31 - Session fixation prevention
0a4fb11 @enygma updating README for new session encryption
authored Jul 26, 2012
32
33 Requires
34 ---------------
35 * PHP 5.3.x
36 * mcrypt extension (for sessions)
a245fce @enygma initial commit
authored Jul 26, 2012
37
38 The Code
39 ---------------
40 I'm a big fan of the Slim microframework, so anyone that's used that will feel at home with Shield.
41 Here's some example code of it in use:
42
43 ```php
b744446 @enygma updating README and removing old location
authored Jul 25, 2012
44 <?php
a245fce @enygma initial commit
authored Jul 26, 2012
45 include_once '../Shield/Shield.php';
46 $app = new Shield\Shield();
47
1dd2026 @enygma updating README to correct the "basic" example
authored Jul 26, 2012
48 $app->get('/',function(){
a245fce @enygma initial commit
authored Jul 26, 2012
49 echo 'website root! woo!';
50 });
51
52 $app->run();
ea45ebc @MDrollette remove closing ?> from PHP-only files according to PSR-2
MDrollette authored Jul 26, 2012
53
a245fce @enygma initial commit
authored Jul 26, 2012
54 ```
55
56 The above example is super simple - all it does is handle (thanks to the included .htaccess file)
57 the request for the root level route "/" as a GET request. When it matches the route, it executes
58 the closure callback and echos out "website root! woo!" Easy right?
59
60 Let's take a look at something a bit more complicated to introduce you to a few other handy tools
61 at your disposal:
62
63 ```php
b744446 @enygma updating README and removing old location
authored Jul 26, 2012
64 <?php
a245fce @enygma initial commit
authored Jul 26, 2012
65 include_once '../Shield/Shield.php';
66 $app = new Shield\Shield();
67
68 $app->get('/',function() use ($app){
69
70 $app->filter->add('test','email');
71
72 echo 'from the URL: '.$app->input->get('test').'<br/>';
73
72b34cd @enygma moved the $app->input->set in example to make it a bit clearer what w…
authored Jul 26, 2012
74 $app->view->set('test','<a href="">foodles</a>');
a245fce @enygma initial commit
authored Jul 26, 2012
75 return $app->view->render('index1 [test]');
76 });
77
78 $app->run();
ea45ebc @MDrollette remove closing ?> from PHP-only files according to PSR-2
MDrollette authored Jul 26, 2012
79
a245fce @enygma initial commit
authored Jul 26, 2012
80 ```
81
82 First off, there's one key difference between this example and the first one. In this example we
83 pass in the `$app` object itself so we have access to some special features. Here's a quick overview:
84
85 * `$app->view`: An instance of the View object that can be used to do some more complex view handling
86 * `$app->filter`: A filtering object that lets you add and execute filters on the given data
87 * `$app->input`: A feature to pull in values from the PHP superglobals ($_GET, $_POST, etc)
88 * `$app->log`: A logging instance (what the framework uses too)
89 * `$app->config`: Access to the configuration options, reading and writing
90
91 There's also one other thing that could help in more complex development - the DI container. The framework
92 makes heavy use of a Dependency Injection Container (DIC) to work with its resources. This is exposed
93 back to the user as well, so you can access `$app->di` and use it to manage your own object instances as well.
94
e05785a @enygma adding regex routing information to the README
authored Aug 5, 2012
95 Regular Expression Routing
96 -----------------
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 5, 2012
97 Besides the ability for Shield to match exact routes (like `/foo`), there's also a feature included allowing
e05785a @enygma adding regex routing information to the README
authored Aug 6, 2012
98 you use regular expresions in your routing. For example:
99
100 ```php
101 <?php
102 include_once '../Shield/Shield.php';
103 $app = new Shield\Shield();
104
105 $app->get('/foo([0-9]+)', function($matches) {
106 print_r($matches);
107 });
108
109 ```
110
111 Shield will try to match exact routes first, but then fall back on the regex routing checks. In th eabove example
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 6, 2012
112 we're matching a route like `/foo123`. You'll notice that the first argument for the method is the routing matches as
6dd5474 @bheesham Fixed a typo. Specified the PHP language when showing examples. Fixed…
bheesham authored Aug 13, 2012
113 pulled from the [preg_match](http://php.net/preg_match) PHP method. You can use whatever preg-based expression you
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 6, 2012
114 want to use and have the values returned to you in the `$matches` value. So:
115
6dd5474 @bheesham Fixed a typo. Specified the PHP language when showing examples. Fixed…
bheesham authored Aug 13, 2012
116 ```php
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 6, 2012
117 <?php
118 include_once '../Shield/Shield.php';
119 $app = new Shield\Shield();
120
6dd5474 @bheesham Fixed a typo. Specified the PHP language when showing examples. Fixed…
bheesham authored Aug 13, 2012
121 $app->get('/foo([0-9]+)', function($matches){
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 6, 2012
122 print_r($matches);
123 });
124 ```
125
bf5ae8c @enygma updating to allow for named params in routes (see README)
authored Nov 2, 2012
126 You would get `Array ( [1] => 123 )` in the `$matches` variable.
127
128 You can also use named parameters in your routes too:
129
130 ```php
131 include_once '../Shield/Shield.php';
132 $app = new Shield\Shield();
133
134 $app->get('/params/[:t1]/[:t2]', function($matches){
135 return $app->view->render('First Parameter: '.$matches['t1']);
136 });
137 ```
138
139 If your route is `/params/123/456` you'll get:
140
141 `Array ( [t1] => 123, [t2] => 456 )` in the `$matches` variable.
dd2b0e6 @enygma updating regex routing info a bit in README
authored Aug 6, 2012
142
143 *NOTE:* DO NOT directly use the values from this array - there is currently no filtering on these values
144 so there is potential for exploitation.
e05785a @enygma adding regex routing information to the README
authored Aug 6, 2012
145
ac4af4f @enygma updating the README with info on the per-route configuration updates
authored Aug 7, 2012
146 Bound Configuration
147 -----------------
148 You can also specify some configuration options linked directly to the route/closure combination. Here's an example:
149
25ef4dd @bheesham Forgot one block of code.
bheesham authored Aug 13, 2012
150 ```php
ac4af4f @enygma updating the README with info on the per-route configuration updates
authored Aug 8, 2012
151 <?php
152 include_once '../Shield/Shield.php';
153 $app = new Shield\Shield();
154
155 $app->get('/xml', function() use ($app){
156 return $app->view->render('<test>this is xml</test>');
157 }, array(
158 'view.content-type' => 'text/xml'
159 ));
160 ```
161
162 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.
163
a245fce @enygma initial commit
authored Jul 26, 2012
164 Documentation
165 -----------------
166 ### Shield
167 The `Shield` class is the main class you'll use and really only has a handful of methods:
168 * `run()`: execute the application, no parameters
169 * Each of the routing methods like `get()` and `post()`. Two parameters: route and closure/callback
170
171 ### Config
172 Access the values loaded from the configuration file or set/read your own.
173 * `set($keyName,$value)`: Set a configuration value
174 * `get($keyName)`: Get a configuration value
175 * `load($path)`: Load the values from the path into the app (overwrites), default looks for "config.php"
176 * `getConfig()`: Get all of the config options as an array
177 * `setConfig($configArr)`: Set the array of options to the configuration (overwrites)
178
179 ## Di
180 Access to the dependency injection container (getting & setting)
181 * `register($obj,$alias)`: Register an object in the container, `$alias` is optional. Uses classname as name
182 if not defined
183 * `get($name)`: Get the object with the given name from the container
184
185 ### Filter
186 Filter values based on filter types (supported are: email, striptags). Filters are applied when `get()` is called.
187 * `add($fieldName,$type)`: Add a filter of the `$type` when the `$fieldName` is fetched
188 * `filter($fieldName,$value)`: Looks for the filter(s) on the object and executes them in order (FIFO) on the `$value`
189
190 *NOTE:* If no filters are specified, it will execute a "strip_tags" on the data by default.
191
ad37d6c updating README with info on the closure-enabled filtering
Chris Cornutt authored Aug 1, 2012
192 The `$type` parameter for the `add()` method can either be a string for the filter type or it can be a \Closure that will
193 be given the value of the field as a parameter - for example:
194
195 ```php
196 <?php
197
198 $app->filter->add('myField', function($value) {
199 return 'returned: '.$value;
200 });
201 ```
202
203 You must be sure to return from this closure, otherwise the filtering will return null.
204
205
a245fce @enygma initial commit
authored Jul 26, 2012
206 ### Input
207 Pull values from the PHP superglobals (filtered)
208 * `get($name)`: Pull from the $_GET, `$name` is name of variable
209 * `post($name)`: Pull from the $_POST, `$name` is name of the variable
210 * `request($name)`: Pull from the $_REQUEST, `$name` is name of the variable
211 * `files($name)`: Pull from the $_FILES, `$name` is the name of the variable
212 * `server($name)`: Pull from the $_SERVER, `$name` is the name of the variable
0a4fb11 @enygma updating README for new session encryption
authored Jul 26, 2012
213 * `set($type,$name,$value)`: Push a `$value` into the property `$name` of `$type` ('session','get','post',etc)
a245fce @enygma initial commit
authored Jul 26, 2012
214
215 *NOTE:* Superglobals are *unset* following a creation of an Input object.
216
217 ### Log
218 Logging to a file
219 * `log($msg,$level)`: Message to log to the file, `$level` is optional (default "info")
220
221 ### View
222 Handle output to the page
223 * `set($name,$value)`: Sets a variable into the view to be replaced in a template
224 * `render($content)`: Renders and returns the content, any variables set to the object are replaced using the notation "[name]"
225
226 *NOTE:* All values are escaped/filtered by default to prevent XSS. This can be overridden if desired.
227
330194e @enygma updating README for new Template class
authored Jul 28, 2012
228 ### Template
229 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.
230 * `render($template)`: Either the name of the template file (no .php) or the string to use as a template
231
232 *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';`)
233
d4a3922 @enygma updating README with info on the config.php file
authored Jul 26, 2012
234 Configuration
235 --------------
236 An optional `config.php` file can be placed in the same root as your front controller (probably `index.php`) so
237 it can be found by the framework. This configuration file is a PHP array returned with your settings. These values
238 can be accessed through the `$di->get('Config')->get()` method call. Here's an example config:
239
240 ```php
241 <?php
242 return array(
243 'log_path' => '/tmp'
244 );
245 ```
246
a4ea17a adding to the README: update on dot notation in config, adding OWASP …
Chris Cornutt authored Aug 2, 2012
247 Additionally, you can use a "dotted notation" to find configuration options. So, for example, to find the value below:
248
249 ```php
250 <?php
251 return array(
252 'foo' => array(
253 'bar' => array(
254 'baz' => 'testing this'
255 )
256 )
257 );
258 ```
259
260 You can use `$app->config->get('foo.bar.baz');` to get the value "testing this".
261
59e7623 @enygma updating README with config options and info about error handling
authored Jul 26, 2012
262 ### Available Config options
263 * `log_path`: Set the default logging path
d7751ae @enygma adding info about the fixation improvement
authored Aug 5, 2012
264 * `session.path`: Set the path on the local filesystem to save the session files to
265 * `session.key`: Customize the key used for the session encryption
266 * `session.lock`: Enable/disable session locking (binds session to the IP+User Agent to help prevent fixation)
5e31628 @enygma updating README with doc on new config features
authored Aug 1, 2012
267 * `allowed_hosts`: Array of hosts allowed to make requests (whitelisting)
c40de3c @enygma adding "force_https" to the README for Config options
authored Aug 4, 2012
268 * `force_https`: Allows you to force the use of HTTPS. Will redirect if enabled and HTTP is detected
59e7623 @enygma updating README with config options and info about error handling
authored Jul 26, 2012
269
182e223 @enygma adding a "How To Contribute" section to the README
authored Jul 29, 2012
270 How To Contribute
271 --------------
272 First off, thanks for considering submitting changes for the project - help is always appreciated!
273 If you're going to contribute to the project, here's a few simple steps to follow:
274
275 * When contributing, please make a branch on your clone of the repo and commit your changes there (
276 this makes it *much* simpler when the time comes to merge)
277 * Submit a pull request with good detail on what changed - reading through code is fun, but a summary
278 is better
279 * Contact information is below - feel free to email or send a message on github if you have questions!
280
a4ea17a adding to the README: update on dot notation in config, adding OWASP …
Chris Cornutt authored Aug 2, 2012
281 Shield and the OWASP "Top Ten"
282 --------------
283 One of the "gold standards" in the web application security community is the infamous ["Top Ten"](http://owasptop10.googlecode.com/files/OWASP%20Top%2010%20-%202010.pdf) 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:
284
20463af updating OWASP section with missed content for Injection
Chris Cornutt authored Aug 2, 2012
285 * A1: Injection - All user input is filtered with at least one filter (including all PHP superglobals).
a4ea17a adding to the README: update on dot notation in config, adding OWASP …
Chris Cornutt authored Aug 2, 2012
286 * 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.
287 * A3: Broken Authentication & Session Management - All session information is encrypted as it is stored using a Rijdael (256) method with an initialization vector.
288 * A4: Insecure Direct Object References - Currently there's no permissioning system (and no auth system) in the framework.
289 * A5: Cross-Site Request Forgery - Currently not prevented.
290 * A6: Security Misconfiguration - The framework checks different PHP configuration settings to ensure that common security issues are mitigated.
291 * A7: Insecure Cryptographic Storage - As previously mentioned, the only storage the framework does - sessions - stores the values encrypted.
292 * 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.
293 * A9: Insufficient Transport Layer Protection - The framework currently does not prevent the use of HTTP over HTTPS.
294 * A10: Unvalidated redirects & Forwards - The framework does not provide a mechanism for redirecting/forwarding.
295
def34ad @enygma updating README with license info and more contact info
authored Jul 26, 2012
296 Contact
297 --------------
298 Chris Cornutt <ccornutt@phpdeveloper.org>
d4a3922 @enygma updating README with info on the config.php file
authored Jul 26, 2012
299
a4ea17a adding to the README: update on dot notation in config, adding OWASP …
Chris Cornutt authored Aug 2, 2012
300 [@enygma](http://twitter.com/enygma)
def34ad @enygma updating README with license info and more contact info
authored Jul 26, 2012
301
32e3cbe @enygma adding Travis-CI image
authored Jul 26, 2012
302
Something went wrong with that request. Please try again.