Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1

    session security tips and code help


    My site pages are php, html and css. I have no need for a session on main pages. I only want a session on the forms, such as register and contact. session_start() is fine for all pages but i must be able to end the session in my situation. understand?
    session for registration form, then end session. I have no need for it after registration. Further, I do not want the drive filled with session files waiting for the garbage collection. I also need to delete the cookie.
    using xampp on Windows 10, my script works as expected. the session files are deleted and the cookies are deleted.
    I've had to battle this script with session handling. I got to a point where the session is destroyed (i watch the file disappear from the tmp folder), only to see the file reappear after a second. so i got angry and added an unset($_SESSION) to try to force the damn destruction of the file. sometimes php is a pain in the a55. the session_destroy should do what it says: destroy.
    I am aware that a session file will not be destoryed if a user navigates away from the site. I have no idea why browser makers cannot add a header for a website. simply alert the website when the user closed the browser or left the page. it would be nice. another problem is navigating to another page in the site from the form. the session file is not destroyed. Is there a way to detect the session on those pages?
    I will use a cron job to delete the unwanted session files older than 24minutes.

    i will greatly appreciate security tips. really, i cannot see the code behind pro services. I want to know how to harden this script. remember Facebook coders found a way to break the console? what must facebook security code look like? how can this script be harder and better?
    please remember that i am absolutely new to php. if you can show sample code with a concept i will greatly appreciate it.

    one more thing: i don't need to test isset or !empty because my form fields are required. if the data doesn't match, then the formerror handles it. all is good.
    my first form processing script:

    PHP Code:
    <?php

    // is it a waste of code to compare the cookie value (session id)? i atleast make sure you have the cookie.
    if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_COOKIE['My_Session_Name'])) {

    session_cache_limiter('nocache');
    session_name('My_Session_Name'); session_set_cookie_params(0'/register/');
    session_start(); session_regenerate_id(true);

        if (isset(
    $_POST['Submit']) && hash_equals($_SESSION['My_CSRF_Token'], $_POST['token'])) {
            
    $_SESSION['My_CSRF_Token'] = $_POST['token'] = NULL//nullify the token to prevent further usage

            // i am still debating if this is even helpful. i imagine timestamps also play a role. again, a work-in-progress.
            
    if ($_SERVER['REMOTE_ADDR'] == $_SESSION['iNe7adIp'] && $_SERVER['HTTP_USER_AGENT'] == $_SESSION['iNe7wbUa']) {

                    
    //declare variables and set to null.
                    
    $formError $gender $title $firstname $lastname $birthDay $birthMonth $birthYear NULL;
                    
    $fullName $birthDate $fullAddress NULL;

                    if (!( (
    $_POST['gender'] == "Lady") || ($_POST['gender'] == "Gentleman") )) { $formError 1; } else { $gender $_POST['gender']; }
                    if (isset(
    $_POST['title'])) {
                        if (!( (
    $_POST['title'] == "Dr.") || ($_POST['title'] == "Prof.") || ($_POST['title'] == "Prof. Dr.") )) { $formError 1; } else { $ttl $_POST['title']; }
                    }
                    if (
    preg_match("/^[-.'\s\p{L}]{1,32}$/u"$_POST['fname']) && !ctype_space($_POST['fname']) && !ctype_punct($_POST['fname'])) { $firstname sanitizeName($_POST['fname']); } else { $formError 1; }
                    if (
    preg_match("/^[-.'\s\p{L}]{1,32}$/u"$_POST['lname']) && !ctype_space($_POST['lname']) && !ctype_punct($_POST['lname'])) { $lastname sanitizeName($_POST['lname']); } else { $formError 1; }
                    
    $fullName $firstname ' ' $lastname;
                    if (!
    preg_match('/^[0-9]{2}$/'$_POST['bDay'])) { $formError 1; } else { $birthDay $_POST['bDay']; }
                    if (!
    preg_match('/^[0-9]{2}$/'$_POST['bMonth'])) { $formError 1; } else { $birthMonth $_POST['bMonth']; }
                    if (!
    preg_match('/^[0-9]{4}$/'$_POST['bYear'])) { $formError 1; } else { $birthYear $_POST['bYear']; }
                    
    // i intend to use a checkdate() function for further validaion. not yet implemented here. also need to convert the date from input string to integer.
                    
    $birthDate $birthDay '.' $birthMonth '.' $birthYear;
                    
    //other form fields to be implemented. still working on this form.

                    
    if (empty($formError)) {
                            
    // do something with this information.
                            
    $formError $gender $title $firstname $lastname $birthDay $birthMonth $birthYear NULL;
                            
    $_POST = array(); //nullify input. I am aware that this eliminates back button. I am fine with this concept.
                            // for some reason, the session file reappears after deletion. i watch it disappear from tmp, then reappear after a second or two
                            // i've used every command i can find to actually remove the session file. it seems to work but is it correct?
                            
    setcookie("My_Session_Name"""time() - 3600"/register/"); unset($_COOKIE['My_Session_Name']);
                            
    $_SESSION = array(); session_unset(); session_destroy(); unset($_SESSION['My_Session_Name']);
                            
    header("Location: ../ThankYou/");
                      exit; 
    //or die with error message.
                    
    } else {
                              
    $_POST = array();
                              
    setcookie("My_Session_Name"""time() - 3600"/register/"); unset($_COOKIE['My_Session_Name']);
                              
    $_SESSION = array(); session_unset(); session_destroy(); unset($_SESSION['My_Session_Name']);
                              
    header("Location: ../Problem/");
                      exit; 
    //or die with error message.
                    
    }

            } else {
                      
    $_POST = array();
                      
    setcookie("My_Session_Name"""time() - 3600"/register/"); unset($_COOKIE['My_Session_Name']);
                      
    $_SESSION = array(); session_unset(); session_destroy(); unset($_SESSION['My_Session_Name']);
                      include 
    'refresh.php';
                      exit;
            }

        } else {
                    
    $_POST = array();
                    
    setcookie("My_Session_Name"""time() - 3600"/register/"); unset($_COOKIE['My_Session_Name']);
                    
    $_SESSION = array(); session_unset(); session_destroy(); unset($_SESSION['My_Session_Name']);
                    
    header("Location: ../area51/");
                    exit;
        }

    } else {
              
    $_POST = array();
              
    setcookie("My_Session_Name"""time() - 3600"/register/"); unset($_COOKIE['My_Session_Name']);
              
    $_SESSION = array(); session_unset(); session_destroy(); unset($_SESSION['My_Session_Name']);
              exit;
    }

    exit;
    ?>

    please remember that i am a beginner. professional source code is not visible, so i only know to use if conditionals here. I'd like to see Apple or Microsoft code for this but it is not possible. Thus, i seek advice from anyone that knows how to make this script better and more secure.
  2. #2
  3. Lord of the Dance
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Oct 2003
    Posts
    4,179
    Rep Power
    2011
    First important point is to never trust the client and always do validation at server side.
    What happens if scripts are disabled or form hasn't even been used?

    if user login and then somehow end back to login form, will they then be logged out?

    any reason you use set cookie manually, instead of just using SESSION? only reason I can see for this, is if you want a remember me option or similar.

    just courius why you don't see the standard garbage collector to be good enough?
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    yes there is a reason why i set the cookie. all tutorials and even the data at php.net is not working for me. my cookie is never deleted. I have functioning eyes and i see the cookie in Edge browser console until i close the browser, hence a session cookie. I don't want the cookie hanging around until the browser is closed.
    this code: $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 3600, $params["lifetime"] etc. etc. does not remove the cookie. I can see it.
    I decided to forget the tutorials and think of a way to actually delete the cookie when i say delete cookie. Thus, I gave it a name and set the proper parameters and the cookie is deleted when i expect it to be deleted.
    basically, every other method has failed me. I tried my own code and the cookie is deleted.

    regarding session files, i just don't want them hanging around. i like a clean and orderly environment. i prefer to destroy them when i want them destroyed. i find it irritating. sorry but i cannot handle my tmp file full of files that are supposed to be destroyed. it drives me nuts.
  6. #4
  7. Wiser? Not exactly.
    Devshed God 2nd Plane (6000 - 6499 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    6,271
    Rep Power
    4193
    There's really no point in trying to clean up session files and cookies immediately. Any solution you come up with will never be perfect and may leave stuff in varying situations. If you really want to try and keep your session directory clean then just rely on your cron job to do it. Other wise, let PHP's garbage collector do it's job. You can tweak PHP's session garbage collector to run more frequently if you want. You could even have it run on every page load mostly negating any need for a cron job, though I wouldn't really recommend that.

    Code:
            $params = session_get_cookie_params();
            setcookie(session_name(), '', time() - 42000,
                $params["path"], $params["domain"],
                $params["secure"], $params["httponly"]
            );
    This code works to delete the cookie just fine for me in Firefox at least. Note that you won't notice the cookie being missing until your next page load, and any pages that call session_start() will just re-create it.
    Recycle your old CD's



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    I was thinking that a CONTENT_LENGTH may also be good practice since my form contains info that shouldn't be greater than 500bytes.
    && $_SERVER['CONTENT_LENGTH'] < 2048) {

    I assume that CONTENT_LENGTH is to be specified using bytes. Thus, 2kb is 2048bytes. yes?
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    this is great. it works. I've tested it. CONTENT-LENGTH will help avoid large amounts of input. the server and the php ini are set too high for such a small form. I wish someone would've mentioned this before. I was just thinking of how to limit the POST array and i came across the CONTENT-LENGTH delimiter.
    PHP Code:
    if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_COOKIE['My_Session_Name']) && $_SERVER['CONTENT_LENGTH'] < 1024) { 
    further, I've discovered why the session file seems to reappear: it is the old session. I dropped the file into notepad to investigate and it holds my old session variables (the first form token and the random input name variable.) This means that the old session needs to be destroyed as well. I really wish someone could've noticed this and mentioned it here.

    what about a whitelist? I found a document about using a whitelist array to check against the submitted data. I think that this concept is also good security?
  12. #7
  13. Wiser? Not exactly.
    Devshed God 2nd Plane (6000 - 6499 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    6,271
    Rep Power
    4193
    Keep in mind that your PHP code isn't run until the request is processed. That means your content length filter isn't really going to do much as PHP will have already accepted and parsed the entire request at that point. If I posted a 100MB request to your script (assuming php.ini allows it) then PHP will still spend time downloading all 100MB, parsing it, constructing $_POST, etc. It won't get cut off after 1024 bytes. If you want to prevent large requests, the way to do that is by configuring php.ini's post_max_size setting. Set it at a level slightly above whatever you anticipate being the maximum data any of your scripts would accept.

    White listing parameters is fine if you want to do that, but it provides little in the form of security. It may help you avoid isset() by ensuring parameters exist but that's about it really. If your script only ever interacts with parameters it knows about then someone submitting unknown parameters doesn't really mater, they will simply be ignored.
    Recycle your old CD's



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  14. #8
  15. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    Thank You kicken, that makes alot of sense. I appreciate your time and effort.
    I'm worried about my host shutting me down because of bad php. I'm a beginner and i have no idea what i'm doing really. I should be able to change the php ini settings on the host server since i'm only paying for a dedicated server. I guess that i assume that i have access to the ini file. otherwise, i will not sign up with this host unless they change it for me. Anyway, Thank You.

    ps: while trying to better understand the session process, i wondered if regenerate_id should occur after i validate the token from the first form? i moved it to that position and now the old session file is not showing. perhaps it is important to know exactly when to do this. I am a bit out of my element here. Php is a bit much for a beginner. I'm only experienced with html, css and javascript. I once played around with c++ console app tutorials. I am a bit frustrated with this session of mine. i sometimes contemplate giving up but i'm not a quitter. i will keep fighting for this. I want to be a better programmer.

    i hope that everyone has a great day. i'm off to read some more about sessions and security.
  16. #9
  17. Wiser? Not exactly.
    Devshed God 2nd Plane (6000 - 6499 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    6,271
    Rep Power
    4193
    For my previous replies I hadn't really looked through your code at all. I took some time to look over it, here's some general feedback and a re-write.

    // is it a waste of code to compare the cookie value (session id)? i at least make sure you have the cookie.
    if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_COOKIE['My_Session_Name'])){
    There's nothing to compare the cookie value too, so yes it'd be pointless to try. Checking if the cookie exists is a bit pointless also but doesn't really hurt I suppose.

    session_cache_limiter('nocache');
    nocache is the default (unless you changed it in php.ini) so this line is unnecessary.

    if (isset($_POST['Submit']) && hash_equals($_SESSION['My_CSRF_Token'], $_POST['token'])){
    I'm not sure what $_POST['Submit'] is, but checking it is probably unnecessary. Checking that it's a post request as you do above should be sufficient.

    if ($_SERVER['REMOTE_ADDR'] == $_SESSION['iNe7adIp'] && $_SERVER['HTTP_USER_AGENT'] == $_SESSION['iNe7wbUa']){
    What is iNe7adIp? iNe7wbUa? Use meaningful names not random/hard to understand strings.


    if (!(($_POST['gender'] == "Lady") || ($_POST['gender'] == "Gentleman"))){
    You can put valid options in an array then use in_array to simplify things.

    $formError = $gender = $title = $firstname = $lastname = $birthDay = $birthMonth = $birthYear = null;
    $_POST = []; //nullify input. I am aware that this eliminates back button. I am fine with this concept.
    Setting your variables to null and $_POST to an empty array doesn't really do anything meaningful. It also has no effect on the back button.

    $_POST = [];
    setcookie("My_Session_Name", "", time() - 3600, "/register/");
    unset($_COOKIE['My_Session_Name']);
    $_SESSION = [];
    session_unset();
    session_destroy();
    unset($_SESSION['My_Session_Name']);
    You have this code multiple times. It should be consolidated either by making a function or re-writing the script in such a way that you only need one instance of the code.

    i wondered if regenerate_id should occur after i validate the token from the first form
    session_regenerate_id only really needs to be done if you're granting the person increased access, such as on login. Doing it more often than that is unnecessary.




    PHP Code:
    <?php

    $validGenders 
    = ['Lady''Gentleman'];
    $validTitles = ['Dr.''Prof.''Prof. Dr.'];

    if (
    $_SERVER["REQUEST_METHOD"] == "POST"){
        
    session_name('My_Session_Name');
        
    session_set_cookie_params(0'/register/');
        
    session_start();
        
    $formError false;

        
    //Define expected fields and set them to null.
        
    $expectedFields array_fill_keys([
            
    'gender''fname''lname''bDay''bMonth''bYear''fullAddress'
            
    'token'
        
    ], null);

        
    //Replace expected fields with input data
        
    $data array_replace($expectedFields$_POST);

        if (!isset(
    $_SESSION['My_CSRF_Token']) || !hash_equals($_SESSION['My_CSRF_Token'], $data['token'])){
            
    $formError true;
        }

        if (!isset(
    $_SESSION['browserIP'], $_SESSION['browserUA']) || $_SERVER['REMOTE_ADDR'] !== $_SESSION['browserIP'] || $_SERVER['HTTP_USER_AGENT'] !== $_SESSION['browserUA']){
            
    $formError true;
        }

        if (!
    in_array($data['gender'], $validGenderstrue)){
            
    $formError true;
        }

        if (
    $data['title'] && !in_array($data['title'], $validTitlestrue)){
            
    $formError true;
        }

        
    $data['fname'] = sanitizeName($data['fname']);
        if (!
    preg_match("/^[-.'\s\p{L}]{1,32}$/u"$data['fname']) || ctype_space($data['fname']) || ctype_punct($data['fname'])){
            
    $formError true;
        }

        
    $data['lname'] = sanitizeName($data['lname']);
        if (!
    preg_match("/^[-.'\s\p{L}]{1,32}$/u"$data['lname']) || ctype_space($data['lname']) || ctype_punct($data['lname'])){
            
    $formError true;
        }

        if (!
    preg_match('/^[0-9]{2}$/'$data['bDay'])){
            
    $formError true;
        }

        if (!
    preg_match('/^[0-9]{2}$/'$data['bMonth'])){
            
    $formError true;
        }

        if (!
    preg_match('/^[0-9]{4}$/'$data['bYear'])){
            
    $formError true;
        }

        
    //other form fields to be implemented. still working on this form.

        
    if (!$formError){
            
    //Do something with $data

            //Destroying the session is not necessary, but if you want to...
            
    killSession();

            
    //If you don't destroy the session, clear the CSRF token at least
            //$_SESSION['My_CSRF_Token'] = null;

            //Send to thank you page.
            
    header("Location: ../ThankYou/");
            exit;
        } else {
            
    //Destroying the session is not necessary, but if you want to...
            
    killSession();

            
    //Send to error page.
            
    header("Location: ../Problem/");
            exit;
        }
    } else {
        
    //Destroying the session is not necessary, but if you want to...
        
    killSession();

        
    //No a post request, go back to form?
        
    header("Location: ../area51/");
        exit;
    }

    function 
    killSession(){
        
    session_destroy();
        
    $params session_get_cookie_params();
        
    setcookie(session_name(), ''time() - 42000,
            
    $params["path"], $params["domain"],
            
    $params["secure"], $params["httponly"]
        );
    }

    ?>
    Recycle your old CD's



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    I didn't expect you make code. I was pleasantly surprised at your post. I really appreciate you taking time to code. I'm used to beibg ignored, so no worries. I suppose i'm a loser. LOL. I just hope always that someone helps me out from time-to-time.

    I have to laugh because I started to recode this yesterday. I was telling my Wife that my code is sloppy and i have too many else statements with the same code. I decided to build an error function called errorPage. Then i moved all of the if statements into consecutive lines and the else statement calls the function. Like a step-by-step procedure. I guess it resembles an old basic program. Anyway, i saw the need to refine the code. I like what you have here, especially the array. Very nice code.

    I tried to add reputation for your earlier post but i have no idea how this works. I have alot of firewall settings and a proxy file. I cannot view NFL videos. Thus, i wonder if something is blocked that i cannot see a give reputation button or link?

    I am trying to learn but it can be difficult alone. I have no friends really. Even if i had a bunch of friends, i doubt that any would be coders. Thus, i battle php alone. it is nice that you help me out here. Thank You very much.
  20. #11
  21. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    one more thing to mention:
    you say "nocache is the default (unless you changed it in php.ini) so this line is unnecessary."

    i know this but i will be using a dedicated server for my website. I worry about a rogue employee changing settings or something. I always figure that i should have some sort of backup plan incase someone fiddles with the ini file. you really cannot trust people. I just figure it may be best to try to handle the matter in my code before something happens.
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    regarding $_POST['Submit']. This is the value or text on the input button. The name can only be matched outside of the session. Thus, I made a random_bytes unique name for the input, then I check if both are valid. I suppose it is simply a test to see that you aren't using your own form. A random input name, button value, and the input token should indicate that you are using my form.
  24. #13
  25. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    question:
    PHP Code:
    if (!isset($_SESSION['My_CSRF_Token']) || !hash_equals($_SESSION['My_CSRF_Token'], $data['token'])){
            
    $formError true;
        } 
    unless I'm wrong, this is a bypass security concern. isset could be null or 0 here, yes? isn't the goal of a token to be absolutely certain that they match? i read this as if isset OR matches. isset doesn't matter here, match is the goal to prevent CSRF and remote form submission.

    i think that a null value passes isset, so the hash_equals is never checked.
  26. #14
  27. Wiser? Not exactly.
    Devshed God 2nd Plane (6000 - 6499 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    6,271
    Rep Power
    4193
    i know this but i will be using a dedicated server for my website. I worry about a rogue employee changing settings or something.
    The whole point of having a dedicated server is so that you have complete control over how it's configured. Any decent hosting company won't touch your server configuration after it's been initially setup unless you ask them to.

    It certainly won't hurt to have that line as an extra safty net if you want, it's just unnecessary.

    regarding $_POST['Submit']. This is the value or text on the input button.
    Unless you have multiple submit buttons that perform different actions, there's no reason to test for the submit button. I don't think it's a problem now days, but in the past checking for the submit button would actually cause problems as some browsers wouldn't send it if the user simply hit enter to submit.

    Thus, I made a random_bytes unique name for the input, then I check if both are valid. I suppose it is simply a test to see that you aren't using your own form.
    The point of the CSRF token is to make sure the form is yours. No need to duplicate that task with some other input's name being random.


    unless I'm wrong, this is a bypass security concern. isset could be null or 0 here, yes? ... i read this as if isset OR matches.
    Notice the ! in front? It reads as: if not isset or not hash_equals. So if My_CSRF_Token is missing/null the isset() is true and results in $formError=true. If My_CSRF_Token exists and has a value then it does the hash_equals test to ensure the posted token is correct.

    The isset check is just to ensure your CSRF token exists. However unlikely, it's possible someone may submit the form without an active session. For example, if they load up your form, but then leave it open for hours before actually filling it out and submitting it. In that time frame your server may have cleaned up the session data due to inactivity so whey they submit the form instead of resuming an existing session they would be starting a brand new one.

    The isset is not strictly necessary, in that scenario the hash_equals would still fail but you'd also get a Notice Error: Undefined index 'My_CSRF_Token' in ... error showing up in your error log files. The isset check prevents that error.
    Recycle your old CD's



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  28. #15
  29. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2018
    Posts
    35
    Rep Power
    1
    really, Thank You for spending time to help me out. I feel like i definitely need to pay you for your help. Most people just ignore me and probably laugh calling me a loser. I don't really understand certain concepts yet but i am trying to understand. Your posts are most helpful to me. I spent about 30 minutes with the OR logic and i get it. I see how it works. I made a small form to see it better in action. I didn't know this logic until now. Thank You. I'm currently recoding this script to what you have shown me. I am not copying and pasting it because i will learn nothing by doing that. So after i recode this, i will try to better understand the complete script.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo