50 Essential Development Security Practices You Can’t Ignore
50 Essential Development Security Practices You Can’t Ignore
Even the highly protected IT infrastructure of popular software systems are facing massive security attacks – increasing the attack surface to any company, organization or individual. Such a productivity-enhancing software system often holds large amounts of sensitive data, both personal and corporate.
The traditional software security management based on the release-and-patch cycle has no potential to counter the rising intensity of security attacks. This article shares 50 essential security practices to be followed during software development offered by expert developers.
Below are awesome Development Security Best Practices:
- Don’t Hardcode Credentials:
Never allow credentials to be stored directly within the application code. While it can be convenient to test application code with hard coded credentials during development this significantly increases risk and should be avoided.
- Develop a Strong Password Reset System:
Password reset systems are often the weakest link in an application. These systems are often based on the user answering personal questions to establish their identity and in turn reset the password. The system needs to be based on questions that are both hard to guess and brute force. Additionally, any password reset option must not reveal whether or not an account is valid, preventing username harvesting.
- Implement a Strong Password Policy:
A password policy should be created and implemented so that passwords meet specific strength criteria.
- Implement Account Lockout against Brute Force Attacks:
Account lockout needs to be implemented to guard against brute forcing attacks against both the authentication and password reset functionality. After several tries on a specific user account, the account should be locked for a period of time or until manually unlocked. Additionally, it is best to continue the same failure message indicating that the credentials are incorrect or the account is locked to prevent an attacker from harvesting usernames.
- Don’t Disclose Too Much Information in Error Messages:
Messages for authentication errors must be clear and, at the same time, be written so that sensitive information about the system is not disclosed. For example, error messages which reveal that the userid is valid but that the corresponding password is incorrect confirms to an attacker that the account does exist on the system.
- Store Database Credentials Securely:
Modern web applications usually consist of multiple layers. The business logic tier (processing of information) often connects to the data tier (database). Connecting to the database, of course, requires authentication. The authentication credentials in the business logic tier must be stored in a centralized location that is locked down. Scattering credentials throughout the source code is not acceptable. Some development frameworks provide a centralized secure location for storing credentials to the backend database. These encrypted stores should be leveraged when possible.
- Applications and Middleware Should Run with Minimal Privileges:
If an application becomes compromised it is important that the application itself and any middleware services be configured to run with minimal privileges. For instance, while the application layer or business layer needs the ability to read and write data to the underlying database, administrative credentials that grant access to other databases or tables should not be provided.
- Apply Access Controls Checks Consistently:
Always apply the principle of complete mediation, forcing all requests through a common security “gate keeper.” This ensures that access control checks are triggered whether or not the user is authenticated.
- Apply the Principle of Least Privilege:
Make use of a Mandatory Access Control system. All access decisions will be based on the principle of least privilege. If not explicitly allowed then access should be denied. Additionally, after an account is created, rights must be specifically added to that account to grant access to resources.
- Don’t Use Direct Object References for Access Control Checks:
Do not allow direct references to files or parameters that can be manipulated to grant excessive access. Access control decisions must be based on the authenticated user identity and trusted server side information.
- Don’t Use Unvalidated Forwards or Redirects:
An unvalidated forward can allow an attacker to access private content without authentication. Unvalidated redirects allow an attacker to lure victims into visiting malicious sites. Prevent these from occurring by conducting the appropriate access controls checks before sending the user to the given location.
- Permission for Roles check:
Permission checks for Roles to be checked from server side as well for Client applications like Angular etc here permissions are also stored in local storage.
- Ensure That Session Identifiers Are Sufficiently Random:
Session tokens must be generated by secure random functions and must be of a sufficient length so as to withstand analysis and prediction.
- Regenerate Session Tokens:
Session tokens should be regenerated when the user authenticates to the application and when the user privilege level changes. Additionally, should the encryption status change, the session token should always be regenerated.
- Implement an Idle Session Timeout:
When a user is not active, the application should automatically log the user out. Be aware that Ajax applications may make recurring calls to the application effectively resetting the timeout counter automatically.
- Implement an Absolute Session Timeout:
Users should be logged out after an extensive amount of time (e.g. 4-8 hours) has passed since they logged in. This helps mitigate the risk of an attacker using a hijacked session.
- Destroy Sessions at Any Sign of Tampering:
Unless the application requires multiple simultaneous sessions for a single user, implement features to detect session cloning attempts. Should any sign of session cloning be detected, the session should be destroyed, forcing the real user to re-authenticate.
- Invalidate the Session after Logout:
When the user logs out of the application the session and corresponding data on the server must be destroyed. This ensures that the session can not be accidentally revived.
- Place a Logout Button on Every Page:
The logout button or logout link should be easily accessible to the user on every page after they have authenticated.
- Use Secure Cookie Attributes (i.e. HttpOnly and Secure Flags):
The session cookie should be set with both the Http Only and the Secure flags. This ensures that the session id will not be accessible to client-side scripts and it will only be transmitted over HTTPS, respectively.
- Set the Cookie Domain and Path Correctly:
The cookie domain and path scope should be set to the most restrictive settings for your application. Any wildcard domain scoped cookie must have a good justification for its existence.
- Set the Cookie Expiration Time:
The session cookie should have a reasonable expiration time. Non-expiring session cookies should be avoided.
Input and Output Handling
- Conduct Contextual Output Encoding:
- Prefer Whitelists over Blacklists:
For each user input field, there should be validation on the input content. Whitelisting input is the preferred approach. Only accept data that meets a certain criteria. For input that needs more flexibility, blacklisting can also be applied where known bad input patterns or characters are blocked.
- Use Parameterized SQL Queries:
SQL queries should be crafted with user content passed into a bind variable. Queries written this way are safe against SQL injection attacks. SQL queries should not be created dynamically using string concatenation. Similarly, the SQL query string used in a bound or parameterized query should never be dynamically built from user input.
- Use Tokens to Prevent Forged Requests:
In order to prevent Cross-Site Request Forgery attacks, you must embed a random value that is not known to third parties into the HTML form. This CSRF protection token must be unique to each request. This prevents a forged CSRF request from being submitted because the attacker does not know the value of the token.
- Set the Encoding for Your Application:
For every page in your application set the encoding using HTTP headers or meta tags within HTML. This ensures that the encoding of the page is always defined and that browser will not have to determine the encoding on its own. Setting a consistent encoding, like UTF-8, for your application reduces the overall risk of issues like Cross-Site Scripting.
- Validate Uploaded Files:
When accepting file uploads from the user make sure to validate the size of the file, the file type, and the file contents as well as ensuring that it is not possible to override the destination path for the file.
- Use the X-Frame-Options Header:
- Use Secure HTTP Response Headers:
The Content Security Policy (CSP), X-XSS-Protection, and Public-Key-Pins headers help defend against Cross-Site Scripting (XSS) and Man-in-the-Middle (MITM) attacks. EXAMPLE: OWASP Secure Headers Project.
- Use HTTPS Everywhere:
Ideally, HTTPS should be used for your entire application. If you have to limit where it’s used, then HTTPS must be applied to any authentication pages as well as to all pages after the user is authenticated. If sensitive information (e.g. personal information) can be submitted before authentication, those features must also be sent over.
- Disable HTTP Access for All Protected Resources:
For all pages requiring protection by HTTPS, the same URL should not be accessible via the insecure HTTP channel.
- Use the Strict-Transport-Security Header:
The Strict-Transport-Security header ensures that the browser does not talk to the server over HTTP. This helps reduce the risk of HTTP downgrade attacks as implemented by the sslsniff tool.
- Store User Passwords Using a Strong, Iterative, Salted Hash:
User passwords must be stored using secure hashing techniques with strong algorithms like PBKDF2, bcrypt, or SHA-512. Simply hashing the password a single time does not sufficiently protect the password. Use adaptive hashing (a work factor), combined with a randomly generated salt for each user to make the hash strong.
- Securely Exchange Encryption Keys:
If encryption keys are exchanged or pre-set in your application then any key establishment or exchange must be performed over a secure channel.
- Set Up Secure Key Management Processes:
When keys are stored in your system they must be properly secured and only accessible to the appropriate staff on a need to know basis. EXAMPLE: AWS Key Management Service (KMS), Azure Key Vault, AWS CloudHSM.
- Weak TLS Configuration on Servers:
Weak ciphers must be disabled on all servers. For example, SSL v2, SSL v3, and TLS protocols prior to 1.2 have known weaknesses and are not considered secure. Additionally, disable the NULL, RC4, DES, and MD5 cipher suites. Ensure all key lengths are greater than 128 bits, use secure renegotiation, and disable compression.
- Use Valid HTTPS Certificates from a Reputable CA:
HTTPS certificates should be signed by a reputable certificate authority. The name on the certificate should match the FQDN of the website. The certificate itself should be valid and not expired. EXAMPLE: Let’s Encrypt (https://letsencrypt.org)
- Disable Data Caching Using Cache Control Headers and Autocomplete:
Browser data caching should be disabled using the cache control HTTP headers or meta tags within the HTML page. Additionally, sensitive input fields, such as the login form, should have the autocomplete=off setting in the HTML form to instruct the browser not to cache the credentials.
- Limit the Use and Storage of Sensitive Data:
Conduct an evaluation to ensure that sensitive data is not being unnecessarily transported or stored. Where possible, use tokenization to reduce data exposure risks.
Error Handling & Logging
- Display Generic Error Messages:
Error messages should not reveal details about the internal state of the application. For example, file system path and stack information should not be exposed to the user through error messages.
- No Unhandled Exceptions:
Given the languages and frameworks in use for web application development, never allow an unhandled exception to occur. Error handlers should be configured to handle unexpected errors and gracefully return controlled output to the user.
- Suppress Framework Generated Errors:
Your development framework or platform may generate default error messages. These should be suppressed or replaced with customized error messages as framework generated messages may reveal sensitive information to the user.
- Log All Authentication Activities:
Any authentication activities, whether successful or not, should be logged.
- Log All Privilege Changes:
Any activities or occasions where the user’s privilege level changes should be logged.
- Log Administrative Activities:
Any administrative activities on the application or any of its components should be logged.
- Log Access to Sensitive Data:
Any access to sensitive data should be logged. This is particularly important for corporations that have to meet regulatory requirements like HIPAA, PCI, or SOX.
- Do Not Log Inappropriate Data:
While logging errors and auditing access is important, sensitive data should never be logged in an unencrypted form. For example, under HIPAA and PCI, it would be a violation to log sensitive data into the log itself unless the log is encrypted on the disk. Additionally, it can create a serious exposure point should the web application itself become compromised.
- Store Logs Securely:
Logs should be stored and maintained appropriately to avoid information loss or tampering by intruder. Log retention should also follow the retention policy set forth by the organization to meet regulatory requirements and provide enough information for forensic and incident response activities.
Configuration and Operations
- Automate Application Deployment:
Automating the deployment of your application, using Continuous Integration and Continuous Deployment, helps to ensure that changes are made in a consistent, repeatable manner in all environments.
- Establish a Rigorous Change Management Process:
A rigorous change management process must be maintained during change management operations. For example, new releases should only be deployed after process.
- Define Security Requirements:
Engage the business owner to define security requirements for the application. This includes items that range from the whitelist validation rules all the way to non-functional requirements like the performance of the login function. Defining these requirements up front ensures that security is baked into the system.
- Conduct a Design Review:
Integrating security into the design phase saves money and time. Conduct a risk review with security professionals and threat model the application to identify key risks. The helps you integrate appropriate countermeasures into the design and architecture of the application.
- Perform Code Reviews:
Security focused code reviews can be one of the most effective ways to find security bugs. Regularly review your code looking for common issues like SQL Injection and Cross-Site Scripting.
- Perform Security Testing:
Conduct security testing both during and after development to ensure the application meets security standards. Testing should also be conducted after major releases to ensure vulnerabilities did not get introduced during the update process.
- Harden the Infrastructure:
All components of infrastructure that support the application should be configured according to security best practices and hardening guidelines. In a typical web application this can include routers, firewalls, network switches, operating systems, web servers, application servers, databases, and application frameworks.
- Define an Incident Handling Plan:
An incident handling plan should be drafted and tested on a regular basis. The contact list of people to involve in a security incident related to the application should be well defined and kept up to date.
- Educate the Team on Security:
Training helps define a common language that the team can use to improve the security of the application. Education should not be confined solely to software developers, testers, and architects. Anyone associated with the development process, such as business analysts and project managers, should all have periodic software security awareness training.
Security is one of the non-functional needs which should be given adequate impetus while deploying a software solution system or tool that is used for commercial or governmental purposes.
There is no silver bullet when it comes to achieving a full-proof and totally secure software solution. Sticking to these security fundamentals will certainly help you garner the great impact on the overall quality and security of your software solution.