Jump to content
Larry Ullman's Book Forums

Recommended Posts

One area of security I've never really been up to snuff on is session security. What I'd really like to do is compile a checklist of all the things that should be done to guarantee secure sessions (i.e., sessions that are not subject to session hijacking).

 

If (some of) this information is already covered in one or more of Larry's books, simple references to those books and sections would be helpful.

 

As a starting point, I found the following checklist on Stack Overflow, but there are a few points I'm not sure on:

http://stackoverflow.com/a/7488/1992973

 

Specifically, here are my questions regarding the points listed in the SO thread above:

 

Use SSL when authenticating users or performing sensitive operations.

One of the comments to the SO answer points out that you have to use HTTPS for every page on the site, or a hacker can easily steal the session ID the first time a non-HTTPS request is made. Does anyone have any thoughts on this?

 

Regenerate the session id whenever the security level changes (such as logging in). You can even regenerate the session id every request if you wish.

What's the best way to regenerate the session ID? Actual code would be helpful for this. Thanks.

 

Have sessions time out

How do you make a session time out?

 

Don't use register globals

What is the problem with using registered globals? I don't get the problem with this at all.

 

Store authentication details on the server. That is, don't send details such as username in the cookie.

This point is pretty straightforward and obvious.

 

Check the $_SERVER['HTTP_USER_AGENT']. This adds a small barrier to session hijacking. You can also check the IP address. But this causes problems for users that have changing IP address due to load balancing on multiple internet connections etc (which is the case in our environment here).

A lot of the comments to this answer seem to be related to checking the user agent string. Maybe it's best to just avoid this check. Any thoughts?

 

Lock down access to the sessions on the file system or use custom session handling

I don't understand this point at all. How do you lock down the session on the file system. Also, how would you go about creating a custom session? Would it just be an array of data stored in the DB?

 

For sensitive operations consider requiring logged in users to provide their authenication details again

This is a good point, but I think it's important to consider the balance necessary for protecting the user without annoying them too much.

 

Any thoughts or opinions anyone can offer would be greatly appreciated.

Thank you.

Link to comment
Share on other sites

One area of security I've never really been up to snuff on is session security. What I'd really like to do is compile a checklist of all the things that should be done to guarantee secure sessions (i.e., sessions that are not subject to session hijacking).

Excellent idea!

 

If (some of) this information is already covered in one or more of Larry's books, simple references to those books and sections would be helpful.

I know some of this is, but unfortunately I don't know the references offhand.

 

Use SSL when authenticating users or performing sensitive operations.

One of the comments to the SO answer points out that you have to use HTTPS for every page on the site, or a hacker can easily steal the session ID the first time a non-HTTPS request is made. Does anyone have any thoughts on this?

Using SSL exclusively will most certainly be more secure as it rules out the possibility of anyone else ever seeing the session ID. Back in the day, you didn't want to overuse SSL because it was slower, but that's less true now. In fact, more and more sites are using exclusively SSL, even when no authentication is involved.

 

Regenerate the session id whenever the security level changes (such as logging in). You can even regenerate the session id every request if you wish.

What's the best way to regenerate the session ID? Actual code would be helpful for this.

You'd just use session_regenerate_id(). For extra security, you can call this whenever someone logs in, or you can just call it when administrators log in and when people change their passwords and the like.

 

Have sessions time out

How do you make a session time out?

Sessions in PHP are already set to time out automatically in 24 minutes by default. But this relies upon garbage collection. To be more careful, you can tweak the session configuration settings to tighten this up (e.g., increase the odds of garbage collection taking place for less busy sites).

  • Upvote 2
Link to comment
Share on other sites

Don't use register globals

What is the problem with using registered globals? I don't get the problem with this at all.

This is a historical consideration that's not germane anymore. Register globals no longer exists in PHP. I always argued that register globals was not in itself insecure, but it allowed people to write insecure code that worked. So you can have register globals on (when it existed) but not have a security hole.

 

Store authentication details on the server. That is, don't send details such as username in the cookie.

This point is pretty straightforward and obvious.

Yes. I'd also add: never store a database primary key value in a cookie.

 

Check the $_SERVER['HTTP_USER_AGENT']. This adds a small barrier to session hijacking. You can also check the IP address. But this causes problems for users that have changing IP address due to load balancing on multiple internet connections etc (which is the case in our environment here).

A lot of the comments to this answer seem to be related to checking the user agent string. Maybe it's best to just avoid this check. Any thoughts?

The user agent and IP address are two simple restrictions you can add that might make a slight be of difference but also can be easily spoofed and will fail in some situations. So, in my opinion, a judgement call.

 

Lock down access to the sessions on the file system or use custom session handling

I don't understand this point at all. How do you lock down the session on the file system. Also, how would you go about creating a custom session? Would it just be an array of data stored in the DB?

By default, session data is stored in plain in a publicly writable directory on the server, making them easy to access for anyone on that server. At the very least, you'd move the sessions directory to another place. Even if you don't change the permissions, you'd have a bit of "security by obscurity" here. Second, if you can, restrict permissions on that directory to your web server user ID. This requires that every site on the server is running as a server instance with its own user ID. This is not the norm, but is possible.

 

Or you could store the session data in the database, so the database permissions would apply. I explain that in the PHP Advanced book.

 

For sensitive operations consider requiring logged in users to provide their authentication details again

This is a good point, but I think it's important to consider the balance necessary for protecting the user without annoying them too much.

Agreed.

 

Any thoughts or opinions anyone can offer would be greatly appreciated.

Getting away from sessions specifically, there's also a good argument for the password-less login (i.e., one-time password login). Or, going the other way, using two-factor authorization.

 

