Category Archives: php

What should be part of a PHP Streetfighter API

4
Filed under defense, php

For my own PHP work, I am using a relatively nimble but effective set of libraries. They have shown to be effective, but are in need of a “redo. “  I released pieces of it in the past, but none of it is actually terribly useful to the public as it is written for me/by me.

Last week, I received some code that someone wrote for us, which is in bad need of a simple API like that to make it workable (= “secure”).  So I am thinking about about wrapping up a “PHP Streetfighter API”. Here are some initial thoughts:

  • Can’t take more then 24 hrs to write
  • A coder should be able to understand / use it in less then 1 hr
  • should force the coder to use prepared statements, proper input validation and avoid XSS
  • maybe some protection against XSRF
  • maybe some anti-pentesting / honeytoken features

Can this be done? Should I add more to it? Anybody interested in using something like this? This isn’t supposed to replace more complete efforts like the OWASP ESAPI, but instead rather provide something for the myriads of “non enterprise coders” who produce tons of crappy code daily. It also shouldn’t be too hard to “retrofit” an existing application with this API.

What do you think… makes sense? Am I nuts? Want to use it?

Various PHP and MySQL Pitfalls

2
Filed under php

This is a short post, to summarize some of the issues I see with PHP code and the use of MySQL.  Not too many people know about these pitfalls and they are given rise to some of the more subtle security issues:

1 – “SQL Overflow”

If a value you insert into a column is too large, it is truncated silently. This can lead to security issues if you don’t validate that the submitted string is of the right length.

2 – “Trailing White Space Ambiguity”

Trailing white spaces are removed by MySQL silently. For example, these two queries retrieve the same result:

select role from user where username='Admin';
select role from user where username='Admin   ';   (note the space at the end).

3 – Unbalanced Comments

