Skip to main content

OWASP TOP 10 Mitigation Best Practices

Building secure software requires a basic understanding of security principles. While a comprehensive review of security principles is beyond the scope of this guide, a quick overview is provided. AINQA’s goal of software security is to maintain the confidentiality, integrity, and availability of information resources in order to enable successful business operations. This goal is accomplished through the implementation of security controls. This guide focuses on the technical controls specific to mitigating the occurrence of common software vulnerabilities. While the primary focus is web applications and their supporting infrastructure, most of the guidance can be applied to any software deployment platform.

To protect the business from unacceptable risks associated with its reliance on software, it helps to understand what is meant by risk. Risk is a combination of factors that threaten the success of the business. This can be described conceptually as follows: a threat agent interacts with a system, which may have a vulnerability that can be exploited in order to cause an impact. While this may seem like an abstract concept, think of it this way: a car burglar (threat agent) goes through a parking lot checking cars (the system) for unlocked doors (the vulnerability) and when they find one, they open the door (the exploit) and take whatever is inside (the impact). All of these factors play a role in secure software development.

There is a fundamental difference between the approach taken by our development team and that taken by someone attacking an application. A development team typically approaches an application based on what it is intended to do. This means designing an application to perform specific tasks based on documented functional requirements and use cases. An attacker, on the other hand, is more interested in what an application can be made to do and operates on the principle that "any action not specifically denied, is allowed". To address this, additional elements need to be integrated into the early stages of the software lifecycle. These new elements are security requirements and abuse cases. This guide is designed to help with identifying high level securely requirements and addressing many common abuse scenarios.

It is important for web our AINQA ATP development teams to understand that client side controls like client based input validation, hidden fields and interface controls (e.g., pull downs and radio buttons), provide little if any security benefit. An attacker can use tools like client side web proxies (e.g. OWASP WebScarb, Burp) or network packet capture tools (e.g., WireShark) to analyzed application traffic and submit custom built requests, bypassing the interface all together. Additionally, Flash, Java Applets and other client-side objects can be decompiled and analyzed for flaws.

Software security flaws can be introduced at any stage of the software development lifecycle, including:

  • Not identifying security requirements up front
  • Creating conceptual designs that have logic errors
  • Using poor coding practices that introduce technical vulnerabilities
  • Deploying the software improperly
  • Introducing flaws during maintenance or updating

Furthermore, it is important to understand that software vulnerabilities can have a scope beyond the software itself. Depending on the nature of the software, the vulnerability and the supporting infrastructure, the impacts of a successful exploitation can include compromises to any or all of the following:

  • The software and its associated information
  • The operating systems of the associated servers
  • The backend database
  • Other applications in a shared environment
  • The user's system
  • Other software that the user interacts with

Secure Coding Practices Checklist

Data Validation:

  • Conduct all data validation on a trusted system (e.g., The server)
  • Encode data to a common character set before validating (Canonicalize).
  • Determine if the system supports UTF-8 extended character sets and if so, validate after UTF-8 decoding is completed.
  • Validate all client provided data before processing, including all form fields, URLs and HTTP header values. Be sure to include automated post backs from JavaScript, Flash or other embedded code.
  • Identify system trust boundaries and validate all data from external connections (e.g., Databases, file streams, etc.).
  • Utilize a master validation routine for inbound and outbound encoding.
  • Validate all input against a "white" list of allowed characters.
  • Sanitize any potentially hazardous characters that must be allowed, like: <, >, ", ', %, (, ), &, +, \, \', \"
  • Validate for expected data types.
  • Validate data range.
  • Validate data length.
  • HTML entity encode all output to the client. If this is not possible, at least encode all dynamic content that originated outside the application's trust boundary.
  • If your standard validation routine cannot address the following inputs, then they should be checked Discretely
  • Check for null bytes (%00).
  • Check for new line characters (%0d, %0a, \r, \n).
  • Check for “dot-dot-slash" (../ or ..) path alterations characters. In cases where UTF-8 extended character set encoding is supported, address alternate representation like: %c0%ae%c0%ae/

(Utilize canonicalization to address double encoding or other forms of obfuscation attacks)

Authentication and Password Management:

  • Establish and utilize standard, tested, security services whenever possible
  • Change all vendor-supplied default passwords and user IDs or disable the associated accounts.
  • Utilize re-authentication for critical operations.
  • Use two factor authentication for highly sensitive or high value transactional accounts.
  • Validate the authentication data only on completion of all data input, especially for sequential authentication implementations.
  • Error conditions should not indicate which part of the authentication data was incorrect. Error responses must be truly identical in both display and source code.
  • Use only POST requests to transmit authentication credentials.
  • Only send passwords over an encrypted connection.
  • Enforce password complexity requirements established by policy or regulation. An example might be requiring the use of alphabetic as well as numeric and/or special characters.
  • Enforce password length requirements established by policy or regulation. Eight characters is commonly used, but 16 is better or consider the use of multi-word pass phrases.
  • Password entry should be obscured on the users screen. (e.g., On web forms use input type "password")
  • Enforce account disabling after an established number of invalid logon attempts (e.g., five attempts is common). The account must be disabled for a period of time sufficient to discourage brute force guessing of credentials.
  • Password recovery and changing operations require the same level of controls as account creation and authentication.
  • Password recovery should only send an email to a pre-registered email address with a temporary link/password which let’s the user reset the password.
  • Temporary passwords and links should have a short expiration time.
  • Password recovery questions should support sufficiently random answers.
  • Enforce the changing of temporary passwords on the next use.
  • Prevent password re-use.
  • Passwords should be at least one day old before they can be changed, to prevent attacks on password re-use.
  • Enforce password changes based on requirements established in policy or regulation. Critical systems may require more frequent changes.
  • Disable "remember me" functionality for password fields.
  • Log all authentication failures.
  • Report unsuccessful logon attempts to a User ID, at its next successful logon.
  • The last use of a User ID should be reported to the User ID at its next successful logon.
  • Segregate authentication logic and use redirection during login.
  • If your application manages credential storage, it should ensure that only the 1-way salted hashes of passwords are stored in the database, and that the table/file that stores the passwords and keys are “write”-able only to the application.
  • Implement monitoring to identify attacks against multiple user accounts, utilizing the same password.
  • This attack pattern is used to bypass standard lockouts.
  • Log out functionality should be available from all pages.
  • Log out functionality should fully terminate the associated ses or connection.

Authorization and Access Management:

  • Use only server-side session objects for making authorization decisions.
  • Enforce authorization controls on every request, including server side scripts and includes.
  • Ensure that all directories, files, or other resources outside the application's direct control have appropriate access controls in place.
  • If state data must be stored on the client, use encryption and integrity checking on the server side to catch state tampering. The application should log all apparent tampering events.
  • Enforce application logic flows to comply with business rules.
  • Use a single site wide component to check access authorization.
  • Segregate privileged logic from other application code.
  • Limit the number of transactions a single user or device can perform in a given period of time. The transactions/time should be above the actual business requirement, but low enough to deter automated attacks.
  • Use the referrer header as a supplemental check only, it should never be the sole authorization check, as it can be spoofed.
  • Create an Access Control Policy to document an applications business rules and access authorization criteria and/or processes so that access can be properly provisioned and controlled. This includes identifying access requirements for both the data and system resources.
  • If long authenticated sessions are allowed, periodically revalidate a user’s authorization to ensure that their privileges have not changed.
  • Implement account auditing and enforce the disabling of unused accounts (e.g., After no more than 30 days from the expiration of an account’s password.).
  • The application must support disabling of accounts and terminating sessions when authorization ceases (e.g., Changes to role, employment status, business process, etc.).
  • Isolate development environments from the production network and provide access only to authorized development and test groups. Development environments are often configured less securely than production environments and attackers may use this difference to discover shared weaknesses or as an avenue for exploitation

Session Management:

  • Establish a session inactivity timeout that is as short as possible. It should be no more than several hours.
  • If a session was established before login, close that session, and establish a new session after a successful login.
  • Do not allow concurrent logins with the same user ID.
  • Use well vetted algorithms that ensure sufficiently random session identifiers.
  • Session ID creation must always be done on the server side.
  • Do not pass session identifiers as GET parameters.
  • Server-side session data should have appropriate access controls in place.
  • Generate a new session ID and deactivate the old one frequently.
  • Generate a new session token if a user's privileges or role changes.
  • Generate a new session token if the connection security changes from HTTP to HTTPS. Only utilize the system generated session IDs for client-side session management.
  • Avoid using parameters or other client data for state management.
  • Utilize per-session random tokens or parameters within web forms or URLs that are associated with sensitive server-side operations, like account management, to prevent Cross Site Request Forgery attacks.
  • Utilize per-page random tokens or parameters to supplement the main session token for critical operations.
  • Ensure cookies transmitted over an encrypted connection have the "secure" attribute set.
  • Set cookies with the HTTP Only attribute unless you specifically require client-side scripts within your application to read or set a cookie's value.
  • The application or system should log attempts to connect with invalid or expired session tokens.
  • Disallow persistent logins and enforce periodic session terminations, even when the session is active. Especially for applications supporting rich network connections or connecting to critical systems.
  • Termination times should support business requirements and the user should receive sufficient notification to mitigate negative impacts

Sensitive Information Storage or Transmission:

  • Implement encryption for the transmission of all sensitive information.
  • Encrypt highly sensitive stored information, like authentication verification data, even on the server side. When encryption is required implement well vetted algorithms.
  • Protect server-side code from being downloaded.
  • Do not store passwords, connection strings or other sensitive information in clear text or in any non-cryptographically secure manner on the client side. This includes embedding in insecure formats like:
  • MS view state, Adobe flash or compiled code.
  • Do not store sensitive information in logs.
  • Implement least privilege, restrict users to just the functionality, data and system information that is required to perform their tasks.
  • Remove developer comments.
  • Remove unnecessary application and system documentation.
  • Turn off verbose system messages, especially any associated with error conditions.
  • The application should handle application errors and not rely on the server configuration.
  • Filter GET parameters from the referrer, when linking to external sites

System Configuration Management:

  • Ensure servers, frameworks and system components are patched.
  • Ensure servers, frameworks and system components are running the latest approved version.
  • Use safe exception handlers.
  • Disable any unnecessary Extended HTTP methods. If an Extended HTTP method that supports file handling is required, utilize a well vetted authentication mechanism. (e.g., WebDav)
  • Turn off directory listing.
  • Ensure SSL certificates have the correct domain name and are not expired.
  • Restrict the web server, process and service accounts to the least privileges possible.
  • Implement generic error messages and custom error pages that do not disclose system information.
  • When exceptions occur, fail secure.
  • Remove all unnecessary functionality and files.
  • Remove any test code.
  • Remove unnecessary information from HTTP response headers related to the OS, webserver version and application frameworks.
  • Prevent disclosure of your directory structure and stop robots from indexing sensitive files and directories by moving them into an isolated parent directory and then "Disallow" that entire parent directory in the robots.txt file.
  • Log all exceptions.
  • Restrict access to logs.
  • Log all administrative functions.
  • Use hashing technology to validate log integrity.
  • Implement asset management systems and register system components and sofware in them .

General Coding Practices:

  • Utilize task specific built-in APIs to conduct operating system tasks. Do not allow the application to issue commands directly to the Operating System, especially through the use of application-initiated command shells.
  • Use tested and approved managed code rather than creating new unmanaged code for common tasks.
  • Utilize locking to prevent multiple simultaneous requests to the application or use a synchronization mechanism to prevent race conditions.
  • Explicitly initialize all your variables and other data stores, either during declaration or just before the first usage.
  • Properly free allocated memory upon the completion of functions and at all exit points including error conditions.
  • In cases where the application must run with elevated privileges, raise privileges as late as possible, and drop them as soon as possible.
  • Avoid calculation errors by understanding your programming language's underlying representation and how it interacts with numeric calculation. Pay close attention to byte size discrepancies, precision, signed/unsigned distinctions, truncation, conversion, and casting between types, "not-a-number" calculations, and how your language handles numbers that are too large or too small for its underlying representation.
  • Do not pass user supplied data to any dynamic execution function.
  • Restrict users from generating new code or altering existing code.
  • Review all secondary applications, third party code and libraries to determine business necessity and validate safe functionality, as these can introduce new vulnerabilities
  • Implement safe updating. If the application will utilize automatic updates, then use cryptographic signatures for your code and ensure your download clients verify those signatures. Use encrypted channels to transfer the code from the host server.

Database Security:

  • Use strongly typed parameterized queries. Parameterized queries keep the query and data separate through the use of placeholders. The query structure is defined with place holders and then the application specifies the contents of each placeholder.
  • Utilize input validation and if validation fails, do not run the database command.
  • Ensure that the input does not include unintended SQL keywords.
  • Ensure that variables are strongly typed.
  • Escape meta characters in SQL statements.
  • The application should use the lowest possible level of privilege when accessing the database.
  • Use secure credentials for database access.
  • Do not provide connection strings or credentials directly to the client. If this is unavoidable, encrypted them.
  • Use stored procedures to abstract data access.
  • Turn off any database functionality (e.g., unnecessary stored procedures or services).
  • Eliminate default content.
  • Disable any default accounts that are not required to support business requirements.
  • Close the connection as soon as possible.
  • The application should connect to the database with different credentials for every trust distinction (e.g., user, read-only user, guest, administrators)

File Management:

  • Do not pass user supplied data directly to any dynamic include function.
  • Limit the type of files that can be uploaded to only those types that are needed for business purposes.
  • Validate uploaded files are the expected type.
  • Do not save files in the web space. If this must be allowed, prevent, or restrict the uploading of any file that can be interpreted by the web server.
  • Turn off execution privileges on file upload directories.
  • Implement safe uploading in UNIX by mounting the targeted file directory as a logical drive using the associated drive letter or the chrooted environment.
  • When referencing existing files, use a hard coded list of allowed file names and types. Validate the value of the parameter being passed and if it does not match one of the expected values, use a hard coded default file value for the content instead.
  • Do not pass user supplied data into a dynamic redirect. If this must be allowed, then the redirect should accept only validated, relative path URLs.
  • Do not pass directory or file paths, use index values mapped to hard coded paths.
  • Never send the absolute file path to the user.
  • Ensure application files and resources are read-only.
  • Implement access controls for temporary files.
  • Remove temporary files as soon possible