Also, my understanding is that many security breaches aren't through the password and login system but through the password recovery system. Don't use stupid security questions and make sure that the forgotten password system is as secure as possible.

  • Upvote 2
Link to comment
Share on other sites

Good question, I had a similar question on here but in terms of it being through Yii. 

 

A follow up question on a slight tangent, Larry, when you say:

 

 


Yes. I'd also add: never store a database primary key value in a cookie.

 

I would therefore take it that you wouldn't advocate using a url parameter in Yii such as

 

user/profile/1 - with 1 being the user's primary key? 

 

Or do you say that because the cookie can be altered?

Link to comment
Share on other sites

Larry,

 

Thanks for responding to this thread!  I have been looking into session security for a couple weeks and have talked to HartleySan about it.  I feel that we absolutely should be working to secure sessions as much as possible as these types of attacks are increasing.

 

 

The user agent and IP address are two simple restrictions you can add that might make a slight be of difference but also can be easily spoofed and will fail in some situations. So, in my opinion, a judgement call.

 

I read the same thing!  Also, because service providers like AOL use shared IP pools, and an IP address can change mid connection, checking for IP addresses is problematic, unless you write a work around for those using AOL, or anyone else using a similar service.  As for checking the user agent, I've heard that this is completely useless, and serves nothing more than a way to give the developer a false sense of security!

 

I think that a session class is an excellent candidate for using objects as it will encapsulate all the session handling in a convenient place.  We could all write one here in the forum.  Anyone who wants to contribute would be welcome and we all could use it!

 

Any thoughts?

 

Matt

Link to comment
Share on other sites

Larry, thanks again for all the good information.

As Matt suggested, I am currently working on a session function/class that would be able to handle all the various concerns of session security.

 

If you don't mind though, could use please elaborate a little bit more on the following things you mentioned at the bottom of your second post?

Getting away from sessions specifically, there's also a good argument for the password-less login (i.e., one-time password login). Or, going the other way, using two-factor authorization.
 
Also, my understanding is that many security breaches aren't through the password and login system but through the password recovery system. Don't use stupid security questions and make sure that the forgotten password system is as secure as possible.

 

Specifically, how do you manage a one-time password login system, and what are some good examples of two-factor authorization? Also, what's the best way to implement password recovery? Is the password recovery method you mention in your PHP & MySQL book still relevant?

 

Thanks.

Link to comment
Share on other sites

Jonathon, the visibility of primary keys depends upon the security involved. If it's okay that a user might switch X to Y in order to view a different page, then it's fine. For example, if you'd have links to pages of categories, changing X to Y just circumvents the links. If you have a security method in place, then showing the primary key may not be problematic. Although that's not great. The main point is that you have to be careful storing a primary key in a cookie if something relies solely upon that primary key (e.g., access to content). 

 

HartleySan, the one-time/password-less login sends people a link via email that they must click to access a site. They do this every time. This way you don't store passwords on your site, which is a good thing, and you don't need password recovery. But from a security perspective, it relies upon email being secure, which isn't a flawless argument. Check out this: http://notes.xoxco.com/post/27999787765/is-it-time-for-password-less-login

 

As for password recovery, I think the most secure approach is to send a one-time, temporary access link to the email address. When the user clicks that, you use other prompts to verify the user, then let them change the password. 

 

As for two-factor auth (2fa), Gmail, Stripe, GitHub, and many others have turned to using the Google Authenticator app. So to long into my business's Stripe account (i.e., the one associated with the Yii book), I need to correctly enter my email address, password, and a random six-digit number generated by an app on my phone. Or some services send a code via a text message. 2fa virtually eliminates the possibility of a remote hack because access is needed to your email address and password and a device that's normally on you. 

Link to comment
Share on other sites

Ok thanks Larry.

 

I believe I have suitable protection, through role RBAC even though the primary key is visible. Perhhaps I may rethink how the url is displayed or use .htaccess to stop it being visible. I just look at other websites like stackoverflow and I note in people user pages there appears to be {id number}-{nickname}

 

Thanks Larry

Link to comment
Share on other sites

I think that a session class is an excellent candidate for using objects as it will encapsulate all the session handling in a convenient place.  We could all write one here in the forum.  Anyone who wants to contribute would be welcome and we all could use it!

 

Any thoughts?

 

I would recommend you to use something that already exists. Laravel is component based, and you can find components under the Illuminate namespace. Illuminate\Session will abstract and secure Session handling for you. You can find it on packagist.com and install it using composer. :)

  • Upvote 1
Link to comment
Share on other sites

@Antonio - Thanks for sharing that session component.  I agree that using something that already exists, and not completely reinventing the wheel, is the best way to go.  I will look at it!

 

I have looked into how some other frameworks handle session management and wasn't too impressed.  For example, with the Zend session component, you have to use 3 or 4 classes to do what could easily be done with one.

 

@Jon - Thanks for taking on this endeavor.  One thing I wanted to say was that in my research I found that there are a few small things to watch out for when developing your own session class, and I do think it is a good idea to use others as a model when creating one.  For example, whenever you regenerate a session ID, it can cause race conditions in sites that use a lot of AJAX.

 

There is an excellent tutorial from the Treehouse blog here:

http://blog.teamtreehouse.com/how-to-create-bulletproof-sessions

 

After stripping out the code which tries to lock the session to the same IP and User Agent, it is a great base class to build on.  It also has an nice function for regenerating session IDs which takes care of the problem I mentioned above.

 

One guy said that you should use a static class for the session manager because only one should ever be created per user per visit.  Does this have any benefit over using a regular class to handle sessions?

 

Also, I have read that if you have a small site which frequently accesses the database (as ours does), then storing session data in it can cause performance problems, as now the database will need to be accessed every time a session is created, written to, or read from.  It is probably fine in most cases, but just something to think about.

  • Upvote 1
