Sharks in the Moat
Page 25
1) It forces the developer to think things through before laying down code.
2) It ensures that modules are implemented with high cohesion and loose coupling.
3) It produces a series of tests that can be quickly run prior to code check-in that will reveal issues in the earliest stages of development.
4) It allows a team to quickly find the source of pesky bugs, as unit testing points directly to the offending module.
Overall, a team will be able to generate better code in a shorter timeframe relative to delivering the entire project. It is important to note the ‘relative’ term here, as it will increase development time upfront, but more than make up for it later when fewer bugs are generated and the ones that are found are easier to fix. It requires a good deal of discipline on the developer’s part to properly implement decent unit tests.
Unit testing also discourages the use of hard-coding values, as unit tests should inject any dependencies directly into the module. While we won’t go into dependency injection in this book, it is a crucial capability that every development team should understand and execute if proper unit testing is to be achieved.
Another win for unit testing is the ability to allow modules to be developed even if the code on either side of the module has not yet been completed. For example, let’s suppose that we are building the checkout process for an online store. In our design, we have a Cart object that invokes a ShippingRate object, a CurrencyConversion object, a DiscountCode object, and a Tax object. The developer tasked with creating the ShippingRate object is at a clear disadvantage as neither the Cart object is ready which would invoke her class, and neither is the CurrencyConversion object ready, which her code would consume. Fortunately, she has chosen to create a test harness which will play the part of the Cart object so that her own code can be tested – this harness is called a driver. Furthermore, she can mock up what the CurrencyConversion object will eventually look like on her own and call it from her own ShippingRate code – this temporary object is called a stub. She is then able to complete her own class using only the driver and stub as long as the actual Cart and CurrencyConversion classes implement the same interfaces as her driver and stub. Drivers and stubs can also be used when dealing with third-party components that require other dependencies not yet understood.
Other advantages for unit testing include the following:
It validates functional logic.
It makes it easier to discover inefficiencies and complexity that more complex code could hide, as unit testing executes code in smaller modules.
It can enhance automated testing processes by integrating directly with source control build tools. For example, we can configure our source control and build environment to execute all unit tests for each check-in and refuse to accept the changes if any test fails.
It encourages collective ownership of the shared code base, as it highlights developer-caused issues early before the product is deployed.
Software Vulnerabilities and Mitigation Options
In this book, we are focusing on secure code, not just coding in general. But, when discussing the level of security as implemented within our code, how do we quantify such a thing? After all, we all have our own ideas of the riskiest attacks and which ones our code base is most vulnerable to. This is the point at which we can always falls back on our trusty RASQ – the relative attack surface quotient. Let’s quickly summarize the primary contributors to the attack surface:
The amount of code and services that are executed by default.
The volume of code that can be accessed by untrusted users.
The extent of damage encountered when code is exploited.
RASQ should be calculated before and after coding activities. Because we have the chance to reduce RASQ by how we implement code, this entire section covers defensive coding practices.
Almost all technological security breaches are a direct result of software weakness. The leading root causes of such attacks are design flaws, coding issues, and improper configuration and operations. The number one root cause? Software coding weaknesses. This information had been culled from vulnerability databases that collect such information and collate the breach to the underlying root cause. In addition to the name of the vulnerability these databases include how exploitable the weakness is, the potential impact, and how to mitigate the vulnerability. Following is a list of the most commonly used vulnerability databases.
The National Vulnerability Database, or NVD, is owned by the U.S. government and uses something called the Security Content Automation Protocol, or SCAP. This approach enables the automation for vulnerability management, security measurement and compliance.
The US Computer Emergency Response Team, or CERT, has a Vulnerability Notes Database that has the primary goal of reducing security risks in software before and after deployment. This is applied by focusing on discovering vulnerabilities before deployment and mitigating vulnerabilities after deployment.
The Open Source Vulnerability Database is an independent database created by the security community.
Common Vulnerabilities and Exposures, or CVE, is a free international dictionary of publicly known vulnerabilities and exposures.
The OWASP Top 10 List not only lists the most common issues but views them from an organizational risk perspective. Figure 75 shows the top weaknesses discovered in 2017.
Risk
Description
A1 – Injection
Injection flaws, such as SQL, NoSQL, OS, and LDAP injection, occur when untrusted data is sent to an interpreter as part of a command or query. The attacker’s hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization.
A2 – Broken Authentication and Session Management
Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or to exploit other implementation flaws to assume other users’ identities temporarily or permanently.
A3 – Cross-Site Scripting (XSS)
Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, and PII. Attackers may steal or modify such weakly protected data to conduct credit card fraud, identity theft, or other crimes. Sensitive data may be compromised without extra protection, such as encryption at rest or in transit, and requires special precautions when exchanged with the browser.
A4 – Insecure Direct Object References
Many older or poorly configured XML processors evaluate external entity references within XML documents. External entities can be used to disclose internal files using the file URI handler, internal file shares, internal port scanning, remote code execution, and denial of service attacks.
A5 – Security Misconfiguration
Restrictions on what authenticated users are allowed to do are often not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access other users' accounts, view sensitive files, modify other users’ data, change access rights, etc.
A6 – Sensitive Data Exposure
Security misconfiguration is the most commonly seen issue. This is commonly a result of insecure default configurations, incomplete or ad hoc configurations, open cloud storage, misconfigured HTTP headers, and verbose error messages containing sensitive information. Not only must all operating systems, frameworks, libraries, and applications be securely configured, but they must be patched and upgraded in a timely fashion.
A7 – Missing Function Level Access Control
XSS flaws occur whenever an application includes untrusted data in a new web page without proper validation or escaping or updates an existing web page with user-supplied data using a browser API that can create HTML or JavaScript. XSS allows attackers to execute scripts in the victim’s browser which can hijack user sessions, deface web sites, or redirect the user to malicious sites.
> A8 – Cross-Site Request Forgery (CSRF)
Insecure deserialization often leads to remote code execution. Even if deserialization flaws do not result in remote code execution, they can be used to perform attacks, including replay attacks, injection attacks, and privilege escalation attacks.
A9 – Using Components with Known Vulnerabilities
Components, such as libraries, frameworks, and other software modules, run with the same privileges as the application. If a vulnerable component is exploited, such an attack can facilitate serious data loss or server takeover. Applications and APIs using components with known vulnerabilities may undermine application defenses and enable various attacks and impacts.
A10 – Unvalidated Redirects and Forwards
Insufficient logging and monitoring, coupled with missing or ineffective integration with incident response, allows attackers to further attack systems, maintain persistence, pivot to more systems, and tamper, extract, or destroy data. Most breach studies show time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring.
Figure 75: The OWASP Top 10
The Common Weakness Enumeration, or CWE, is an international list of vulnerabilities providing a common language for describing architectural, design and coding weaknesses. The CWE/SANS Top 25 most dangerous programming errors are shown in Figure 76.
Rank
ID
Name
1
CWE-89
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
2
CWE-78
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
3
CWE-120
Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
4
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
5
CWE-306
Missing Authentication for Critical Function
6
CWE-862
Missing Authorization
7
CWE-798
Use of Hard-coded Credentials
8
CWE-311
Missing Encryption of Sensitive Data
9
CWE-434
Unrestricted Upload of File with Dangerous Type
10
CWE-807
Reliance on Untrusted Inputs in a Security Decision
11
CWE-250
Execution with Unnecessary Privileges
12
CWE-352
Cross-Site Request Forgery (CSRF)
13
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
14
CWE-494
Download of Code Without Integrity Check
15
CWE-863
Incorrect Authorization
16
CWE-829
Inclusion of Functionality from Untrusted Control Sphere
17
CWE-732
Incorrect Permission Assignment for Critical Resource
18
CWE-676
Use of Potentially Dangerous Function
19
CWE-327
Use of a Broken or Risky Cryptographic Algorithm
20
CWE-131
Incorrect Calculation of Buffer Size
21
CWE-307
Improper Restriction of Excessive Authentication Attempts
22
CWE-601
URL Redirection to Untrusted Site ('Open Redirect')
23
CWE-134
Uncontrolled Format String
24
CWE-190
Integer Overflow or Wraparound
25
CWE-759
Use of a One-Way Hash without a Salt
Figure 76: The CWE/SANS Top 25 Most Dangerous Programming Errors
The Top 25 programming errors can be grouped into three different categories:
Insecure interaction between components, represented by 6 errors on the top 25 list and shown in Figure 77. These weaknesses are related to insecure ways in which data is sent and received between separate components, modules, programs, processes, threads, or systems.
Risky resource management, represented by 11 errors on the top 25 list, shown in Figure 78. The weaknesses in this category are related to ways in which software does not properly manage the creation, usage, transfer, or destruction of important system resources.
Porous defenses, represented by 8 errors on the top 25 list, shown in Figure 79. The weaknesses in this category are related to defensive techniques that are often misused, abused, or just plain ignored.
1
CWE-89
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
2
CWE-78
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
4
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
9
CWE-434
Unrestricted Upload of File with Dangerous Types
12
CWE-352
Cross-Site Request Forgery (CSRF)
22
CWE-601
URL Redirection to Untrusted Site ('Open Redirect')
Figure 77: CWE Top 25 - Insecure interaction between components
Rank
ID
Name
5
CWE-306
Missing Authentication for Critical Function
6
CWE-862
Missing Authorization
7
CWE-798
Use of Hard-coded Credentials
8
CWE-311
Missing Encryption of Sensitive Data
10
CWE-807
Reliance on Untrusted Inputs in a Security Decision
11
CWE-250
Execution with Unnecessary Privileges
15
CWE-863
Incorrect Authorization
17
CWE-732
Incorrect Permission Assignment for Critical Resource
19
CWE-327
Use of a Broken or Risky Cryptographic Algorithm
21
CWE-307
Improper Restriction of Excessive Authentication Attempts
25
CWE-759
Use of a One-Way Hash without a Salt
Figure 78: CWE Top 25 - Risky resource management
Rank
ID
Name
3
CWE-120
Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
13
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
14
CWE-494
Download of Code Without Integrity Check
16
CWE-829
Inclusion of Functionality from Untrusted Control Sphere
18
CWE-676
Use of Potentially Dangerous Function
20
CWE-131
Incorrect Calculation of Buffer Size
23
CWE-134
Uncontrolled Format String
24
CWE-190
Integer Overflow or Wraparound
Figure 79:CWE Top 25 - Porous defenses
Now it’s time to address the most common vulnerabilities head-on. While we could approach them using the CWE categories, it is a little easier to categorize them from the end-user’s point of view into
four groups – client, network, system and server code, as shown in Figure 80. Note that the following discussions do not represent a comprehensive list of all possible weaknesses, but rather the most important ones that the development team can directly impact through coding.
Another note – any developer should read the Testing role as well, as it discusses some additional steps on preventing various attacks such as injection by performing input validation.
Client Vulnerabilities
Client vulnerabilities are found directly within the application an end-user interacts with. For all practical purposes with modern applications, this will be represented by a browser. But it should be simple to envision each vulnerability as implemented in a native mobile or desktop app as well.
International Issues
When software must be written to support more than one language, culture or geographical region, it opens a whole different world that seems strange to someone who has never had to deal with such a thing before. Challenges can be grouped into two categories – legal and technological.
Figure 80: The Four Categories of Development Vulnerabilities
Legal requirements must be addressed to prevent the application from violating regulations. For example, full-time in France often means a 30-hour work week, while in the US it is a 40-hour week. The software must be able to accommodate both if it is designed to work in both locations.