Memory Management:

  • Utilize input validation.
  • Double check that the buffer is as large as specified.
  • When using functions that accept a number of bytes to copy, such as strncpy(), be aware that if the destination buffer size is equal to the source buffer size, it may not NULL-terminate the string.
  • Check buffer boundaries if calling the function in a loop and make sure there is no danger of writing past the allocated space.
  • Truncate all input strings to a reasonable length before passing them to the copy and concatenation functions.
  • Specifically close resources don’t rely on garbage collection. (e.g., connection objects, file handles, etc.)
  • Use Non-executable stacks when available.
  • Avoid the use of known vulnerable functions (e.g., printf, strcat, strcpy et).

10 React Security Best Practices

  1. Use Default XSS Protection with Data Binding

Use default data binding with curly braces {} and React will automatically escape values to protect against XSS attacks. Note that this protection only occurs when rendering textContent and not when rendering HTML attributes.

  • Use JSX data binding syntax {} to place data in your elements. Ex.
<div>{data}</div>

- Avoid dynamic attribute values without custom validation.

Don’t use <form action={data}>...
  1. Watch Out for Dangerous URLs and URL-Based Script Injection

URLs can contain dynamic script content via javascript: protocol urls. Validate URLs before use

  • Use validation to assure your links are http or https to avoid javascript: URL based script injection. Achieve URL validation using a native URL parsing function then match the parsed protocol property to an allow list.
  1. Sanitize and Render HTML

It is possible to insert HTML directly into rendered DOM nodes using dangerouslySetInnerHTML. Any content inserted this way must be sanitized beforehand.

  • Use a sanitization library like DOMPurify on any values before lacing them into the dangerouslySetInnerHTML prop.
import purify from "dompurify";  <div dangerouslySetInnerHTML= {{\_\_html:purify.sanitize(data)}} />
  1. Avoid Direct DOM Access

Accessing the DOM to inject content into DOM nodes directly should be avoided. Use dangerouslySetInnerHTML if you must inject HTML and sanitize it before injecting it using DOMPurify.

  • Avoid using refs and findDomNode() to access rendered DOMelements to directly inject content via innerHTML and similar properties and methods.
  1. Secure Server-side Rendering

Data binding will provide automatic content escaping when using server-side rendering functions like ReactDOMServer.renderToString() and ReactDOMServer.renderToStaticMarkup().

  • Avoid concatenating strings onto the output of renderToString() and renderToStaticMarkup() before sending the strings to the client for hydration or rendering.
  1. Check for Known Vulnerabilities in Dependencies

Some versions of third-party components might contain security issues. Check your dependencies and update when better versions become available.

  • Use a tool like the free Snyk cli to check for vulnerabilities
  • Automatically fix vulnerabilities with Snyk by integrating with your source code management system to receive automated fixes.

$ npx snyk test

  1. Avoid JSON Injection Attacks

It is common to send JSON data along with server-side rendered React pages. Always escape < characters with a benign value to avoid injection attacks.

  • Avoid unescaped HTML significant values in JSON state objects.
<script>   

// WARNING: See the following for

security issues around embedding JSON in HTML:

// https://redux.js.org/recipes/ server-rendering/#security

considerations

window.\_\_PRELOADED\_STATE\_\_ =

${JSON.stringify( preloadedState).replace(

/</g,

'\\u003c')}

</script>
  1. Use Non-Vulnerable Versions of React

The React library has had a few high severity vulnerabilities in the past, so it is a good idea to stay up-to-date with the latest version.

  • Avoid vulnerable versions of the react and react-dom by verifying that you are on the latest version using npm outdated to see the latest versions.
  • Use Snyk to automatically update to new versions when vulnerabilities exist in the versions you are using.
  1. Use Linter Configurations

Install Linters configurations and plugins that will automatically detect security issues in your code and offer remediation advice.

  • Use the ESLint React security config to detect security issues in our code base.
  • Configure a pre-commit hook that fails when security related linter issues are detected using a library like husky.
  1. Avoid Dangerous Library Code

Library code is often used to perform dangerous operations like directly inserting HTML into the DOM. Review library code manually or with linters to detect unsafe usage of React’s security mechanisms.

  • Avoid libraries that do use dangerouslySetInnerHTML, innerHTML, unvalidated URLs or other unsafe patterns.
  • Use security linters on your node modules folder to detect unsafe patterns in your library code.