Link to comment
Share on other sites

Matt and Antonio, thanks a lot for both of your posts.

 

Antonio, I went though all of that code fairly thoroughly, but in the end, it seemed like a lot of code to do some fairly simple tasks (that I think could be done with a lot less code).

I did, however, like their expression for generating a random ID:

sha1(uniqid(true).str_random(25).microtime(true))

 

Matt, thanks a lot for that Treehouse link. That bit about the Ajax requests was interesting, and it's something that I had never considered before. Also, I agree that the code concerning the user agent and IP address was unnecessary, and even more than that, likely to cause issues for various users.

As for using a static class, I'm guessing they do that because you're not going to need to use the new keyword to create several instances of a session manager; just one will do.

 

Just to sum up what I have been doing the past few days, I did quite a bit of research into session security as well as went through all of Larry's bits about sessions in all of his books that I have.

While I'm not ready to write the final function(s) yet, I have reached a couple of conclusions (and, anyone, please correct me if I say something wrong/stupid):

 

1) Simply calling a function or functions that combines a bunch of session-related operations is not enough to properly secure sessions. You must also be vigilant in all matters of security, especially in preventing XSS attacks. Also, using SSL all the time is a very smart thing to do.

 

2) Because a lot of web hosting providers will not give you access to the PHP config (.ini) file(s), there needs to be a way to do everything you need to do from a PHP script. Luckily, there is. PHP provides the interface to edit all the PHP config settings as necessary on a script-by-script basis.

 

3) You can store sessions in a DB, but after doing a lot of research, this is simply one of many possible solutions, and it seems like a poorer solution since it is slower and requires more programming than other (equally safe) solutions.

 

4) You should definitely change the directory where session data is saved. You can easily do this with the session_save_path function in PHP. I highly recommend changing it to a randomly-name directory that is only accessible from your namespace on a shared server, but is still outside the web root.

 

5) You can use the session_name function to rename the cookie that holds the PHP session ID. By default, the cookie name is PHPSESSID. You can easily change this to some random name that no one will ever guess (and even if they see it, they will likely not know what it's for). You can also opt to change the name up whenever you want.

 

6) Similar to #5, you can change the actual session ID (i.e., the value of the PHPSESSID cookie) by using the session_id function. You can either use the session_id function to custom generate a PHP session ID, or you can use the session_regenerate_id function to have PHP do it all for you. I personally prefer the former, as it makes things that bit more unpredictable.

 

7) Every time a script is called, you can set the current time to a session variable, and then check that every time another script is called. By doing so, you can easily create your own system for forcing the session to be destroyed (and forcing a user to be logged out) whenever they idle longer than a time you choose. From what I've heard, forcing users to be logged out after 10 minutes or so is a great way to prevent hacking (and it's only a minor inconvenience for a small number of users).

 

8) Concerning the Ajax problem that the Treehouse article points out, my proposed solution is to regenerate the session ID, etc., etc. every time a PHP script is called, except for PHP scripts that might be called often via Ajax. For example, if you call a PHP script every time a checkbox is clicked in a list to update the DB accordingly, then you could easily have a user click a bunch of checkboxes real quickly, which could cause issues if you're regenerating the session ID each time in that Ajax-requested script. However, for simple Ajax operations like that, updating the session ID each time seems unnecessary. Also, it's important to keep in mind that a user could easily write a few lines of JS in their console that would loop through all the Ajax-enabled components on a page, and trigger them all within milliseconds of each other. Point being, don't do anything fancy with the session for scripts that can be quickly called.

 

Well, those are my thoughts for now.

Before I get to writing the actual functions, I would appreciate any feedback from anyone.

 

Thanks a lot.

Link to comment
Share on other sites

Jon: The general nature of a framework means it will most likely have more features than you need. You must also keep in mind that due to the composer based nature of the package, you will dynamically only load what you need. Laravel provides you with session management from anything from a database to memcache, but won't utilize the whole package in each go. I just think I should clarify that.

 

Matt: Static is generally bad, unless you deal with pure helper classes or helper methods. Laravel and YII both lies a little bit to you in code appearance, as you are actually talking to a Facade class. While you seemingly call static methods all the way, everything are objects behind the scene. The main reason to not do static classes is testability. Code you can't test is often badly written by design.

Link to comment
Share on other sites

Yes, you are right, Antonio. But even with the ability to reduce the code I actually need with Composer, I still think it's overkill.

 

I will gladly use a library/framework if I need to quickly produce something and I don't have the time to do it the right way, but in actuality, I've only been researching the secure session conundrum for about a week now, and already, I pretty much know everything that needs to be done to create secure sessions.

And best of all, after that week of research, I can now quickly code something that is tailored and customized to exactly what I need, and more efficient than anything I could ever get from a framework.

 

As I've said before, I don't disagree with frameworks in theory, but if I have the opportunity to take a week or so to really research a topic deeply, and really learn about it, and come out of it with a high-level of understanding that allows me to quickly write my own code, then I'm going to do it.

Furthermore, I think that approach has greatly helped as a programmer and developer. I think too many people these days are too quick to turn to a framework. And really, I think the irony is that the better you understand the core concepts of something, the better you ability to use a framework will be. Case and point, I understand jQuery better than just about anyone I know, and I loath using it. That's not a coincidence.

 

Anyway, I know you're a big Composer guy, and I get it. It's very powerful, and it's the right way to create a PHP environment, but nowadays, with PHP 5.4, 5.5 and beyond, the standard PHP library has pretty much everything someone will ever need.

 

Thanks again for your input though.

 

Also, Antonio, as a final bit, I didn't get your comment about why static classes are hard/impossible to test. Could you please elaborate on that a bit more?

Thanks.

Link to comment
Share on other sites

It's mostly related to test stubs and the nature most static methods are written. Static code is procedural by nature, and while that is not bad in itself, you cannot (easily, with a few exceptions) mock that. The point of OOP is to create modular classes with few hard dependencies, for re-usability and easy refactoring.

 

A mock is basically a replica of object functionality. If your class expects an object implementing a Deductable interface, you can make a mock with the methods required. While that may seem illogical, you wouldn't be able to delete the class Deductor if your tests relies on it, but with a mock, the dependency is dissolved. I don't really think I explain that anywhere near good, but I hope I drove the point trough.  

 

If those dependencies can't be mocked due to static methods, you'll have real problems testing what you really want to test. That will prevent you from easily introducing new functionality without affecting the classes AND tests tied to it. Static is therefor not bad in itself, but it will make things seriously harder if you want to use the process test-driven development. As a general rule, everything static is therefor advised against. Everything static is possible to write object-oriented, so that is why some programmers will disregard static methods or classes with a few exceptions.

 

1. Factory methods. These are generally helper methods inside a class that builds the object for you.

2. Facades and IOC-containers. (used by YII and Laravel) The facade class simply wraps object calls in a static programming interface for you and add any needed dependencies set in the constructor. This is for easy usage and prettier code than writen large setup instantiations with lots of object params. Behind the scenes of a YII call for Product::findById(1), the call is made using an object.

3. Helper methods. Your typical Math class and helpers for sorting, filtering, etc.

 

Most of the views might be a bit extreme, but they are issued by experienced programmers. The statements especially holds true in larger software and collaborating settings or where you need proof of correctly functioning programs. (Bugs in the medical section might be bad for example) While I don't tend to follow advice religiously, these are mostly established practices in the work sector here. I therefor try to stick to it for the sake of training.

 

The counter-point to make is that all code might not need testing. That argument falls short if others depend on your software, which again gets me to composer. Due to small packages being tested, I don't need to write my own Money pattern object and risk bugs in sensitive areas of my code. The same level of security isn't needed for session management, but it frees my time to focus on what makes my project unique.

 

You should also keep in mind that packages aren't necessarily a small framework in of itself. If you prefer small, focused classes - as I do too - you should consider publishing your session implementation on Packagist.com when you are done. ;)

 

Sorry for the long post. Hope I drove some points home at least. There's plenty of resources on the web if you want a better explanation.

 

Edit: To illustrate why I like testing a bit better, I will show you the test and domain code from my implementation of a deductor class. The tests both works as documentation, as you can easily follow what is done, and ensures I never break the behavior I expect here. This is vital as other parts of my system, such as my Coupon implementation, uses this class to deduct a coupon value for the checkout total.

<?php namespace SpeedJumpers\Cart\Tests\Pricing;

require dirname(__DIR__) . '../../vendor/autoload.php';

/**
 * Description of DiscountTest
 *
 * @author Thomas Maurstad Larsson <thomas.m.larsson@gmail.com>
 * @version 0.1
 */

use Money\Money;
use SpeedJumpers\Cart\Pricing\Discount;

class DiscountTest extends \PHPUnit_Framework_TestCase
{

    /** @test **/
    public function discount()
    {
        $discount = new Discount(Money::USD(1000));

        $this->assertEquals(Money::USD(900), $discount->reduceByPercent(10), "Should return new amount with 10% deduction");
        $this->assertEquals(Money::USD(500), $discount->reduceByPercent(50), "Should return new amount with 50% deduction");
        $this->assertEquals(Money::USD(950), $discount->reduceByAmount(50), "Should return new amount with 50 cents in deduction");
    }

}

Here's the actual class:

<?php namespace SpeedJumpers\Cart\Pricing;

/**
 * Description of Discount
 *
 * @author Thomas Maurstad Larsson <thomas.m.larsson@gmail.com>
 * @version 0.1
 */

use Money\Money;

class Discount
{

    private $base;
    
    /**
     * Public constructor
     * 
     * @param \Money\Money $money
     */
    
    public function __construct( Money $money )
    {
        $this->base = $money;
    }
    
    /**
     * Deduct the price by percentage
     * 
     * @param int $deductionPercent             The percent to deduct from the price
     * @return Money                            A Money object with new amount
     */
    
    public function reduceByPercent( $deductionPercent )
    {
        $this->assertPositiveInteger($deductionPercent);
        return Money::USD( $this->amount() - (( $this->amount() * (int) $deductionPercent) / 100) );
    }
    
    /**
     * Deduct the price by amount
     * 
     * @param int $amount                       The amount to deduct from price
     * @return Money                            A Money object with new amount
     */
    
    public function reduceByAmount( $deductionAmount )
    {
        $this->assertPositiveInteger($deductionAmount);
        return Money::USD($this->amount() - (int)$deductionAmount);
    }

    /**
     * Returns the amount as units from base
     * 
     * @return int              The amount
     */
    
    private function amount()
    {
        return $this->base->getAmount();
    }
    
    /**
     * Assert positive integer
     * 
     * @param type $int
     * @throws \InvalidArgumentException
     */
    
    private function assertPositiveInteger( $int )
    {
        if ( ! is_int( (int) $int) || intval($int, 10) === 0)
            throw new \InvalidArgumentException("Must be a positive integer over zero");
    }

}

And here the checkout expect the deductor to work on the total:

class Checkout
{
    ...

    /**
     * Apply a discount using a Coupon
     *
     * @param \SpeedJumpers\Cart\Pricing\Coupon $coupon
     */

    public function applyDiscountUsing( Coupon $voucher )
    {
        $deduction = new Discount($this->totalAmount);

        if ( $voucher->isAmountDeduction() )
            $deduction->reduceByAmount($voucher->value());
        else if ( $voucher->isPercentageDeduction() )
            $deduction->reduceByPercent($voucher->value());
        else if ( $voucher->isFreeShipping() )
            $deduction->reduceByAmount($this->shippingDestinationAmount());

        $this->subtractFromTotal($deduction);
    }

   ... 

}

I hope that kind of shows why testing can be very good.

Link to comment
Share on other sites

In my current workplace, we rely very heavily on TDD, utilizing both unit and functional tests. The tests you speak of seem to be more like unit test in nature.

In my personal experience, I do not feel like OOP offers any advantage over procedural coding when it comes to testing. I feel like good code, whether it be OOP or procedural, is easy to test, and bad code (be it either) is hard to test.

 

Where I will agree with you though, is that I think that a majority of inexperienced programmers tend to lean towards procedural code over OOP, in which regard I agree with you that procedural code is generally harder to test (because it's usually written by less-experienced programmers).

 

When it comes to unit testing, I find that a lot of testing is performed directly on the model and the changes the model goes through in the various stages of the program/page. To that end, OOP vs. procedural does not really matter (I personally think).

 

Also, while I think that testing is good in theory, in practice, I feel that quite often the gaps in a programmer's thinking carry over to gaps in their testing, which leads to incomplete code coverage and possible bugs.

 

And at the end of the day, I have seen many bugs in code that is supposedly "fully tested". As such, I fully commend you for taking testing seriously, as I feel it truly is important, but the reality is, a bad coder is a bad tester, and the resulting code is bad regardless of whether testing was conducted or not. To that end, testing really doesn't do much for me.

With all that said, I do hope that over time, I will come around to the importance of testing, and do more formal testing myself, but I'm just a bit jaded by what I've personally seen in a TDD environment.

In the workplace, more often than not, "required testing" simply equates to less development time, which again leads to bugs.

 

Just to give you a little anecdote, the last project I was on, I had a huge workload (more than most of my co-workers) and as such, I did not have enough time to conduct any formal testing. However, every component I wrote work 100% of the time without any bugs (and we have a huge team of testers that pick everything apart), whereas some of my co-workers that wrote lots of tests still had bugs in their code after our codebase went to production.

I'm not telling you this in an effort to try and show you how awesome a programmer I am, I simply say that to let you know why I'm personally not quite sold on testing and TDD yet.

 

One thing I will say though, I have found that over time, my coding style is much different from most people. I have found that I naturally work in a much more iterative style than most people. I quite often write just a little code (often just a single line), test it out exhaustively, and then move onto the next line and rinse and repeat.

In that way, I think that I naturally test my code a lot more than most people, thus making testing less necessary. (I don't mean to suggest that I never make mistakes; simply, I personally am still searching for the silver lining of TDD in an actual development environment with hard-set deadlines.)

 

As a final point, all frameworks like Yii and Laravel have bugs in them. And the problem with those bugs is that because the codebase is so big and usually so much of a black box, it's really hard to find and fix the bugs. To that end, in most cases, I trust my own code a lot more. (Of course, there are instances where I am going to rely on libraries for things that I have no expertise on, but I generally like to try and become an expert in a subject matter than rely on someone else's expertise. I guess I've been burned too many times by supposed "experts", but I digress.)

 

Anyway, sorry for this really long, scatterbrained post. I don't have the energy to go back and edit it.

I do believe that testing is good, and I think that it's great that you believe in it, but I think that in your case, you're a great tester because you're a great programmer. They go hand-in-hand. Testing does not solve anything for bad programmers. All it does it create more hectic deadlines.

 

Just my two cents.

  • Upvote 1
Link to comment
Share on other sites

I agree with you on almost every point. I also think you are a great coder, and there's no mistake you produce few bugs. The tests in questions are unit tests, yes. I don't really perform functional testing unless you count confirming behavior be looking at the output result.

 

The statement regarding test quality versus code quality is spot on. Testing can absolutely give you a false sense of security, and that is why I focus more on the process of TDD than the actual unit tests themselves in my post. TDD helps me keep focused on a single class at a time, where I normally get scattered-brained and want to implement everything at once. I'm also a "feature-creaper", and produce way to much "nice-to-have"-functionality unless kept in a straight line. Because of the process, I can't really refactor large pieces of code at once, (and introduce errors in the process) but must walk the line on a tight rope. I've seen this so much in fellow programmers, that I believe TDD as process can help them out a lot. I'm really more of an artistic person than a highly logical one.

 

Good tests are the core of TDD. I don't really write good test, or many tests for that matter. The point is never to produce a large amount of tests for me, but to write those tests that matter in real life. I want to make sure that vital parts of a class works as expected, and I want it to keep working the same way after I've been on a refactoring frenzy. The rules in TDD are also generally "one-assertion-per-method", but I prefer my highly expressive style of testing to other peoples preferences. As stated, TDD is a process for me. My deduction class should really assert on a valid percentage value and test for exceptions on illegal values, but I couldn't be bothered at the time...

 

I've especially fallen in love with clear, expressive methods that is highly readable. When a piece of code makes sense even in queens English, I'm starting to become really happy with my code. This is also why I wanted to share the following piece of code. What started out as an ugly algorithm in a checkout class, magically transformed itself into a beautiful, reusable piece. It's used several places in my current project.

 

I found you point about one-liners really interesting. I've read a lot about coding principles recently, and the SOLID principles really stuck with me. I especially find the single-responsibility principle extremely valuable. Due to that, my methods rarely does more than one thing neither. The next things that stuck with me are a lot of so called "coding smells". Especially "Large class", "Long method", and "long parameter list" stuck with me. All combined, have resulted in a lot simpler code split up into smaller classes, that are usually more geared towards their actual intention. My largest revelation was though when I read about primitive obsession. That connected a lot of dots between my Java background and my PHP experience. I've mainly gathered knowledge from books during the last year, but I recently stumbled upon a resource that provides short introductions to most of the earlier stated smells. I think you'll like it: http://sourcemaking.com/

 

I too must apologize for a long post full of rambling. Your post opened the flood gates, I guess. Anyway. I really appreciate your long post and respect all your views to the fullest. As "nerds", we are often way to opinionated and religious about the "one, true way" to everything, and therefor I try to underline the subjectiveness of my statements clearly. Looking forward to reading any of your thoughts.

  • Upvote 1
Link to comment
Share on other sites

I definitely agree with you that TDD is very good at helping guide us as programmers, and keeping us on track and avoiding feature creep as much as possible. With that said, I have my own method I employ for the very same purpose called make-a-note-of-everything-I-want-to-make-before-I-start-coding, which is very similar to TDD , except it only takes me a fraction of the time TDD does.

 

Also, while I don't formally employ TDD, I love adding console.log statements to my JS everywhere and calls to a custom-built PHP function for reporting things in my code. I use both of these a lot, so in that sense, I'm essentially doing the same thing that you're doing with unit tests. I like relying on only console.log statements in JS and my custom function in PHP though, because it allows me to use another helper script I wrote that goes through all my code before I push it to production, and removes all of those statements from all my files.

 

Also, I totally agree with you that one test statement per method is more than enough, especially when you keep your methods lean, which you seem to and I totally get. I generally like to keep functions short as well, but I don't mind making a function a bit longer if the function is designed to accomplish a specific task, and I know that none of the code in the function will be used anywhere else.

 

Also, like you, I am very opinionated when it comes to programming, but I do try my best to keep an open mind when I'm introduced to something that I'm not familiar with. I think doing so has helped me grow a lot as a programmer. I'm always willing to check out something new, but after giving it an honest effort, I also know when something isn't my cup of tea, and when to go back to something that works better for me.

 

Also, (Christ! How many paragraphs in a row have I started with "Also"?!) I think it's interesting that on the surface, you and I take very different approaches to programming, but at the same time, when it comes down to fundamental truths about programming, we definitely see eye to eye in many ways. As such, the way I see it is this: I have a way of programming that works for me, and you have a way of programming that works for you, but in the end, we're really writing the same quality code that accomplishes the same thing. There's no reason to force or try to convince each other why our coding methods (no pun intended) are better.

 

You're an awesome programmer, and I greatly respect your skills. I also know that you're just now starting out your career, but you will definitely go far before too long. You have the smarts, the drive, and most importantly, the passion.

Anyway, I don't mean to turn this post into a praise fest (and really, I should get back to the original topic of this thread at some point), but I totally agree with everything you have said, even though I don't personally buy into the whole TDD thing. Like I hinted at before, to me, TDD is just the next big fad to come along that is supposed to suddenly fix all our broken code (but you and I both know that it doesn't work that way). Good coders will use TDD properly, and bad coders will fail at TDD, and their code will still suck.

 

Also, thanks a lot for that link. I took a brief look at it, and it's very useful. It will definitely take me some time to really work through it though.

Thanks.

 

So yeah, if there's anything else you want to say on the matter, by all means, go ahead.

I, however, am going to try and direct my next post in this thread towards writing secure-session functions.

Thanks again for all your input. I always enjoy hearing what you think.

Link to comment
Share on other sites

This has been a very interesting read!  I want to throw my 2 cents in as well, and either of you can correct me if I'm wrong.

 

Even though I have had a lot of experience coding, both of you guys are better coders than me!  I love database design and programming as well as the front end, so I tend to spread myself too thin I think.  That being said, I have learned a lot from Jon over the past 2 years, and let me tell you, when it comes down to it we are a lot alike in our attitudes towards coding.  For one, I agree with Jon that the iterative style of testing is better than throwing a bunch of code out on the screen, and then going back to fix all the bugs.  Many programmers (including myself) often don't take the time to go through and thoroughly think through the logic they have written.

 

Second, over time I have become much more flexible about my approach towards solving problems in the most organized way.  What I mean is that I will often do things a little outside accepted patterns in order to achieve better performance.  One example being that I know very well how to normalize a database, but when you start thinking about how the data will be accessed, sometimes some redundant data in a table is better than 6 joins, which will slow down the site and irritate the user!  The same is true for procedural vs. OOP!  While OOP is an awesome way to encapsulate and organize code, it has it's time and place and procedural programming will always be faster (and easier to debug IMHO).  I know that Jon agrees with me on this!  The same goes with frameworks.  Why in the hell would I trust my site's security to a huge entanglement of classes and bloat when I can code the same thing in a little more time, but have it twice as secure, take a third the space on the hard drive, and be 10 times as fast?  I'm not saying that I don't use someone else's class or library here and there, but the point is that I am not going to rely on another person's code to make my site.

 

Sorry guys, I have vented enough!  Also, Antonio, I know as well that you are an awesome coder and you have given me some good advice here in the past.  I'd like to hear your take on the whole hardcore MVC, let's recode our whole site using classes up the ying yang, trend?  Also, having looked at your excellent work over the years, you would be a great choice to give Jon and I some advice on ways to better organize our site.

 

Matt

  • Upvote 2
Link to comment
Share on other sites

Jon: Very interesting. I've started using a scratch-card when I program, and any thoughts that pop up in my mind is written there instead of switching focus. I think our approach is much more similar than anyone of us could guess from the get go. I think you are correct in your assessment of TDD in general. Nothing is magic, and everything requires dedication and work, no matter which route you go.

 

My conclusion when it comes to programming, is that simplicity is often the most important aspect. You should understand your code after two months away from it and be able to add functionality to it with ease. I have found that a really solid understanding of OOP have helped me understand better where parts of logic should belong.

 

Let me know if you want any input on your session solution. I actually need one myself shortly, and would greatly consider using your solution.

 

Matt: Thanks for the nice words, Matt. There's no denying you have become a good coders over the years. I have seen your progression here. A direct comparison of skill-sets rarely gives you the full picture, and you are definitely stronger than me and Jon in some regards.

 

Regarding frameworks and MVC, I've kind of switched approach recently. I have found out that I have to make too many compromises in a framework, and my solutions don't always manifest themselves in the best way possible. This is especially true for the Models in MVC. I find they restrict me in the ways I write SQL normally. I have therefor started to create two layers of models in my code. One for database interaction and one for Domain specific logic. To give you an example, I prefer to create a Coupon class that encapsulates the logic for that real-world entity, and then create a simple Database models for returning those objects and make CRUD operations for me. I find too much logic gets placed in the wrong parts or that my logic gets too abstract if I rely 100% on a Framework.

 

That very reason is also why I like Laravel. I can use their Auth system, Routing and Session implementation and rely on my own code elsewhere. I think that better encapsulates what I really want to do in my system. That's why I generally recommend composer too.

Link to comment
Share on other sites

Even though I have had a lot of experience coding, both of you guys are better coders than me!

Matt, give yourself more credit. You are an excellent coder, and like you said, we see eye-to-eye on a lot of things. You have come to many of your own sound conclusions when it comes to programming, and I will defer to your advice on many things related to programming. Also, you're a really good graphic designer (something I can't do at all).

 
Also, I agree with you on your approach to not always 100% normalize a DB. In a way, you're talking about a hybrid of a SQL solution combined with a NoSQL solution, which is often the most practical solution in my mind.
Also, while I am guessing that Antonio will disagree, just like you, I find procedural code to be just as organized (or disorganized) as OOP code. The organization of the code really comes down to the ability of the programmer, not the paradigm used. (I know we've discussed this point among the two of us many times, but I wanted to state the fact here for everyone else that wants to participate in the conversation.)
 
At the end of the day, I tend to prefer procedural code with PHP for two reasons:
1) OOP adds code and complexity that is often not warranted in PHP.
2) Most scripts I write are not complex enough to necessitate the inherently more structured nature of OOP. Again, please see #1 above.
 
Anyway, as we have discussed many times, I have nothing against OOP, and it definitely has its uses, but for the sake of keeping things simple and fast, procedural just makes more sense for me a majority of the time in PHP.
 
Edit: Antonio, you replied to Matt in the middle of me replying, so I will add my thoughts to your post here.
 
You should understand your code after two months away from it and be able to add functionality to it with ease.
Yes! This should be one of the guiding principles of all coders. You hit the nail right on the head.
 
Also, I have my own approach to MVC, which is much less abstract than the standard MVC approach, but like you, I find that I often have to write an entire layer of code that allows for easy DB queries (with prepared statements), and then takes the DB results and turns that into a model that works well with what I need. Essentially, it's a middleware layer that I have to code that allows back-end DB data to be turned into a reasonable model that can be easily consumed for view purposes in either PHP or JS.
With that said, I do love the general principles of MVC: First, create a workable model, then run through the programming logic and routing necessary, and finally, spit all the corresponding model view out to the view.
 
And yes, I totally get and agree with your approach to using Composer and Laravel to get the pieces you want, and then coding the rest yourself. I think I'm just more stubborn and curmudgeon than you (and most programmers, for that matter) in that I'd rather take the time to study how to do something really well than to rely on someone else's code. Of course, there all limits for even me, but I think that in the end, we have the same view, just where we draw the line is slightly different (with there being sacrifices that we both have to make).
 

Anyway, good discussion, guys. Thanks a lot.

I'd love to hear Larry's thoughts, if he has the time. 

Link to comment
Share on other sites

Larry, there's nothing in particular I wanted your opinion on. Just if you had by chance read the whole thread (which is admittedly quite long), I was curious if you had any thoughts on anything. That's all.

 

Anyway, I have written the first version of my secure session functions. After doing a lot of research on the topic, I finally came to the conclusion that creating secure sessions is actually not that difficult to do (and a majority of what you need to do is covered in Larry's books).

 

Anyway, without further ado, here's my first attempt at some secure session functions:

 



<?php
  
  // These constants should go in your config file.
  
  define('SITE_ROOT', 'C:\xampp\\');
  
  define('SESSION_SAVE_PATH', SITE_ROOT . 'd79252d7dea8e2812b4ebf29ffc603ed\\');
  
  define('SESSION_NAME', 'f7eac143c2e6c95e84a3e128e9ddcee6');
  
  // This code can go in a separate include file for creating secure sessions.
  
  function session_init($regenerate_session_id = true, $timeout = 600) {
    
    session_save_path(SESSION_SAVE_PATH);
    
    session_name(SESSION_NAME);
    
    session_start();
    
    if ($regenerate_session_id) {
      
      regenerate_session_id();
      
    }
    
    if ($timeout !== 0 && isset($_SESSION['last_script_load_time']) && time() - $_SESSION['last_script_load_time'] > $timeout) {
      
      session_terminate();
      
      return false;
      
    }
    
    $_SESSION['last_script_load_time'] = time();
    
    return true;
    
  }
  
  function regenerate_session_id() {
    
    $session = array();
    
    foreach ($_SESSION as $k => $v) {
      
      $session[$k] = $v;
      
    }
    
    session_destroy();
    
    session_id(bin2hex(openssl_random_pseudo_bytes(16)));
    
    session_start();
    
    foreach ($session as $k => $v) {
      
      $_SESSION[$k] = $v;
      
    }
    
  }
  
  function session_terminate() {
    
    $_SESSION = array();
    
    session_destroy();
    
    setcookie(SESSION_NAME, '', time() - 3600);
    
  }


 

There are several things to note with the code:

 

1) The constants defined at the top of the script should go in a separate config file. Naturally, the SITE_ROOT constant should be changed to whatever is appropriate for your site.

 

2) The 32-character random hex strings generated for SESSION_SAVE_PATH and SESSION_NAME were created by running the following script twice, and copying and pasting the output string:

 



<?php
  
  echo bin2hex(openssl_random_pseudo_bytes(16));


 

After doing a lot of research, I found that openssl_random_pseudo_bytes is apparently the best way to create random strings that can't be easily cracked and that can't result in collisions. The above expression is also used to regenerate session IDs (to be discussed in a second).

 

After running short script above, and assigning random values to SESSION_SAVE_PATH and SESSION_NAME, you then need to create a directory in the site root with the same name as the string assigned to SESSION_SAVE_PATH. Otherwise, the session script will attempt to save the sesssion files to a directory that doesn't exist.

 

Please see the following SO post for more details on where this random string generator comes from:


 

Please also note that it's not necessary to assign completely random strings to SESSION_SAVE_PATH and SESSION_NAME, but it doesn't hurt either. For the session save directory, the most important thing is that it's not in a web-accessible directory and that the directory name is not easily guessable. For SESSION_NAME, the most important thing is that it not contain any information that may give away something about the inner workings of your site. For example, you never want to use something like a user's name or a primary key ID for the session name.

 

For the sake of being as cryptic as possible though, I suggest just going all the way and using random strings for both.

 

3) The session_init function should be called in place of the session_start function. The session_init function accepts two optional arguments. The session_init function starts out by setting the session save path and the session name before actually starting the session. It's always a good idea to change the session save path from the default path, especially when you are on a web-hosting company server that likely hosts many sites on the same server and forces all sessions for all sites to be stored in the same directory by default. Also, just to make things slightly trickier for a potential hacker, not using the default session name of PHPSESSID is a good idea.

 

4) After starting the session, if $regenerate_session_id is set to true (the default), then the session ID will be regenerated. For the sake of regenerating session IDs, you can use the built-in session_regenerate_id function. While not a bad option (and definitely much simpler to implement than my custom function), there is the remote chance of session ID collisions with the session_regenerate_id function, and also, the homebrew method of generating random session IDs is apparently a bit more "random".

 

While it's advisable to regenerate the session ID in almost all cases, I provided the option to disable the regeneration of the session ID in the event that you're using these functions in a script that may get called many times in quick succession. A good example is an Ajax script that is called every time a certain UI element on a web page is clicked. In such a case, you could have a race condition where one call to the Ajax script attempts to access a session ID that no longer exists. In that case, it's best to set the $regenerate_session_id flag to false. Please see the Treehouse tutorial Matt linked to for details on this issue.

 

If the regenerate_session_id function I wrote is called, the current session is first copied to a temp variable, and then destroyed after that. Because we are going to create a new session with a new ID, there's no reason to keep the old session after we have all the data that was stored in it.

 

To create the random session ID, we then use the bin2hex(openssl_random_pseudo_bytes(16)) expression again. After that, we call session_start to start the session again with the new ID and copy all the data from the old session over to the new session.

 

5) The session_init function next checks that a user hasn't been idle for too long on a page, or it automatically destroys the session. The default $timeout value is 600 seconds (10 minutes), but that value can be changed by the second argument to the session_init function.

 

If a user exceeds the timeout value, then the session_terminate function is called, and false is returned by the function. You can check the return value of the session_init function to determine whether a session has timed out or not, and alert the user accordingly.

 

Note that you can also pass a value of 0 for the second parameter to the session_init function to ensure that the session never times out.

 

6) The session_terminate function should be used whenever you want to destroy a session completely. It first sets the active $_SESSION superglobal to an empty array (essentially clearing out any values stored in it), then calls the session_destroy function, which deletes the corresponding session file on the server, and then sets the cookie stored on the client's machine for the session to expire at a time in the past, which causes the cookie on the client's machine to be deleted.

 

7) Note that while the above functions will secure sessions as much as is possible via PHP logic, sessions will not be truly safe unless you both use SSL/TLS and prevent XSS attacks. Without the use of SSL/TLS (i.e., HTTPS), session information sent to a client's machine can be potentially stolen by a man-in-the-middle attack or the like. However, by using HTTPS, all data sent over the wire will be encrypted, and thus unreadable, even if someone steals it.

 

Similarly, if you don't provide the proper safeguards against XSS attacks, a malicious third party could potentially get access to a user's cookie information, which would give them everything they need to steal a user's credentials and possibly get access to all sorts of things they shouldn't have access too.

 

Luckily, if a user were to fall for an XSS attack, the secure session functions above would hopefully prevent any monkey business in that every time the real user went to a new page, a new session ID would be generated, thus making the session ID that a hacker stole useless. In the event that a user's session ID wasn't regenerated after it got stolen, so long as more than 10 minutes had passed since the real user last went to a page, then the session info that the hacker stole would still be rendered useless.

 

So with that, I have given the best first effort I could at creating a set of functions that can be used for easily handling secure sessions.

Any and all constructive criticism is welcome.

 

Thank you.

  • Upvote 1
Link to comment
Share on other sites

 Share

×
×
  • Create New...