Code Fortification

Code Fortification

Password Hashing and Encryption

The following list includes mitigation strategies you will want to present to your clients concerning secure password storage and transmission:

  • Don’t allow developers to hard-code credentials in apps.
  • Hash stored passwords rather than storing them in plaintext.
  • Use cryptographically strong hash functions, like SHA-256 and bcrypt.
  • Avoid cryptographically weak hash functions, like MD5 and SHA-1.
  • Use network access protocols that encrypt passwords in transit.
  • For example, use SSH instead of Telnet, HTTPS instead of HTTP, FTPS instead of FTP, etc.
  • Ensure network access protocols are using strong ciphers, like AES-256 and RC6.
  • Avoid using network access protocols that incorporate weak cryptographic ciphers, like DES and 3DES.
  • Disallow or reconfigure services that allow themselves to be negotiated down to a weaker cryptographic or protocol version.
  • Ensure security solutions like IDS and data loss prevention (DLP) can monitor and manage unencrypted traffic in the network.

Multi-Factor Authentication

Just a few years ago, the cost of implementing multi-factor authentication could be quite high. More recently, it has become very affordable, costing as little as $10 USD per person. MFA is therefore a more feasible strategy for even smaller businesses to adopt. It is especially useful in circumstances where users must authenticate to a system that gives them critical access to company resources or to their own PII and personal activities, like online banking. Even if the organization has systems that enforce password strength and complexity requirements, users will still tend to choose easily guessable and/or word-based passwords that a dictionary attack will make short work of. MFA can compensate for this weakness by requiring the user to also provide some other authentication, or else they will be unable to log in.

There are many authentication methods that supplement the “something you know” of password-based authentication. Perhaps the most common is a limited-time security code sent to the user’s smartphone via SMS. This fulfills a “something you have” factor and can be combined with a user name and password to sign in. Since many people have smartphones, this is not an overly strict requirement, and in some cases, the organization will issue smartphones to employees for them to use on the job. Other examples of authentication factors used in MFA include smart cards (“something you have”), hardware tokens/key fobs, and biometric fingerprint scanners (“something you are”).

Input Sanitization

Input sanitization is the process of stripping user-supplied input of unwanted or untrusted data so that the application can safely process that input. It is the most common approach to mitigating the effects of code injection, particularly XSS and SQL injection. Any online form that echoes input from the user back to the user on the web page, or which stores input data within the web app database, must be sanitized before the data is output or processed. There are actually several tactics that are considered types of input sanitization, and each one has a different purpose and mitigates different types of attacks.

For XSS, the most prominent type of sanitization is escaping HTML special characters such as angle brackets (< and >) and the ampersand (&) to prevent them from being processed by the browser with the user input. Escaping, also referred to as encoding, substitutes special characters in HTML markup with representations called entities. For example, the entity for less than (<) is &lt; when encoded. Entities ensure that the browser does not interpret malicious code as something that it should run. Depending on the language the page is written in, you will need to use the encoding command appropriate for that language. In PHP, you can use the htmlspecialchars() function to escape major HTML characters:

