Thread: Security.

    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    10
    Rep Power
    0

    Security.


    I remember I once ran into a website that listed all commonly made security mistakes by webdevopers.

    This included mistakes made when coding in HTML, CSS and PHP and practices that lead to security risks.

    My problem is that I forgot to bookmark that website. I think it was a .gov or .edu website but I am not sure no more.

    Does anyone know what website I am reffering to or knows of anything simular?
  2. #2
  3. --
    Devshed Expert (3500 - 3999 posts)

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

    the OWASP is a great resource for web security. The OWASP Top Ten lists the most common security problems.

    Comments on this post

    • Storm2012 agrees : Thank you for your help.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    10
    Rep Power
    0
    Originally Posted by Jacques1
    Hi,

    the OWASP is a great resource for web security. The OWASP Top Ten lists the most common security problems.
    I am familiar with the OWASP and like their website and work.

    However the OWASP does not describe all mistakes made in web development.

    I just hate it when I do not bookmark certein websites thinking I will find them again with a google search....
  6. #4
  7. I <3 ASCII
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Aug 2003
    Posts
    2,400
    Rep Power
    1233
    Owasp is new to me. I was aware of (though had to re-google) sans.org's list of most dangerous programming exploits:

    http://www.sans.org/top25-software-errors/

    I like this list because once an exploit has been identified it gets numbered and it's always that nubmer: (so sql injection is always CWE 89). It also boils down to related CAPEC's (Common Attack Pattern Enumeration and Classification) that list more specific examples of different attack parameters.

    It can be dry reading but they're rather in depth.

    -MBirchmeier
  8. #5
  9. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,317
    Rep Power
    7170
    The golden rule of security: never trust user input

    Literally virtually all software exploits are a result of input validation or sanitization failure.

    There is a security notes thread in the FAQ section. It is old, but mostly still relevant. Don't read past the first post as most of the comments in it are garbage. I am in the process of rewriting it but have not finished yet and will probably not be finished for several months.

    However, here is what I've completed so far on the rewrite. Obviously there are various formatting errors and incomplete sections and probably a few errors, but the information is still solid:



    This thread is a consolidated, reorganized, updated and expanded version of the previous security notes thread originally written by JeffCT in 2001.

    The purpose of this article is to document the most common security-related coding mistakes made by PHP programmers. Following these security practices will eliminate the vast majority of security problems with your PHP code. Many of these security holes have been found in widely-used open source and commercial PHP scripts in the past. Most PHP scripts are compromised because the script does not validate or sanitize user input; user-supplied input must never be trusted in any circumstances.

    This thread is not to be used for general discussion. If you have a question or comment on PHP security please create a new thread. You may reply to this thread, however all replies will either be split into separate topics or deleted once addressed (for example, if the reply points out a mistake in the original thread). Separate threads which explore certain aspects of PHP security in more depth may be referenced at the end of this article.

    One final word of warning: this thread contains some code examples that are intentionally insecure; do not copy and paste code these examples out of this thread!

    Section 1: Validate, sanitize and never trust user-supplied data

    Chapter 1.1: Protect against SQL injection

    For an in-depth explanation of SQL injection, please consult the Wikipedia article on it: SQL Injection. In a nutshell, a SQL injection exploit exists whenever you use user-supplied data as part of a SQL query without sanitizing it.

    For example, the following is a very common example of code that is vulnerable to a SQL injection attack:
    PHP Code:
    $result mysql_query("SELECT * FROM users WHERE username = '" $_POST['username'] . "' AND password = '" $_POST['password'] . "'");
    if(
    mysql_num_rows($result) > 0) {
       
    // User login successful

    The SQL injection vulnerability in this code would allow me to authenticate as any user without needing to know their password. For a non-malicious user, the SQL query executed against the database would look something like:
    Code:
    SELECT * FROM users WHERE username = 'user1' AND password = 'pass1'
    However, a malicious user could enter their username as admin and their password as:
    Code:
    ' OR username = 'admin
    And the resulting query that gets executed becomes:
    Code:
    SELECT * FROM users WHERE username = 'admin' AND password = '' OR username = 'admin'
    When this query is executed, the row for the admin user will be returned even though the password is wrong, and the user will have successfully logged in as the admin user without needing to know the admin password.

    Protecting against SQL injection is very simple, but differs depending on which database library you use.

    For the deprecated mysql library, use mysql_real_escape_string
    PHP Code:
    $result mysql_query("SELECT * FROM users WHERE username = '" mysql_real_escape_string($_POST['username']) . "' AND password = '" mysql_real_escape_string($_POST['password']) . "'");
    if(
    mysql_num_rows($result) > 0) {
       
    // User login successful

    For the mysqli procedural library, use mysqli_real_escape_string
    PHP Code:
    $result mysqli_query("SELECT * FROM users WHERE username = '" mysqli_real_escape_string($_POST['username']) . "' AND password = '" mysqli_real_escape_string($_POST['password']) . "'");
    if(
    mysqli_num_rows($result) > 0) {
       
    // User login successful

    For the mysqli object oriented library, use real_escape_string
    PHP Code:
    $result $mysqli->query("SELECT * FROM users WHERE username = '" $mysqli->real_escape_string($_POST['username']) . "' AND password = '" $mysqli->real_escape_string($_POST['password']) . "'");
    if(
    $result->num_rows 0) {
       
    // User login successful

    For the PDO library, use quote
    PHP Code:
    $result $pdo->query("SELECT * FROM users WHERE username = '" $pdo->quote($_POST['username']) . "' AND password = '" $pdo->quote($_POST['password']) . "'");
    if(
    $result->rowCount() > 0) {
       
    // User login successful

    For mysqli and PDO, it is also possible to use prepared statements to protect against SQL injection:
    PHP Code:
    $st $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
    $result $st->execute(array(':username' => $_POST['username'], ':password' => $_POST['password']));
    if(
    $result->rowCount() > 0) {
       
    // User login successful


    Special care must be taken when using user-supplied numeric parameters. For example, consider the following:
    PHP Code:
    $result mysql_query("SELECT * FROM users WHERE username != 'admin' AND id = " mysql_real_escape_string($_POST['userid'])); 
    This code is not supposed to allow the admin user to be retrieved, however, despite the user of mysql_real_escape_string, this code is still vulnerable to SQL injection. For example, consider passing the following value in userid
    Code:
    1 OR id = 1
    The resulting query is:
    Code:
    SELECT * FROM users WHERE username != 'admin' AND id = 1 OR id = 1
    When this query is run, user ID 1 will be selected even if that user is the admin user.

    To properly handle integer parameters you must do one of the following:
    * Enclose the value in quotation marks in the query even though it is numeric
    * Cast the value to an integer instead of using an escape/quote function
    * Validate that the parameter is numeric and do not run the query if it is not
    * Use prepared statements (for mysqli or PDO)

    Chapter 1.2 - Protect against XSS attacks

    For an in-depth explanation of XSS attacks, please consult the Wikipedia article on it: Cross-site scripting. In a nutshell, an XSS exploit exists whenever you use user-supplied data as part of the output you send back to the user. XSS vulnerabilities frequently allow attackers to execute arbitrary JavaScript code on your page, which enables them to hijack your users' sessions and redirect them to malicious pages.

    The following is a very common example of code that is vulernable to an XSS vulnerability:
    PHP Code:
    <?php ?>
    <input type="text" name="username" value="<?php echo $_GET['username']; ?>" />
    An attacker could link an innocent user to this page with the username parameter set to:
    Code:
    " onclick="window.location='http://malicioussite.com/'
    And the resulting HTML that is sent to the innocent user becomes:
    Code:
    <input type="text" name="username" value="" onclick="window.location='http://malicioussite.com/'" />
    As soon as the user clicks on the form field, they will e redirected to the malicious site controlled by the attacker.

    To protect against XSS attacks, any output used in HTML must be cleaned using a function like htmlentities:
    PHP Code:
    <?php ?>
    <input type="text" name="username" value="<?php echo htmlentities($_GET['username'], ENT_QUOTES'UTF-8'); ?>" />
    Another very common security flaw is the use of $_SERVER['PHP_SELF'] as the action attribute value of a <form> tag. For example:
    PHP Code:
    <?php ?>
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>">
    htmlentities is also used to fix this vulnerability:
    PHP Code:
    <?php ?>
    <form action="<?php echo htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES'UTF-8'); ?>">
    When outputting values into JavaScript you should use json_encode instead. For example:
    PHP Code:
    <?php ?>
    <script type="text/javascript">
        var username = '<?php echo $username?>';
    </script>
    Should be written as:
    PHP Code:
    <?php ?>
    <script type="text/javascript">
        var username = <?php echo json_encode((string)$username); ?>;
    </script>
    Chapter 1.3: Protect against file path manipulation

    Using improperly sanitized user-supplied data as part of a file path can lead to vulnerabilities that allow attackers to access arbitrary files on the server. This is known as a remote file inclusion vulnerability.

    Here is an example of vulnerable code:
    PHP Code:
    <?php
        
    require("pages/{$_GET['page']}.php");
    An attacker could send a page parameter with a value like "../../../../etc/passwd\0" and steal a list of user accounts from your server. There are two key elements to this attack: the first is the use of "../" to go up a directory level. This allows the attacker to include files that are outside of your web root. The second is the use of a null-byte "\0" at the end of the filename. In C programming, a null-byte is used to designate the end of a string. This allows an attacker to discard and ignore the rest of the string (".php"), thus letting them to point to any arbitrary file regardless of its extension.

    This same potential for exploitation exists for all function that use file system paths (file_get_contents, fopen, move_uploaded_file, etc.).

    Chapter 1.4: Protect against malicious file uploads

    An improperly validated file upload script will attacks to take complete control of your server by uploading and executing arbitrary PHP code. This type of attack is devestating to security, and the only proper resolution if it does happen is to wipe your server and restore from an uncompromised backup of the code.

    All of the issues inherent with using user input in file paths also exists with file uploads, but there are additional security concerns related to the type, extension and contents of the uploaded file.

    Here is an example of insecure upload code:
    PHP Code:
    $uploads_dir '/uploads/';
    $tmp_name $_FILES['picture']['tmp_name'];
    $name $_FILES['picture']['name'];
    move_uploaded_file($tmp_name$uploads_dir $name); 
    Here is another example of insecure code:
    PHP Code:
    $uploads_dir '/uploads/';
    $uploads_ext '.jpeg';
    $tmp_name $_FILES['picture']['tmp_name'];
    $name pathinfo($_FILES['picture']['name'], PATHINFO_BASENAME);
    move_uploaded_file($tmp_name$uploads_dir $name $uploads_ext); 
    And here is a third example of insecure code:
    PHP Code:
    $uploads_dir '/uploads/';
    $is_image strpos($_FILES["picture"]["type"], "image");
    $tmp_name $_FILES['picture']['tmp_name'];
    $name $_FILES['picture']['name'];
    if(
    $is_image !== FALSE) {
       
    move_uploaded_file($tmp_name$uploads_dir $name);

    And yet a fourth example of insecure code (there are a lot of ways of doing this wrong):
    PHP Code:
    $uploads_dir '/uploads/';
    $tmp_name $_FILES['picture']['tmp_name'];
    $name $_FILES['picture']['name'];
    if(
    mime_content_type($tmp_name) === 'image/png') {
       
    move_uploaded_file($tmp_name$uploads_dir $name);

    When allowing a user to upload a file you must never allow the user to arbitrarily specify the extension of the uploaded file. Always validate the extension of the file name against a white list of valid file extensions.

    And finally, here is an example of the only secure way to perform file upload validation - a file extension check:
    PHP Code:
    $uploads_dir '/uploads/';
    $tmp_name $_FILES['picture']['tmp_name'];
    $name pathinfo($_FILES['picture']['name'], PATHINFO_BASENAME);
    $allowed_extensions = array('png');
    if(
    in_array(pathinfo($namePATHINFO_EXTENSION), $allowed_extensions)) {
       
    move_uploaded_file($tmp_name$uploads_dir $name);

    Alternatively: do not allow the user to specify file name at all.

    Chapter 1.6 - Do not trust user-supplied form values

    Select boxes do not force a user to select a valid option. A malicious user can submit any value, as if the select box were a text input. When a select box is submitted, the option must be validated against the list of items that were originally present in the box.

    The same applies to hidden input fields. It is trivial for a malicious user to change the value of a hidden field, so they must never be used to store anything that you don't want the user to be able to change (for example, a price).

    Chapter 1.7 - Do not trust HTTP_REFERER

    $_SERVER['HTTP_REFERER'] cannot be used for security purposes because it can be arbitrarily changed by the user with no effort. Additionally, some legitimate users will not send valid HTTP_REFERER headers, and they will not be able to use any section of your site that depends on HTTP_REFERER being set.

    There is no reliable way to obtain the address of the referring page.

    Chapter 1.8 - Do not trust cookies

    The value of a cookie can be arbitrarily changed by the user with no effort. Do not use them to store information that you do not want the user to be able to change (such as the user ID that they are logged in as).

    Additionally, passwords, even hashed passwords, should never be stored in a cookie.

    If you need to track data for a visitor and do not want them to be able to change it, you must use a session instead.

    Chapter 1.9 - Validate user-supplied redirect URLs

    Whenever using a user-supplied URL for redirection you need to validate the URL to ensure that it belongs to your website. Not doing so allows an attacker to abuse your redirection feature for phishing.

    User-supplied redirection URLs are commonly used on login forms. For example, if a user visits /my-account and they are not logged in, your site might redirect them to /login.php?after-login-redirect-to=/my-account.

    After the user logs in, your application may perform a simple redirect ack to the /my-account page:
    PHP Code:
    <?php
    header
    ("Location: {$_GET['after-login-redirect-to']}");
    exit;
    However, an attacker could send a novice user a URL like: http://yoursite.com/login.php?after-login-redirect-to=http://malicioussite.com/

    The user will see the page as being from your trusted site, and the login page they receive will be on your domain and show your security certificates; but after they log in they are automatically sent to a malicious site.

    To avoid this problem, validate the URL before performing the redirect. This may be as simple as not allowing absolute URLs, or you may need to validate the domain name against a white list of valid redirect domains.

    Chapter 1.4 - Protect against PHP injection

    Use of the eval function is usually a bad idea, but using user-supplied data as part of a string passed to eval is a worse idea. The best approach is to not do this at all, but if you must, make sure the user-supplied data is properly validated and sanitized.

    There is no general-case solution to sanitizing user-supplied data used in eval; it depends completely on how the data is used within eval.

    Chapter 1.?: Protecting against shell injection

    When using shell functions like system, exec, passthru, etc. any user-supplied data passed to the functions must be escaped using escapeshellarg similar to the way mysql_real_escape_string would be used.

    Chapter 1.10 - Protect against CSRF

    Chapter 1.11 - Things to NOT do when escaping data


    Section 2: Storing user data

    Chapter 1.1 Storing passwords

    Chapter 1.2 Storing credit card data

    Simple: don't do it. Unless you already know enough to have written this guide, you do not know enough about security to store credit card information. Use a hosted API or hire an expert.

    I would also like to point out that it is a violation of every merchant agreement to ever store CVV/CCV/card security codes in any format for any length of time. Storing these may result in the revocation of your company/client's ability to process credit cards and/or fines of up to $500,000.


    Section 3: Application design

    Chapter 3.1 Always re-validate user authentication on private pages

    Chapter 3.2 Call exit or die after redirecting a user

    A header redirect like the following is often used to redirect the user:
    PHP Code:
    <?php
    header
    ("Location: http://url/");
    However, it is important to note that PHP does not stop executing after the call to header(). The rest of the script still executes, and all of its output is still send to the user. There are two related security holes that might result from this:

    PHP Code:
    <?php
        
    if(!$user_has_access) {
            
    header("Location: /access-denied.php");
        }

        
    some_protected_database_change();

        echo 
    "some protected content;
    In this example, the PHP script will still execute the function some_protected_database_change() even if the user does not have access to the page (ie: $user_has_access is false). Additionally, "some protected content" will still be sent to the user's browser so they can access this if they want to see it.

    Section 4: PHP configuration

    Chapter 4.1 - Handling error reporting correctly

    On a production web server, display_errors should never be enabled. PHP error messages can provide attackers with information about your server, such as file paths, file names, and even database connection usernames and passwords.

    On a production web server, log_errors should always be enabled and error_log should be set. You should monitor these, as error messages can often tell you when someone is attempting to break into your server.

    On both development and production machines, error_reporting should always be set to E_ALL.

    All of these configuration parameters can be set using the ini_set function, but ideally they should be set in php.ini instead.

    Chapter 4.2 - Do not rely on insecure PHP features
    PHP FAQ

    Originally Posted by Spad
    Ah USB, the only rectangular connector where you have to make 3 attempts before you get it the right way around

IMN logo majestic logo threadwatch logo seochat tools logo