Older versions of MySQL allow /* to be used unbalanced. For example,

select now() /* test

will work. Newer versions of MySQL require balanced comments (unbalanced was always “illegal” according to the documentation

4 – php ‘rand()’ function returns bad results

If the argument exceeds the maximum integer, you will get not-so random numbers back. This one depends a bit on the version of PHP you are using. But you will not get an error. Instead, you will get negative numbers, or numbers that are not random (e.g. only last couple of digits change).

5 – MySQL “–” comments require a white space

In order to use “–” as a comment, it has to be followed by a whitespace.

select now() –test  will fail
select now() — test will work

You don’t have to use a space. A tab will work just fine and evades some filters.

Got some to add? Use the comments ;-)

Session Attacks and PHP – Part 2

1
Filed under Sessions, php

Yes, I will talk in this article about why it is not good to leave your session files in /tmp.  But first, allow me to follow Jason’s lead and talk about the session attacks he discussed in Part 2 of his ASP.NET article.  I will keep it short :)

Session fixation isn’t really that much of a problem as long as you stick with a few simple principles.  Remember we called this blog “App Sec Streetfighter“? It’s about simple and reproducible techniques that work while under attack.  So lets keep it simple:

  1. Use only cookies to transport the session token.  This considerably raises the bar on session fixation.  The attacker now has to set a cookie which isn’t easy at all.
  2. Change the session ID whenever the users state changes (logged in vs. logged out).
  3. Change the session ID every so often. (every X pageviews, every X minutes).

In order to change the session id, PHP offers a simple comand, session_regenerate_id, just add it to your header and you will get a new session ID on every page.  If that works for you: great!.   If it causes performance issues, then add some logic to limit the life time of sessions or add the session_regenerate_id whenever the user logs in and out.

One important caveat for session_regenerate_id:  It uses one parameter.  Set it to “true.”  The default is “false,” which will leave the old session intact.

Now to the part everybody appears to be waiting for: Why not /tmp ?

/tmp is a convenient location for session data.  Every Unix system I have seen has a /tmp directory that is globally readable and writable.  But this is just the problem for session data.  The file name itself gives away the session ID.  A listing of all session files will give an attacker a list of all valid sessions. In most dedicated web server scenarios, the risk of leaking /tmp file names is low.  But the defense is simple enough to “just do it” ™:

  • Create a directory which will only hold session data (let’s call it /tmp/phpsessions).
  • This directory should NOT be owned by the apache user, but by root and the apache user’s group.
  • Set permissions to 770.  Sadly, 760 is not possible.  Theoretically, it should work.  PHP (the web server) doesn’t really need to be able to get a list of valid sessions.  But sessions will fail if you set the permissions to 760.

I typically prefer to keep my sessions in a database, less for security reasons but more for scalability.  Memcached sessions is an other great way to get sessions to scale.

Related Articles:

Session Attacks and PHP – Part 1

Session Attacks and ASP.NET – Part 1

Session Attacks and ASP.NET – Part 2

Session Attacks and PHP

7
Filed under Sessions, php

This blog is of course inspired by Jason’s ASP .Net blog. I figured as the PHP guy in the group, I may as well cover what he did for .Net from the PHP side.

PHP’s default session mechanism is rather simple and effective. The php.ini file configures how sessions work. Many of the parameters can be overridden within your PHP code, or .htaccess files can be used to create more fine grained configurations for particular directories. The session module is part of PHP by default, but can be disabled at compile time. By default, the session data is saved in files. The directory the session data is stored in is again configured in php.ini and defaults to /tmp (not the best choice, but more about that in a later blog).

Much of the session module can be adjusted, or custom code can be used to store session data in a database.

Like Jason noted for .Net, sessions and authentication are two different things in PHP as well. It is up to the developer to use sessions to store the user’s identifier.

Let’s follow Jason’s outline, and talk about session fixation first!

Session Fixation

PHP provides a number of defenses to prevent session fixation. First of all, the lifetime of a session can be limited in php.ini, or by simply using runtime configuration directives. The one “gotcha” here is that some developers mistake the cookie lifetime for the session lifetime. The session lifetime is the part that counts. It is adjusted via gc_maxlifetime parameters. The “gc” (Garbage Collection) parameters are a bit hard to grasp for someone new to PHP. First of all, it is important to understand that nothing happens in PHP unless a page is rendered. Session data will survive indefinetly if the server is idle. Whenever a page is displayed and a session is initiated, the garbage collection functions run and clean up old session data. There are a total of three parameters that determine how this is done:

gc_probability and gc_divisor: How likely is it that the garbage collection is performed. The probability is calculated as gc_probability/gc_divisor. The default is 1/100, which may be a bit a lot probablility if you only have 100 page views per hour. But if you have 100 page views per second, this is perfectly fine.

gc_maxlifetime: This parameter defaults to 1440 seconds (15 minutes). After 15 minutes of inactivity, the session is considered for garbage collection.

So in short: Using default parameters, the session is deleted within 100 page views after the 15 minute time out expired, assuming that each page view initiates a session.

What does this mean for session fixation and reusing session data: The time window is about 15 minutes by default, which is appropriate for most applications.

PHP does allow for a “referrer check”. Sessions will only be considered if the referrer contains the string defined using the “referer_check” configuration parameter. By default, this parameter is empty. This is a very powerful way to block many session fixation attacks.

It is also rather simple to change the session ID in PHP. session_regenerate_id will create the new session and move the data. Take care to set the optional parameter to “true”. Otherwise, the old session will not be deleted. For the paranoid, it is as easy as adding “session_regenerate_id(true)” to your header file. (and wait for entropy starvation to set in ;-) ).

Now what about the attacker obtaining a valid session id? PHP allows for sessions to be delivered via the URL, or cookies. URL based sessions are disabled by default via the “use_only_cookies” parameter. The cookie itself is configured via php.ini.

Cookies can simply be configured as http_only and secure via php.ini. No need for extra code on this one.

Another item not discussed (yet?) by Jason is the session ID generation. PHP’s session ID generation is reasonably secure by default. It is possible to define the source of the entropy used to create sessions (/dev/random or /dev/urandom), how many bytes of entropy are used and which hash function is used. Plenty of ways to mix it up!

There is a lot more to talk about when it comes to PHP sessions. Let’s see what Jason is up to next! Also note that the facts above are valid for later versions of PHP (5 and later). Maybe I should also write about suhosin one of these days, an excelent PHP hardening module.