<?php function my_func($input) { echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8'); } ?>
<!DOCTYPE html> 
    	<?php my_func('<script>alert("XSS attack successful!");</script>'; ?>

The htmlspecialchars() function encodes the accepted $input input parameter so that any instances of ampersands (&), double quotes (“), single quotes (‘), less than symbols (<), or greater than symbols (>) in the input are turned into entities. So, in the HTML below that, when the custom my_func() function is called with the malicious alert string, it gets encoded into &lt;script&gt;alert(&quot;XSS attack successful!&quot;);&lt;/script&gt; and therefore the browser will not run the script.

This type of encoding is sufficient for preventing XSS in many cases, but not all. For example, encoding won’t work in apps that need to accept HTML input. In those cases, you should use a sanitization library that is written to the relevant language. These libraries automatically parse and strip user-supplied HTML input of untrusted data. Some example libraries include HtmlSanitizer (.NET), PHP HTML Purifier (PHP), SanitizeHelper (Ruby on Rails), and OWASP Java HTML Sanitizer Project (Java).

Additional XSS Mitigation Techniques

In addition to using sanitization libraries, you can also whitelist the type of rich text inputs you’ve deemed safe for the web app to accept. Any inputs not matching the whitelist will be rejected. You can also replace raw HTML markup for rich text components with another markup language, like Markdown. Attempts to inject malicious HTML will prove ineffective.

Null Byte Sanitization

The most effective way of preventing the poison null byte is to remove it from the input entirely. Modern web app languages tend to handle this automatically, but you can also perform the sanitization manually if you’re using an older version. For example, in PHP, you can strip the null byte as follows:

$file = str_replace(chr(0), '', $input);

Parameterized Queries

Parameterized queries, also called prepared statements, process SQL input by incorporating placeholders for some of a query’s parameters. When the query is executed, the web app binds the actual values to these parameters in a different statement. So, a quotation mark in a parameterized query would be interpreted literally, rather than be interpreted as if it were a part of the query structure. The input x’ OR ‘x’=’x in the user name field of a login form would force the database to look for a user name that literally matched x’ OR ‘x’=’x in its records.

Parameterized queries are the most effective means of preventing SQL injection attacks. Like other forms of input sanitization, how you implement parameterized queries will differ based on language. For example, PHP uses an abstraction layer called PHP Data Objects (PDO) for processing database content:

	$prod_name = ""
    $prod_desc = ""
    // Code to connect to database...
    // Prepare statement
    $stmt = $db_conn->prepare("INSERT INTO products (prod_name, prod_desc) VALUES (:prod_name, :prod_desc)");
    $stmt->bindParam(':prod_name', $prod_name);
    $stmt->bindParam(':prod_desc', $prod_desc);

The INSERT INTO query is prepared, essentially creating a template for the database to parse. This parsed template is stored without being executed. The input values for $prod_name and $prod_desc are then bound to each parameter and transmitted after the query itself. When plugged into the template, the input values are executed literally, preventing the web app from succumbing to injected code.

Example for .NET Core 5 using C#:

private static void UpdateDemographics(Int32 customerID,
    string demoXml, string connectionString)
    // Update the demographics for a store, which is stored
    // in an xml column.
    string commandText = "UPDATE Sales.Store SET Demographics = @demographics "
        + "WHERE CustomerID = @ID;";

    using (SqlConnection connection = new SqlConnection(connectionString))
        SqlCommand command = new SqlCommand(commandText, connection);
        command.Parameters.Add("@ID", SqlDbType.Int);
        command.Parameters["@ID"].Value = customerID;

        // Use AddWithValue to assign Demographics.
        // SQL Server will implicitly convert strings into XML.
        command.Parameters.AddWithValue("@demographics", demoXml);

            Int32 rowsAffected = command.ExecuteNonQuery();
            Console.WriteLine("RowsAffected: {0}", rowsAffected);
        catch (Exception ex)

Secure Software Development

Whether the client organization develops its own software or leverages software provided by a third-party vendor, it should ensure that the security of this software is not an afterthought. Security should be an active component in the development process, not something that the organization applies reactively whenever an issue crops up.

Secure software development should follow a software development life cycle (SDLC). An SDLC focuses primarily on the design, development, and maintenance of applications and other software. Development passes through several phases, and ideally, security is incorporated at each of those phases. For example, the testing phase should include techniques like fuzzing and input validation to identify if the app is vulnerable to certain attacks before it is put into operation. Adhering to an SDLC is crucial because it helps ensure that there are no gaps in the software’s security at any point from beginning to end.

Adhering to best coding practices is also an important component of secure software development. Some examples of best practices include writing code that:

  • Is clear and easy for other developers to grasp.
  • Has useful and informative documentation.
  • Is easy to incorporate in the build process.
  • Is highly extensible.
  • Has as few external dependencies as possible.
  • Is concise.
  • Relies on well-established techniques.
  • Integrates well with test harnesses.
  • Closely aligns with design requirements.

Related to this, the organization should also actively avoid the insecure coding practices discussed in a previous lesson.

Follow NASA’s 10 Rules:

  1. Avoid complex flow constructs, such as goto and recursion.
  2. All loops must have fixed bounds. This prevents runaway code.
  3. Avoid heap memory allocation.
  4. Restrict functions to a single printed page.
  5. Use a minimum of two runtime assertions per function.
  6. Restrict the scope of data to the smallest possible.
  7. Check the return value of all non-void functions, or cast to void to indicate the return value is useless.
  8. Use the preprocessor sparingly.
  9. Limit pointer use to a single dereference, and do not use function pointers.
  10. Compile with all possible warnings active; all warnings should then be addressed before release of the software.

Guidelines for Developing Recommendations for Mitigation Strategies

When developing recommendations for mitigation strategies:

  • Consider people, processes, and technology when recommending mitigation strategies.
  • Recommend strategies for common findings, such as:
  • Shared local administrator credentials: Randomize credentials or use LAPS.
  • Weak password complexity: Configure minimum password requirements and use password filters.
  • Plaintext passwords: Use protocols that hash or encrypt passwords.
  • No multi-factor authentication: Implement or require multi-factor authentication for access to critical systems.
  • XSS attacks: Sanitize user input by encoding/escaping special HTML characters.
  • SQL injection: Sanitize user input by parameterizing queries.
  • Unnecessary open services: Perform system hardening.
  • Physical intrusion: Incorporate guards, security cameras, motion alarms, and other physical security defenses.
  • Recommend end-user training to mitigate social engineering attacks on end users.
  • Recommend system hardening techniques like patch management and firewall configuration to secure hosts.
  • Recommend MDM solutions for mobile infrastructure security.
  • Recommend SDLC and best coding practices for secure software development.

Leave a Reply

Your email address will not be published. Required fields are marked *