Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: How to protect other files in Login folder etc

  1. #1
    Join Date
    Sep 2007
    Location
    Maui
    Posts
    628
    Thanks
    277
    Thanked 14 Times in 14 Posts

    Default How to protect other files in Login folder etc

    In the past I have always used .htaccess to protect folders so this is my first attempt at an actual login script & I have some questions. So far I have done the Login and the Lost Password parts, and they work great, but are probably not as secure as they could be.

    1. .htaccess protects all files in the folder but login does not. After reading posts from other people writing login scripts, I get the impression that you have to put require_once('login.php') (or something) at the top of each file in the folder and use sessions somehow. I have googled sessions and I still don't quite get it. Can someone please explain sessions from scratch?

    2. Are sessions necessary for login scripts? They seem to be for logging users out after a set length of time, or remembering info from their last session. Can you control what values are stored in the session info? Are cookies files that store the session info?

    3. I understand == but what does === mean?

    4. Is this a good function to use to prevent SQL injection?
    Code:
    function clean($str) { 
      $str = @trim($str); 
      if(get_magic_quotes_gpc()) { 
        $str = stripslashes($str); 
      } 
      return mysql_real_escape_string($str); 
    }
    5. I know in php.ini that magic_quotes_gpc = On, so what does this mean...
    Code:
    if(get_magic_quotes_gpc()) { 
        $str = stripslashes($str); 
      }
    and what does it accomplish security-wise? Do people use slashes in SQL injection?

    6. Does this remove blanks at each end of a string? Anything else?
    $str = @trim($str);

    7. Is it necessary to md5 encrypt the passwords in the database? If encrypted, how do you send people forgotten passwords? If they are decryptable, couldn't anyone do it? So what is the point?

    Thanks for any help. e
    Last edited by kuau; 01-16-2012 at 10:47 PM. Reason: added a question

  2. #2
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    Quote Originally Posted by kuau View Post
    1. .htaccess protects all files in the folder but login does not. After reading posts from other people writing login scripts, I get the impression that you have to put require_once('login.php') (or something) at the top of each file in the folder and use sessions somehow. I have googled sessions and I still don't quite get it. Can someone please explain sessions from scratch?
    if you are password protecting file-by-file, yes (and therefore, yes, it would only protect PHP pages). The simplest solution to this would be to have all of your password-protected PHP pages in one (non-htpasswd) folder, and all your other restricted files in a different folder.
    Quote Originally Posted by kuau View Post
    2. Are sessions necessary for login scripts? They seem to be for logging users out after a set length of time, or remembering info from their last session. Can you control what values are stored in the session info? Are cookies files that store the session info?
    strictly speaking, they're not necessary - though it would be inconvenient and counter-productive to avoid using them.

    -- cookies store the session id on the user's computer.
    -- php gets the cookie and finds the matching session info (actually stored in a tmp file).
    -- session info is read/writable via the $_SESSION superglobal (once you start the session, of course).

    keeping session info means that you can keep track of what the user is doing (for example, his name, his permissions, what steps of a process he's already completed, etc.).

    Quote Originally Posted by kuau View Post
    3. I understand == but what does === mean?
    == means "equivalent," whereas === means "(exactly) equal."

    for example:
    PHP Code:
    <?php
    === 1
    // true (both integers)

    == '1'
    // true (one integer, one string)

    === '1'
    // false (equivalent value, but different data types)

    // this is most useful in the context of certain return values:

    //  executing some query  //
    //  checking # of rows returned //
    if( !$result ){ print "there was an error!"; }

    // in fact, there may have been no error, just zero rows. observe:

    == FALSE
    == NULL
    == ''   // (empty string)
    == '0' // ("0" as a string)
    //  all "true."  in fact,
    == "false" //  ("false" as a string)
    // and so on.

    // realistically, "===" should be used in almost all cases.
    // "==" is usually just laziness, oversimjplification, and/or ignorance :)
    Quote Originally Posted by kuau View Post
    4. Is this a good function to use to prevent SQL injection?
    the best option is to make sure magic_quotes_gpc is TURNED OFF in your php configuration

    you should still have a function like this, as a backup in case you can't affect the server configuration. it's easier to do it all at once, at the very beginning of the script. I'll find the code I use and post it later.

    Quote Originally Posted by kuau View Post
    ...and what does it accomplish security-wise? Do people use slashes in SQL injection?
    the slash is an escape character: it marks the following character as "literal" where it might have a special meaning otherwise. the most common case is a quote, which a hacker can use to end one SQL statement and begin another.

    Quote Originally Posted by kuau View Post
    6. Does this remove blanks at each end of a string? Anything else?
    $str = @trim($str);
    read here for the characters it removes. you can also specify other characters to remove by using the optional second parameter.

    Quote Originally Posted by kuau View Post
    7. Is it necessary to md5 encrypt the passwords in the database? If encrypted, how do you send people forgotten passwords? If they are decryptable, couldn't anyone do it? So what is the point?
    it is very beneficial to encrypt passwords, since it makes it impossible to accidentally disclose someone's password -even if your database is compromised.

    you don't send people their forgotten passwords. you send them a new, temporary password, so they can choose a new one themselves.

    hashing functions like md5, sha1, etc., are not "decryptable," no.

  3. The Following User Says Thank You to traq For This Useful Post:

    kuau (01-18-2012)

  4. #3
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    I agree with everything traq said. Just a few things to add:

    1. Sessions are incredibly easy to use (once you understand them), and they're very helpful. First, include the following at the beginning of every page before any output of any kind, including even a blank line:
    PHP Code:
    <?php //first line of your file, before any output
    session_start();
    /*......*/ ?>
    Now you can use $_SESSION whenever and wherever you want. $_SESSION['myvar'], for example.
    Session information is available for a single user during a single session. It is stored on the server, NOT in cookies, and it is completely secure. You could put your server admin password into $_SESSION and the user could never see it (don't do that, though!), unless you chose to show them. It's a way to track ongoing information for a single user. It's not reliable as a way to permanently store it, because it expires with the session. Sessions last somewhere between 15 minutes and forever, depending on the configuration.
    Sessions use a cookie to link the session to the user, and otherwise they don't use cookies. So the session ID is stored in a cookie, the server figures out which session to use, and that's all.
    The only problem there is that by stealing the session ID cookie, a session can be hijacked. But that's not very common and would require taking the file from the user's computer.
    A nice trick with that is to use the current IP address to make sure that the session isn't hijacked (as an entry in the $_SESSION array). That's a tradeoff, though, since mobile devices or laptops might move IPs, but it's certainly very secure. Just check to be sure that stored session IP value still matches $_SERVER['REMOTE_ADDR'] for each page load, and it's the same connection.

    2. Sessions aren't necessary, but they're useful. I really like them. There are plenty of systems that use cookies only, but they don't have a good way to store information from page to page for users, and they can be less secure (if designed badly). I'm still surprised at how many login systems don't use sessions, mostly because they are so easy.

    3. It's useful to use both == and === because they do different things. Personally I use == unless I have a very specific reason to use ===. If you want to distinguish between false and 0, then use === (and a few other similar cases). If not, then you probably would want to use just == in case your number might be sent as a string, or anything like that. Most of the time it won't matter anyway, but it can be important sometimes.

    6. Basically, yes, just whitespace.

    7. Hashing and encryption are different. Hashing algorithms are strictly one-way so they aren't "encryption" and can't be "decrypted". It's a very simple (but powerful) principle: one-way hashing means that by following the same algorithm, you can check if two inputs are equivalent. So when they first set the password, you store the hashed password. Then next time you need to check their password, you take their submitted (raw) password, convert it using md5(), then see if it matches the stored md5() value. If it's the same, then it was the same input. If it's not the same, then it wasn't the same input. There's no way to decrypt it, so it's not hackable. In fact, some systems (although these aren't the most secure) actually store the hashed password in a cookie. (I'm not recommending that, just explaining how truly "secure" a hashed value is, assuming that the hashed value itself can't give access to the system on its own. That's the one weakness of a hashing system, but easy to avoid if you always require re-hashing before comparing.)
    A couple notes:
    1. The only weakness of hashing is that they're consistent and widely used, so there actually are some database projects out there that match up inputs and outputs, so in that sense they can be decrypted, but only by long term brute force. For that reason, it's a good idea to use a newer algorithm. md5() is very popular, but sha1() is a little newer and probably a better idea. It's no harder to use, and just generates a longer string (I think 40 chars instead of 32.)
    2. Technically, it's possible for two passwords to have the same hashed value. It's incredibly unlikely, but this also helps for security: because it's not "1 to 1", you truly can't figure out what the password is, at least not definitively.
    3. You can use "salt" to make it more secure. Instead of md5($pass), you can use md5($username.$pass), among other things.
    Daniel - Freelance Web Design | <?php?> | <html>| español | Deutsch | italiano | português | català | un peu de français | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  5. The Following User Says Thank You to djr33 For This Useful Post:

    kuau (01-19-2012)

  6. #4
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    slightly tangential (not-quite-off-topic):

    md5's main weakness is that it's been around a while - as Daniel says, there are databases ("rainbow tables") of known input-output combinations (sha1 will eventually have a similar weakness). That's why he recommends using a "salt": an additional value prepended/appended to the actual password.

    Beyond "salting," there is extending: instead of hashing the value once, do it multiple times. For example, this:
    PHP Code:
    $hash md5md5md5$salt.$password ) ) ); 
    is exponentially more secure than just hashing once.

    you could even do something like
    PHP Code:
    $hash md5$garlicsalt.md5$seasalt.md5$rocksalt.md5$salt.$password ) ) ) ); 
    ...of course, this sort of extreme measure is completely unnecessary in almost any code you or I are likely to write, but it's good to know.

    (just don't forget how you did it)

    also, some people might ask, "only 32 characters??? SOME values will have duplicate results!!!"

    While logically true, no one has found duplicate values yet. And believe me, they're looking - everyone wants to the status of being The First.

    But in the meantime, I look at it this way:
    Quote Originally Posted by http://progit.org/book/ch6-1.html#a_short_note_about_sha1

    ...A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night.

  7. The Following User Says Thank You to traq For This Useful Post:

    kuau (01-20-2012)

  8. #5
    Join Date
    Sep 2007
    Location
    Maui
    Posts
    628
    Thanks
    277
    Thanked 14 Times in 14 Posts

    Default

    I literally had this window open for 2 days writing a response and then when I submitted it, it told me I had to reload the page and saw all these subsequent entries, but I have to go running right now so I'll just submit what I had for now. Just ignore if you have since answered these questions...

    Dear Adrian & Daniel: Thanks very much for all the answers.

    The simplest solution to this would be to have all of your password-protected PHP pages in one (non-htpasswd) folder, and all your other restricted files in a different folder.
    To me this implies that by having all the private files in one folder, I can protect the whole folder. I don't know how to do that except with htaccess (?). Maybe I am not understanding what you mean.

    Did you find the code you use to clean user input? I would really appreciate having something an expert considers good protection against SQL injection because I'm not sure what the bad guys can do so am not sure how to protect against it. Thanks.

    OK, now I understand about encrypting passwords. Figures... right after I perfected my script to send the forgotten password! I did find a script for generating random passcodes.

    I remember you said this...
    It might be best to make it so you can log in using $_GET, so you could just create a hyperlink in the email and the user can log in to edit with one click; something like http://example.com/edit.php?email=us...f01276af9ce88e
    I'm just not sure how to implement it. How do I log them in to change their password? Do I replace their password first with the generated one and then use it to log them in using GET? I feel as if I may be reinventing the wheel here. Are there some examples online of this process? I found this one but apparently it is not secure enough based on the comments...

    http://www.danbriant.com/general/cre...-reset-script/

    As for magic quotes, if I turn it off in php.ini, I know it then causes problems if there are apostrophes in the text. Is addslashes($str) sufficient to do what magic quotes would have done, and if so, isn't that just as insecure as magic quotes?

    If you start a session, how do you know what values it is tracking and how do you access them?

    Thanks, e

  9. #6
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    To me this implies that by having all the private files in one folder, I can protect the whole folder. I don't know how to do that except with htaccess (?). Maybe I am not understanding what you mean.
    Yes, use .htaccess to protect the files you don't want accessed. Use PHP just in PHP files to control access-- of course you don't want to actually block access entirely to PHP, so you'll have a password or user system or whatever. That's not really the same as .htaccess.
    Actually, unless there's a reason you want to download your protected (non-PHP) files, I'd recommend against a password-- just block the folder entirely. You won't be able to access it either (except by FTP of course) and it will be completely safe. If they're blocked, I assume that means you're not using them except for server internal reasons. Note that PHP can still access them if you write that into the code. For example, you can have a "hidden/" directory containing "security.php" and include() the security.php file into other PHP files, even though via HTTP it would be blocked.


    For MySQL injection, the single function mysql_real_escape_string() does everything you need. The only other issue is the outdated and troublesome magic_quotes situation. Just turn it off on your server and you don't need to worry about it. If it is on, you need to escape it, and I believe what you posted is fine. When traq posts his code, maybe that will be better (I'm not yet sure how), but for now I think what you have is ok, but not needed unless magic_quotes is on. On the other hand, if you want to write code that can be portable (installed easily on any server) then checking for that, even if it is off on your server, wouldn't hurt. But that's not important unless you're distributing your scripts to others (or using them for multiple clients and/or on multiple personal servers).


    You should be able to find plenty of resources about "forgotten password scripts" if you search for that. In short, you will give them a code by email. When they get this code they can either click the URL directly (which includes the code) or type in the code in a form on your site. You can decide whether they need to have the username and/or email as well-- that's not technically required. This is a secondary login system and you will simply tell your server to let them bypass the normal system if they have this code. The way that I do it is by creating a new database table of forgotten password codes with two columns: a username/id and a code. Then when that code is entered, they get immediate access to change the password of that account. So of course you need the passwords to be difficult to guess (at least 8 characters and all that stuff). You might also want an expiration time so that a hacker doesn't get a year to guess what might have been sent to the email (that they can't see because they're not the user).


    Magic_quotes is bad. You don't want to replace its behavior if you turn it off-- you want to get rid of it completely. You don't need to add slashes or do anything. Now, in some cases, magic_quotes is useful, but not in all cases. The problem is that it is inconsistent. So, if you turn it off then do everything yourself, it will be consistent and you never need to
    Last edited by djr33; 01-19-2012 at 07:35 PM.
    Daniel - Freelance Web Design | <?php?> | <html>| español | Deutsch | italiano | português | català | un peu de français | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  10. The Following User Says Thank You to djr33 For This Useful Post:

    kuau (01-20-2012)

  11. #7
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    This is broken into a second post because the system wouldn't accept it as one. Not sure why, but maybe it was too long.
    -------


    Again, sessions are easy. There are two very simple steps:
    1. Include the code to start a session at the top of every page.
    2. Use $_SESSION['variable'] to access the session variable named "variable". Repeat.

    It is tracking whatever values you've put it in. If you want to see what values it contains (for debugging/testing, not for public release) then use print_r($_SESSION); to see the entire array.
    $_SESSION is an array just like anything else. It's a superglobal so you don't need to worry about scope (that is, you can use it inside functions or wherever and it's always the same and available). It's like $_GET and $_POST, except that you often write to it rather than just retrieving information from it. (You can put information into $_GET and $_POST too, but it's not often very useful.)

    Anyway, here's an example:
    PHP Code:
    <?php
    session_start
    (); //session is active;
    //this is the same session as any other pages visited recently
    //you can't have multiple sessions or overlapping sessions
    //sessions are either on or off and if there's too long a gap, then they reset

    $_SESSION['variable'] = "value"//store something
    echo $_SESSION['variable']; //echo "value";

    //now this works just like any other variable/array
    //the only special part is that the same information is available on new pages
    ?>

    <?php //imagine this is now a new page, 2.php, loaded 2 minutes later:
    session_start();

    echo 
    $_SESSION['variable']; //magically, you get "value" again from that other page
    ?>
    So again, sessions are incredibly easy-- in fact, they're probably the easiest thing in PHP in my opinion. Then again, once in a while you need to change the session length in the cookie or fix subdomain problems, but aside from configuring them overall, they really are easy to use.
    But of course they appear confusing at first because they are counter-intuitive to the way that PHP usually works. Don't worry if you're confused-- just try them out and they'll make sense very quickly.
    (In how they actually work, sessions are incredibly complicated, involving a temporary database on the server and other stuff. But PHP deals with all of that for you and you don't need to do anything at all.)

    The one other thing you might want to do some time is destroy a session. This is often used to log users out or restart a process (a site-wide process, not just something on one page).
    PHP Code:
    <?php
    session_destroy
    (); //no more session; all of the variables are gone
    //and you will need to start a new session if you want one
    ?>
    Daniel - Freelance Web Design | <?php?> | <html>| español | Deutsch | italiano | português | català | un peu de français | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  12. The Following 2 Users Say Thank You to djr33 For This Useful Post:

    kuau (01-20-2012),TwitterRooms (01-20-2012)

  13. #8
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    Quote Originally Posted by kuau View Post
    To me this implies that by having all the private files in one folder, I can protect the whole folder. I don't know how to do that except with htaccess (?). Maybe I am not understanding what you mean.
    what Daniel said.
    Quote Originally Posted by kuau View Post
    Did you find the code you use to clean user input? I would really appreciate having something an expert considers good protection against SQL injection because I'm not sure what the bad guys can do so am not sure how to protect against it. Thanks.
    [...]
    As for magic quotes, if I turn it off in php.ini, I know it then causes problems if there are apostrophes in the text. Is addslashes($str) sufficient to do what magic quotes would have done, and if so, isn't that just as insecure as magic quotes?
    Quote Originally Posted by djr33 View Post
    For MySQL injection, the single function mysql_real_escape_string() does everything you need.
    [...]
    On the other hand, if you want to write code that can be portable (installed easily on any server) then checking for that, even if it is off on your server, wouldn't hurt. But that's not important unless you're distributing your scripts to others (or using them for multiple clients and/or on multiple personal servers).
    [...]
    Magic_quotes is bad. You don't want to replace its behavior if you turn it off-- you want to get rid of it completely. You don't need to add slashes or do anything. Now, in some cases, magic_quotes is useful, but not in all cases. The problem is that it is inconsistent. So, if you turn it off then do everything yourself, it will be consistent and you never need to
    That is the situation (portability) that I was referring to; but it beneficial even if you don't even plan to share your code: do it once and forget about it.

    to recap:
    1. You want to completely get rid of magic_quotes_gpc.
    2. You can't effectively do that from inside your php script - only via server configuration.
    3. You might not have access to your php.ini, and/or you might forget about it at some point.

    This takes care of that for you: counteracts the affects of magic_quotes_gpc if it's turned on; does absolutely nothing if it's turned off.
    PHP Code:
    // if get_magic_quotes_gpc is set in your config, kill it!  KILL IT!

    // (using ini_set('magic_quotes_runtime', 0); is useless:
    //   the evil slashing has already happened, 
    //   and the setting is restored to its default next time a script runs.)
    if(get_magic_quotes_gpc()){
        
    // make strip_slashes() recursive, so it affects _all_ values in the GPC arrays
        
    function stripslashes_recursive$v ){ 
            return 
    is_array$v )? 
                
    array_map'stripslashes_recursive',$v ): 
                
    stripslashes$v ); 
        }
        
    //  if you didn't know, GPC stands for GetPostCookie,
        //    so those are the superglobals you need to "fix":
        
    $_GET stripslashes_recursive$_GET );
        
    $_POST stripslashes_recursive$_POST );
        
    $_COOKIE stripslashes_recursive$_COOKIE );
    }
    //  I also do this 
    //  ( $_REQUEST is unrelated to our magic_quotes problem, but evil nonetheless )
    $_REQUEST NULL
    this solves your Magic Quotes problem, which un-complicates (does not solve) your SQL injection issues.

    You must still use mysql_real_escape_string() (or switch to mysqli or PDO and use prepared statements ) to sanitize your user inputs - this is not intended to replace the need for that.

    Edit:

    As for your question about "using $_GET" with your "forgot password" script:

    when a user says they forgot their password, you might do something like this:

    1. create a temporary password (something random and hard-to-guess)
    2. store the temp password in a special table in your DB, along with the username and email it belongs to, and the time it was created
    3. send the temp password to the user's email - BUT, instead of saying "here's your temp password," give them a link like this:
    PHP Code:
    '<a href="http://example.com/lostpass.php?email='.$user_email.'&passonce='.$temp_password.'">click here to recover your password</a> 
    4. when they click on the link, you can check the user email against the temp password (and how long ago the password was created; it's good to make these expire within a day at most).

    This way, recovering their password is as convenient as possible: just click the link and follow directions.
    You might also give them the temp_password, so they can enter it manually, in case they have an objection to clicking on links in emails (if they just requested a new password, they ought to trust you; but it is a good security habit).

    IF the temp password is valid:
    1. log the user in (only for the session).
    2. redirect them to the "change your password" page and tell them to change their password (good idea to make this _required_).
    3. delete the temp password so it can not be used again.

    REALISTICALLY, even though the reset-pass-via-email approach is widely used (even by google and amazon, among others), the concept is not fool-proof. It relies on two things that you can't be sure of:

    1. the user's _current_ email address is in your records.
    2. the user's email account has not been compromised.

    However, this is all beyond your control, and responsibility for both issues rests squarely with the user.

    Last edited by traq; 01-20-2012 at 12:39 AM.

  14. The Following User Says Thank You to traq For This Useful Post:

    kuau (01-20-2012)

  15. #9
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    Traq, do you have any reasonable alternatives? Sure, the email account might be hacked and/or old, but is there any other way? Google now tries to use a mobile phone number for this as well, but that is similarly limited (what if you lose your phone or it is stolen?).

    One more option is to include a "contact us" link near the forgotten password form to deal with weird situations. Assuming you can trust someone who claims they can't access their account, you can always help them manually.
    Daniel - Freelance Web Design | <?php?> | <html>| español | Deutsch | italiano | português | català | un peu de français | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  16. #10
    Join Date
    Apr 2008
    Location
    So.Cal
    Posts
    3,643
    Thanks
    63
    Thanked 516 Times in 502 Posts
    Blog Entries
    5

    Default

    Alternatives? Not really. The 'contact us' link is good, but you need to be careful - tricking a human into believing you are who you say you are -can- be easier than hacking the email account. It's been done.

    About mobile phone numbers, etc., yes, it can provide a fallback method for verifying Id, but at the end of the day it's really just another point of failure.

    There's no easy solution without sacrificing user-friendliness (which we're obviously not trying to do).

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •