#1
  1. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Sep 2006
    Posts
    2,037
    Rep Power
    535

    Checklist for making a secure site


    I am trying to come up with a list of security good practices which I could go through and confirm whether I am doing them. Below is my current list. Obviously, I cannot confirm that I am doing things that I don't know need to be confirmed. Anything that should be added, modified, or removed? Thank you
    1. Never include() a file which might be suspect.
    2. Be very careful with eval().
    3. Turn register_globals and magic quotes off.
    4. Make sure Apache, PHP, MySQL, Linux, firewalls, etc are set up correctly.
    5. Prevent SQL Injection. Escape all user inputs.
    6. Prevent shell injection by escaping user inputs to shell commands by using escapeshellarg() and escapeshellcmd().
    7. Prevent XCC. Escape all content which was provided by the user and is to be displayed on the page (unless it was cleaned prior to saving in the DB which I typically do not do). Should htmlspecialchars() be used for all, or should JavaScript use jsonencode() or something else? What about when used to populate an input value?
    8. Don’t display internal error messages.
    9. Use PHPass (or something similarly robust) to hash passwords before storing in DB
    10. Prevent Cross-site request forgery. Have some other random number sent from the client to the server to verify that it is correct.
    11. Don’t use weak random numbers for critical procedures such as resetting passwords.
    12. Limit files which can be publically accessed on a needed basis. Either put under the root or check a constant as being defined to continue.
    13. Encode all content using UTF-8 (be consistant!). Also, use the same encoding on the database and any text files.
    14. Use HTTPS where applicable.
    15. Require user to re-enter their password when changing their password or email address.
    16. Apply proper Linux permissions to files and directories
    17. Apply proper MySQL permissions to tables.
    18. Use strong passwords for MySQL, etc.
    19. Don’t access the server from a public location like Starbucks?
    20. Lockout login if repeatedly enter incorrect password.
    21. Update all scripts/applications/plugins to the newest version available (after of course I thoroughly understand them which will never happen)
    22. Create audit trails for any critical database actives.
    23. Whenever some high suspect activity is performed, log the event along with as much info as possible (i.e. IP, user ID, etc) and output message to investigate.
    24. Maybe also log whenever a non-logged on user either unsuccessfully attempts to log on or to reset their password, but don't sent out a warning.
    25. Maybe also when a user is logged in, store in a DB each time they access the site for the given session. When user logs on, store a record with the users_id, IP Address, etc. Then future time the site is accessed, store $_SERVER[‘SCRIPT_NAME’], json_encode of $_GET, $_POST, and $_COOKIE, or anything else which will archive what the user was doing.
  2. #2
  3. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Hi,

    I pretty much agree with this list. I think a lot of this boils down to some simple rules:

    • Give everybody and every program only the necessary privileges and information. This includes file permissions and database privileges as well as error messages.
    • Be very careful when putting data into an "executable" context like a query, an HTML document or a shell command, especially if it's user input. Always use the proper escaping technique (or prepared statements in the case of queries).
    • Use established and up-to-date algorithms, procedures and libraries. Don't invent your own stuff. Even more important: Know your limits! Don't fumble with things you don't fully understand (like crypto algorithms).

    Based on those rules, there's of course all kinds of different techniques to fight the different risks. The OWASP cheat sheets are an excellent resource for the concrete implementation. Not everybody agrees on every detail, but it's a very good start.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Sep 2006
    Posts
    2,037
    Rep Power
    535
    Thank you Jacques1, I like how you sum them up as a few key basic principles.

    I think your first principle also includes limiting what files users have access to (i.e. keep it below the root or using some other strategy to prevent public access).

    Maybe the following belong in one of them, or maybe they need their own heading.
    • Encode consistency (i.e. UTF-8)
    • Reduce time frame for critical activities such as changing passwords.
    • Log inconsistencies and alarm if required
    • Be smart and don't share your passwords or use weak encryption
    • Encrypt (HTTPS) where appropriate
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Loyal (3000 - 3499 posts)

    Join Date
    Dec 2004
    Posts
    3,016
    Rep Power
    376
    thanks Notion, I think that list should be like a "checkpoint" for all beginners until they get the hang of it.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Sep 2006
    Posts
    2,037
    Rep Power
    535
    7. Prevent XCC. Escape all content which was provided by the user and is to be displayed on the page (unless it was cleaned prior to saving in the DB which I typically do not do). Should htmlspecialchars() be used for all, or should JavaScript use jsonencode() or something else? What about when used to populate an input value?
    Hoping to get some clarification on this one. It is my understanding that the following should be done for the following situations:

    • echo('<p>'.htmlspecialchar($_GET['badness']).'</p>'); to make user provided text safe to put on the page.
    • echo('<input value="'.htmlspecialchar($_GET['badness']).'" name="hello">'); to make user provided text safe to add as an attribute (such as the value of an input element).
    • Use htmlpurifier (or something similar) to make user provided HTML safe to add as page.
    • echo('<script> var myVar='.json_encode($_GET['badness']).';</script>'; to make user provided text to include in JavaScript (why shouldn't I use htmlspecialchar() instead?)
    • Use CDATA if user provided text is used in JavaScript (why is this different that the previous item?)
    • $.post('myDBQuery.php',function(badness) {$('#myID').text(badness);}); No need to escape the data returned from the server either client or server side?
    • Any other situations which I haven't included?
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Loyal (3000 - 3499 posts)

    Join Date
    Dec 2004
    Posts
    3,016
    Rep Power
    376
    i think if you are displaying data from the database which has previously been inputted by the user, you should still run the htmlspecialchar on it.
  12. #7
  13. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Originally Posted by NotionCommotion
    • echo('<p>'.htmlspecialchar($_GET['badness']).'</p>'); to make user provided text safe to put on the page.
    • echo('<input value="'.htmlspecialchar($_GET['badness']).'" name="hello">'); to make user provided text safe to add as an attribute (such as the value of an input element).
    htmlspecialchars() is the correct function. But you have to always specify the ENT_QUOTES flag and the character encoding when using htmlspecialchars(). If you don't, it will only escape double quotes while leaving single quotes untouched. And it will use some default encoding, which may or may not be correct.

    So you want something like this:
    PHP Code:
    htmlspecialchars($rawENT_QUOTES ENT_XHTML'UTF-8'); 
    It's also important to actually quote the attributes. Otherwise it's easy to break out of them without any special characters. A simple space is enough.



    Originally Posted by NotionCommotion
    • Use htmlpurifier (or something similar) to make user provided HTML safe to add as page.
    I wouldn't let the vistors use any HTML at all. Instead, give them a simple meta-language like BBCode with very limited functionalities.



    Originally Posted by NotionCommotion
    • echo('<script> var myVar='.json_encode($_GET['badness']).';</script>'; to make user provided text to include in JavaScript (why shouldn't I use htmlspecialchar() instead?)
    Using htmlspecialchar() in a JavaScript context is simply wrong. Double quotes and "<" and ">" have no special purpose in a script context. An attacker doesn't need them at all. And encoding them as HTML entities doesn't even work in a CDATA section (which all script contents are).

    Securing JavaScript content is very different from normal HTML escaping and requires a completely different approach. Actually, the json_encode() I suggested turns out not to be enough, because attackers can break out of the script container by simply writing a </script> in any JavaScript string. The OWASP suggests encoding all non-alphanumeric characters with the \xHH or \uHHHH representation and then putting the whole thing in a JavaScript string. This way an attacker can neither inject JavaScript code nor trick the HTML interpreter into closing the script container.



    Originally Posted by NotionCommotion
    • Use CDATA if user provided text is used in JavaScript (why is this different that the previous item?)
    Not sure why you mean by this. An explicit <![CDATA[]]> section? That's a good idea for clean JavaScript in XHTML, but it doesn't help security, because attackers can break out of the CDATA section with a simple ]]>. Use the OWASP approach above.



    Originally Posted by NotionCommotion
    • $.post('myDBQuery.php',function(badness) {$('#myID').text(badness);}); No need to escape the data returned from the server either client or server side?
    The text() method already takes care of the escaping.



    Originally Posted by NotionCommotion
    • Any other situations which I haven't included?
    It's very important to consider the exact context. For example, putting user input directly into a script context (not wrapped in a JavaScript string) is never safe, no matter what you do. Putting it into the eval() function (or one of its sisters) is never safe. And putting user input into an unquoted attribute is also (almost) never safe.

    So be very, very careful whenever input goes into an attribute or a script container. If possible, avoid it completely.
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Sep 2006
    Posts
    2,037
    Rep Power
    535
    Thanks Jacques1, great information.

    The text() method already takes care of the escaping.
    I take it the same is true for html()? Normally, I think "do it server side", but I suppose you are protecting the user that is viewing the page, it is okay either way.

    25. Maybe also when a user is logged in, store in a DB each time they access the site for the given session. When user logs on, store a record with the users_id, IP Address, etc. Then future time the site is accessed, store $_SERVER[‘SCRIPT_NAME’], json_encode of $_GET, $_POST, and $_COOKIE, or anything else which will archive what the user was doing.
    Also, do you think taking the above step is worthwhile? My thought was it would create a poor mans audit trail where the actual steps of the user could be traced back.
  16. #9
  17. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Originally Posted by NotionCommotion
    I take it the same is true for html()?
    No. As the name already suggests, this method is for inserting HTML, so it doesn't do any escaping. If you insert '<div>', you actually get a div element.



    Originally Posted by NotionCommotion
    Normally, I think "do it server side", but I suppose you are protecting the user that is viewing the page, it is okay either way.
    Personally, I think escaping should be done right before you insert the string. Relying on "pre-escaped" strings is risky, because you never know if the escaping has actually been done (maybe there was an error, maybe the logic is flawed). There's also the risk of double-escaping.

    So it's usually best to do the escaping ad hoc. If a JavaScript method inserts the string, then JavaScript should also take care of the escaping.



    Originally Posted by NotionCommotion
    Originally Posted by NotionCommotion
    25. Maybe also when a user is logged in, store in a DB each time they access the site for the given session. When user logs on, store a record with the users_id, IP Address, etc. Then future time the site is accessed, store $_SERVER[‘SCRIPT_NAME’], json_encode of $_GET, $_POST, and $_COOKIE, or anything else which will archive what the user was doing.
    Also, do you think taking the above step is worthwhile? My thought was it would create a poor mans audit trail where the actual steps of the user could be traced back.
    I see no reason to do this -- except maybe for high security application. I also find it rather problematic with regard to privacy.

    It does make sense to log the IP address and the timestamp for critical actions like a login, a password reset, a change of the user credentials etc. But what do you gain from logging every single action?
    The 6 worst sins of securityHow to (properly) access a MySQL database with PHP

    Why can’t I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Sep 2006
    Posts
    2,037
    Rep Power
    535
    No. As the name already suggests, this method is for inserting HTML, so it doesn't do any escaping. If you insert '<div>', you actually get a div element.
    What I meant is if "badness" included dangerous content, the following could be used without doing any other escaping such as htmlspecialchar($badness) serverside.
    Code:
    $.post('myDBQuery.php',function(badness) {$('#myID').html(badness);});
    I see no reason to do this -- except maybe for high security application. I also find it rather problematic with regard to privacy..... But what do you gain from logging every single action?
    Someone says "I did not perform those actions." I could go back and re-create the scenario. Any sensitive data (such as a password) would need to be scrubbed out before saving the $_POST.

IMN logo majestic logo threadwatch logo seochat tools logo