0% found this document useful (0 votes)
17 views31 pages

Secure Coding Principles Overview

The document introduces principles of secure coding, emphasizing defensive programming, the attacker’s mindset, and the importance of error handling and testing for security vulnerabilities. It distinguishes between robustness and security, highlighting that robust programs may not always be secure, and outlines key concepts such as privileges and protection domains. Additionally, it discusses the principles of least privilege and fail-safe defaults, advocating for strict access controls and secure failure mechanisms in software development.

Uploaded by

68378d7d2f
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views31 pages

Secure Coding Principles Overview

The document introduces principles of secure coding, emphasizing defensive programming, the attacker’s mindset, and the importance of error handling and testing for security vulnerabilities. It distinguishes between robustness and security, highlighting that robust programs may not always be secure, and outlines key concepts such as privileges and protection domains. Additionally, it discusses the principles of least privilege and fail-safe defaults, advocating for strict access controls and secure failure mechanisms in software development.

Uploaded by

68378d7d2f
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

‫بسم هللا الرحمن الرحيم‬

‫اللهم ال سهال اال ما جعلته سهال‬

Principles of Secure Coding Course Introduction

Module1

Key points include:


1. Defensive Programming: Secure programming extends basic principles from
introductory programming, such as checking bounds and inputs, assuming errors
will occur, and handling them properly.
2. Attacker’s Mindset: Developers should think like attackers, considering how
someone might exploit their program to disrupt it or the system it runs on.
3. Error Handling: Secure programs can manage both intentional attacks and
unintended errors, improving overall robustness.
4. Testing Focus: Unlike general testing, which prioritizes common use cases,
security testing focuses on edge cases where vulnerabilities are likely to occur.
5. Understanding the Environment: Programs interact with systems, people, and
devices. A lack of awareness about the operating environment can lead to
vulnerabilities.
6. Procedures Matter: Even the best-written program can fail if improperly
installed or configured, highlighting the importance of procedural security.
7. Robust vs. Secure: Robustness is a prerequisite for security, but it does not
guarantee it. Secure programs must first be robust and then address specific
security concerns.

What is Secure Programming?


1. Definition:
Secure programming focuses on creating software that adheres to both robustness
and security principles, ensuring it works as intended without vulnerabilities that
attackers can exploit.

1|Page
2. Difference Between Robustness and Security:
o A robust program handles errors and prevents unintended behaviors.
o A program is secure if it prevents unauthorized actions or breaches,
depending on the policies and procedures in place.
o Robustness is essential for security, but a robust program may not always
be secure depending on its context.
3. Context Matters:
o Security is determined by the program, its environment, and the
procedures used.
o Example:
▪ A mathematically proven secure system can still be insecure if
procedural flaws (e.g., no passwords, open internet connection)
exist.
▪ A vulnerable system might remain secure if its usage policies
eliminate potential attack vectors (e.g., never connecting to a
network).
4. Key Concepts:
o Privileges:
Users and programs operate with specific rights (e.g., read, write).
Escalated privileges (e.g., admin or root access) can lead to vulnerabilities
if not managed properly.
o Protection Domain:
This includes all resources a program can access and actions it can
perform. Minimizing the protection domain limits potential damage from
attacks.
Secure programming combines careful coding, understanding of the operating
environment, and strict adherence to procedures to prevent vulnerabilities and
ensure system integrity.

2|Page
Aspect Explanation

Writing software that conforms to security policies,


Secure
prevents unauthorized actions, and protects against
Programming
vulnerabilities.

Robust Ensures the program handles errors gracefully without


Programming crashing or behaving unexpectedly.

- Robust programs handle errors but may not address


Difference
security issues.

- Secure programs must be robust and also prevent security


violations.

- Privilege: Rights or permissions a user/program has (e.g.,


Key Concepts
admin/root privileges).

- Protection Domain: The resources and actions a program


can access or perform.

Programming - Buffer overflows: Writing outside memory bounds can


Issues lead to crashes or unauthorized access.

- Assumptions: Programmers make assumptions about


input, output, and the environment, which may cause
vulnerabilities if unexpected cases occur.

- Heartbleed bug: Exploited a buffer underflow to leak


Examples of Risks
sensitive data.

- Electronic voting systems: Vulnerabilities in software can


compromise elections.

Secure programming must account for how the software


Environment
interacts with its environment, including procedures,
Importance
configuration, and usage context.

Development - Waterfall Model: Better for security due to step-by-step


Models reviews.

- Agile Model: Prioritizes speed; security checks are often


done later.

3|Page
Aspect Explanation

Infrastructure Secure programs rely on secure and robust infrastructure,


Dependence such as libraries, compilers, and network services.

Main Idea Details

Non-secure components lead to non-secure systems; even


Security is cumulative
secure components connected improperly may fail.

Shims can mediate communication between modules but may


Use of shims
themselves pose risks if poorly implemented.

Risks of libraries and Reusing libraries inherits their bugs; assumptions about
assumptions environments can lead to vulnerabilities.

Policies define security goals; procedures enforce them. Both


Policies and procedures
must be practical and consider human limits.

Handling unknown Assume potential issues in unknown environments; avoid


environments hardcoding specific policies.

Common issues include trusting the environment, bad


Program vulnerabilities
assumptions, and race conditions.

Assumptions: Always check your assumptions. Think beyond the obvious (out-of-the-box
thinking) and question what you trust.

Non-technical Solutions: Sometimes the easiest solutions are non-technical, as demonstrated


in the case of stopping a hacker.

Vulnerabilities in Documentation: Manuals can reveal implicit assumptions, errors, or


vulnerabilities. For example, checking for contradictions or ambiguities in documentation.

Interactions and Dependencies: Pay attention to how the program interacts with external and
internal components, such as user inputs, network connections, and dependencies like
cryptography.

Critical Program Behaviors: Focus on ensuring programs do what they're supposed to do


(integrity) and properly handle sensitive data, such as passwords.

4|Page
Error Messages: Be cautious with how much information is revealed in error messages, as
overly detailed messages can assist attackers.

Security Assumptions in System Design: Understand the limitations of systems (e.g., root
access in Unix/Linux), and how encryption can be bypassed if the root user is malicious.

Iterative Process: Identifying vulnerabilities is an iterative process, as the environment and


assumptions may change over time.

1. Interaction and Error Handling:

o Modular Design: Network interactions should be handled by dedicated modules,


isolating the network checks and ensuring higher levels handle only error cases.
This keeps error handling and validation separate from the main program flow.

o Error Propagation: When an error occurs, it should be detected and reported by


the relevant module (e.g., network or input module). The main program should
only deal with higher-level errors once they're confirmed.

2. Reference Monitor Concept:

o Modules should ensure proper security checks when accessing sensitive


resources, similar to the reference monitor model that verifies every security-
related operation.

3. Input Validation:

o Special attention should be paid to validating inputs, especially if they are


commands or instructions, and ensuring that the execution context is properly
constrained, particularly in privileged programs.

o Validate user identity and handle naming conflicts (e.g., users with the same
name, or websites masquerading as others).

4. Common Security Vulnerabilities:

o Buffer Overflows and Race Conditions are common issues in system


vulnerabilities.

o Error Handling in Privileged Programs: If the cause of an error is known,


attempt recovery; otherwise, terminate the program.

o Cryptography: Both its correct implementation and proper use are critical to
avoid security flaws.

5. Library Function Usage:

o Be cautious about the behavior of library functions and other programs your code
depends on, especially in handling inputs from the environment, such as
environment variables, which can be exploited if not handled properly.

6. Language-Specific Issues:

5|Page
o Pay attention to type checking and potential mismatches (e.g., signed vs.
unsigned numbers) to avoid errors in program execution.

7. Policies and Procedures:

o System Isolation: Assumptions regarding system isolation (e.g., "never


connected to the Internet") need careful validation. Steps like removing all
networking hardware ensure adherence to policies, but be cautious of
workarounds like USB sticks with wireless capabilities.

8. Thought Exercise:

o Consider assumptions such as ensuring a system is never connected to the


Internet. In addition to preventing network connections, you must also ensure
that any form of networking, like USB sticks with wireless capabilities, is
blocked.

1. Where to Look for Vulnerabilities:

o Privilege Changes & Protection Domains: Focus on areas where privileges or


rights are changed, such as network servers or local servers. These are common
places where security vulnerabilities can arise, especially when privileged access
is involved.

o Shared Resources: Pay attention to resources shared between privileged and


unprivileged users, as shared access could lead to unauthorized manipulation.
This can affect availability, confidentiality, and integrity.

2. Network Servers and Authentication:

o Network servers should ideally run with minimal privileges (e.g., as "nobody" on
Linux), reducing the risk of exploitation.

o Servers often authenticate users based on IP address, which is weak security on


its own. A better practice involves checking the DNS to validate the host behind
the IP address.

3. Local Servers:

o Local servers should also limit their environment and be cautious when inherited
from the process that started them, as it could include dangerous configurations.

o The best practice is for servers to wipe the environment and install their own
secure environment before starting.

4. Setuid and Setgid Programs:

6|Page
o Setuid (Set User ID) and Setgid (Set Group ID) programs allow a program to run
with the permissions of the file owner (e.g., root), not the user executing it. These
programs are often exploited if the environment isn't cleaned or validated.

o Manipulating the environment can allow malicious users to escalate privileges or


manipulate the program's behavior.

5. Client-Server Interaction:

o It's a mistake to assume that a client checks the input fully and the server doesn't
need to. If a server doesn't validate incoming data, a malicious client can exploit
vulnerabilities.

o Clients, such as web browsers, should be careful about what information they
send back to the server, including environment variables and cookies, as this data
can be manipulated.

6. The Land Attack Example:

o The Land Attack exploits ambiguities in the TCP handshake by manipulating


source and destination addresses and ports. This attack causes a connection loop
due to mismatched sequence numbers during the handshake, resulting in a lock-
up.

o The ambiguity arises from the RFCs describing the TCP behavior in conflicting
ways, leaving the implementation open to attack.

7. Cryptographic Voting System Assumptions:

o In a cryptographic voting system, the assumptions include:

▪ Uncompromised Website & Browser: The security of the system


depends on the website and the voter’s browser being secure. If the
browser is compromised, the vote could be altered before it reaches the
server.

▪ Anonymous Unique Identifier: The voting system assumes that the


cryptographic identifier is unique and tied to the voter, without exposing
the voter’s identity. However, if someone can trace this identifier back to
the voter, the system’s privacy may be compromised.

7|Page
Summary of Key Security Considerations:

• Always be mindful of the security implications of privilege changes, especially in


network and local servers.

• Shared resources should be tightly controlled to prevent manipulation by unprivileged


users.

• Be cautious with environment handling in Setuid and Setgid programs, as these can be
exploited if improperly configured.

• Both servers and clients need to perform thorough input validation to avoid
vulnerabilities.

• Consider the security of the entire communication flow, including the ambiguities in
protocols like TCP that could lead to attacks like the Land Attack.

• In cryptographic systems, be aware of the assumptions made about the integrity of the
environment and the anonymity of identifiers, as these can impact the overall security and
privacy.

1. Privilege and Privilege Escalation:

• Privileges are not just about special permissions (like Setuid/Setgid). It's also about who
runs the program. For example, if a superuser or sysadmin runs a program, it gets their
high-level privileges.

2. What is an Attack?:

• An attack is anything that tries to break the rules set by the security policy. If it breaks the
rules, the attack is successful; if it doesn't, it's a failure.

Here are the questions with their correct answers structured clearly:

Question 1:

What is the difference between robust programming and secure programming?


Answer:

8|Page
• Robust programming deals with errors whether or not they are a security problem; secure
programming deals with errors that are security problems.

Question 2:

Fill in the blanks with the correct phrases from options below:
Security policies _______ and security mechanisms ______.
Answer:

• Security policies say what is and is not allowed, and security mechanisms enforce the policy.

Question 3:

Consider a program that uses a cryptographic library obtained from a third party. Which of the following is
most likely to be true?
Answer:

• The programmer must take care that all inputs to the library are checked to ensure they match what
the library expects.

Question 4:

When a user tries to log in, she enters a login name and a password. The computer checks that the login name is
that of an authorized user and if not, gives the error message "Bad login name" and requests another name and
password. If the login name is valid, it checks the password and if that does not correspond to the named user, it
gives the error message "Bad password" and requests another password. Which of the following best describes
this procedure?
Answer:

• It is poor security, because a user can tell whether a guessed login name is a valid one.

Question 5:

What are the two key concepts of secure programming?


Answer:

• Privilege and protection.

Question 6:

Which of the following should you do in secure programming?


Answer:

• Checking the input for validity.

Question 7:

Complete the sentence: Buffer overflows are _______ a security problem.


Answer: Sometimes.

9|Page
Module2

1. Introduction to the Principle of Least Privilege (PLP):


o Concept: A subject (process, user, or actor) is given only the rights needed
to complete its task.
o Analogy: "Need to know" – only access what's necessary.
o Example:
▪ A process requiring access to files 1 and 2 will not be granted
access to file 3.
▪ Temporary elevation: A Linux mail handler needs root privileges
to open port 25 but drops them after the task.

2. Introduction to the Principle of Least Authority (POLA):


o Related to PLP but with a subtle distinction:
▪ PLP focuses on permissions (direct actions on objects).
▪ POLA focuses on authority (influence over other subjects and
indirect actions).
o Example: POLA considers whether a subject can control another subject's
interaction with an object.

3. Practical Understanding:
o POLA and PLP are often seen as synonymous, but their differences are
nuanced.
o For most practical purposes, recognizing the two as similar suffices unless
you're a system developer.

4. Application in Systems:
o Question: Do Unix-like systems (e.g., FreeBSD, Linux) or Windows
enforce least privilege?
o This is explored further in exercises, with the principle being a critical
aspect of system security.

10 | P a g e
1. Definition of Fail-Safe Defaults:

o Inspired by Cold War "fail-safe points," where bombers halt unless explicitly instructed
to proceed.

o In computing, this principle ensures:

▪ Default Denial: Deny access by default and grant explicit permissions only
when necessary.

▪ Fail Securely: When a failure occurs, the system must remain secure without
exposing information or granting privileges.

2. Key Aspects of the Principle:

o Default Denial:

▪ Start with "deny, deny, deny" and only explicitly allow permissions.

▪ Example: When an employee leaves, default denial ensures their access is


revoked promptly.

o Secure Failure:

▪ During failures, the system's security should remain intact, matching the security
level before the failure.

3. Practical Example of Fail-Safe Defaults:

o Input sanitization for command-line programs:

▪ Instead of allowing all characters and blocking dangerous ones (e.g., |, $, !), only
permit safe characters like letters, digits, and hyphens.

▪ Advantage: New metacharacters won't cause security issues since only


predefined safe characters are accepted.

o Real-world incident: A server overlooked a newly added metacharacter, leading to


vulnerabilities until patched.

4. Benefit of the Principle:

o Prevents unintended security lapses by ensuring strict and clear rules for granting access
and handling failures.

11 | P a g e
1. Definition of Economy of Mechanism:

o Aligns with the KISS principle: "Keep It Simple Silly."

o Emphasizes simplicity in design, implementation, interfaces, and interactions to enhance


security and usability.

2. Why Simplicity Matters:

o Easier Analysis:

▪ Simple systems are easier to understand, analyze, and debug.

▪ Reduces the likelihood of errors being missed during reviews.

o Simpler Fixes:

▪ Straightforward designs make troubleshooting and fixing issues faster and more
efficient.

o Avoids Confusion:

▪ Complexity may confuse both attackers and legitimate users, but confusion does
not inherently improve security.

3. Application to Interfaces and Interactions:

o Interfaces:

▪ Should be simple, clear, and easy to use to prevent mistakes.

o Interactions:

▪ Must be unambiguous and properly managed to avoid security and functionality


issues.

4. Key Takeaway:

o Complexity often adds confusion, not security. Prioritize simplicity to create secure and
maintainable systems.

1. Definition of Complete Mediation:

o Ensure every access to a resource is checked to confirm that it is allowed.

o Example: When reading a file:

▪ Verify permissions during file opening.

▪ Recheck permissions during every subsequent access (e.g., read commands).

2. Common Violation of the Principle:

o Many systems, like Windows, Linux, and Unix, check permissions only when a file is
opened.

o Once opened, the file handle or descriptor is used without further permission checks,
even if permissions change afterward.

12 | P a g e
3. Key Concept: Capabilities:

o A capability includes:

▪ Object name (e.g., file name).

▪ Rights or permissions (e.g., read, write).

o Possession of a capability grants the ability to perform actions, even if permissions


change later.

▪ Example: A file opened with write permissions remains writable via the
descriptor, even if write permissions are revoked.

4. Key Takeaway:

o For true security, access permissions should be rechecked during every access attempt,
not just at the initial access point.

1. Definition of Separation of Privilege:

o Requires meeting multiple criteria to perform a task, enhancing security.

o Often referred to as defense in depth, similar to a medieval castle with multiple layers of
protection (e.g., moat, outer wall, inner wall, keep, and dungeon).

2. Examples of Separation of Privilege:

o Historical Analogy: Medieval castles requiring attackers to overcome several layers of


defenses.

o Commercial Context: Large checks (e.g., over $100,000) requiring approval from two
individuals.

▪ This specific case is also called separation of duty but follows the same
principle.

3. Technical Example in Linux (SU Command):

o SU (Substitute User):

▪ Allows a user to switch to another user's privileges.

▪ For root (admin) privileges, two conditions must be met:

1. Know the root password.

2. Be a member of the "wheel" group (Group ID 0).

▪ Example of separation of privilege: Satisfying both constraints ensures added


security.

4. Key Takeaway:

o By enforcing multiple layers of verification or criteria, separation of privilege reduces the


likelihood of unauthorized access and strengthens overall system security.

----------------------------------------------------------------------------------------------------------------------------- --

13 | P a g e
1. Principle of Open Design:

o Definition:

▪ Security should not rely on the secrecy of design or implementation.

▪ This principle rejects the idea of "security by obscurity," where security depends
solely on keeping the design secret.

o Important Clarification:

▪ While certain information like passwords or cryptographic keys should be kept


secret, the overall design or implementation should not be concealed.

▪ The goal is for a system to remain secure even if the design or implementation is
discovered.

2. Illustrative Example – DVD Content Scrambling System (CSS):

o CSS Overview:

▪ CSS is an encryption method used to protect DVDs.

▪ The player uses various keys (player key, disc key, and title key) to decrypt
content for playback.

o Security by Obscurity:

▪ CSS was kept secret to prevent cracking.

▪ However, in 1999, a group in Norway created an algorithm compatible with CSS


to play DVDs on Linux systems.

▪ The DVD Copyright Control Association (DCCA) sued to stop distribution, but
when the source code for CSS was submitted in court, it was accidentally made
public.

o Outcome:

▪ The leaked code was downloaded 20,000 times and widely distributed, exposing
weaknesses in CSS.

▪ This case highlights the danger of relying on secrecy for security.

3. Additional Example – Gulf War and Information Aggregation:

o Aggregation of Information:

▪ During the Gulf War, the Associated Press (AP) used publicly available data to
identify the locations of US military bases in Iraq.

▪ This data was initially considered secret but was inadvertently made public.

o Lesson:

▪ Information may leak or be aggregated in unexpected ways, and secrecy alone


cannot ensure security.

14 | P a g e
4. Key Takeaway:

o Open Design Principle:

▪ Security should be robust enough that it doesn't depend solely on keeping


designs or implementations secret.

Least Common Mechanism Principle:

1. Definition:

o The Principle of Least Common Mechanism states that systems should avoid sharing
common resources (such as CPUs, memory, or networks) between users or processes.
Sharing resources can create covert channels, where unintended information can be
leaked between isolated entities.

2. Covert Channels and Side-Channel Attacks:

o Covert Channels: Information can be passed covertly through shared resources. For
instance, manipulating CPU time to encode bits of information.

o Side-Channel Attacks: These attacks exploit system behaviors like power usage or
execution time to gather sensitive information, such as cryptographic keys.

3. Isolation Techniques:

o Virtual Machines: Programs or processes are isolated within a virtual machine that
simulates a separate system. This prevents sharing of underlying resources.

o Sandboxes: A sandbox is a controlled environment that intercepts system calls or alters


the environment to prevent programs from accessing certain resources or communicating
freely with the outside system.

4. Example – Distributed Denial of Service (DDoS) Attack:

o Attack Method: In a DDoS attack, attackers flood a bank's web server with requests,
overwhelming the shared network connection and preventing legitimate users from
accessing the server.

o Principle Connection: The common network channel between the attackers and
legitimate users is the shared resource that makes this attack possible.

o Countermeasure:

▪ Banks can mitigate the attack by isolating malicious traffic from legitimate
users. This can be done by redirecting suspicious traffic to another network or
blocking it at the router level while allowing legitimate connections to proceed.

5. Key Takeaway:

o The principle emphasizes minimizing shared resources to reduce the risk of information
leakage and to prevent attacks that exploit these shared channels. Proper isolation
mechanisms, like virtual machines and sandboxes, are essential for enforcing this
principle.

----------------------------------------------------------------------------------------------------------------------------- ----

15 | P a g e
Least Astonishment:

1. Definition

• Least Astonishment means that security mechanisms should be designed to align with users'
expectations and understanding.

• The goal is to minimize surprise for the user by designing systems that behave in a predictable
and intuitive way.

2. Core Idea

• Security should not confuse the user. Users should understand why something works the way it
does without being surprised or frustrated.

• The system should match the user's mental model of how things should operate.

3. Examples

• Password Example:

o Logging into a system with a username and password is a familiar process. It’s expected
and doesn’t surprise users.

o However, if the system unexpectedly asked for a urine specimen for verification, it
would confuse the user. This violates the principle of Least Astonishment.

• Installation Example:

o Software installation typically asks for simple information, like a serial number. If it
unexpectedly asks for your bank account number, that would be astonishing and break
the user's expectations.

4. Security Mechanisms

• Security mechanisms (like passwords) may add some difficulty or extra steps, but they should
not create unnecessary confusion.

• Users should expect and understand security steps, such as entering a password, as part of
normal behavior.

5. Principle vs. Psychological Acceptability

• Psychological Acceptability: This principle suggests that security mechanisms should not make
access difficult.

• Least Astonishment acknowledges that some difficulty is inevitable for security (like passwords),
but it aims to minimize that difficulty.

6. Applications

• Batch Systems: If a system runs without user interaction and asks for a password in advance, it
doesn't surprise the user.

• Interactive Systems: Asking for a password repeatedly in an interactive system violates Least
Astonishment because it creates unexpected behavior that frustrates the user.

16 | P a g e
7. Conclusion

• The principle of Least Astonishment ensures that security is intuitive and user-friendly, avoiding
unnecessary surprises or confusion.

Summary of Secure Design Principles:

1. Principles of Secure Design:

o Secure design principles should be part of the design and implementation process to
make security effective and usable.

o Without these principles, systems may be either too complex to use or ineffective at
providing security.

2. Understanding the Mechanisms and Environment:

o To successfully apply these principles, you must deeply understand the goals of the
security mechanisms you use.

o You also need to understand the environment in which the system will be used, as this
impacts how security should be implemented.

3. Principles vs. Implementation:

o Principles give you guidelines (what to do) but do not tell you how to do it. The details
of how you apply a principle depend on:

▪ The specific security goal you're trying to achieve.

▪ The context in which the system will be deployed.

4. Design and Analysis:

o A careful design and thorough analysis of the system are crucial to ensuring the security
principles are properly applied.

o The design must consider all aspects of security, making sure the mechanisms work as
intended in the specific environment.

Conclusion:

• Secure design is not just about implementing security features, but about carefully considering
how they will work, why they are needed, and how they fit within the broader system and
environment

17 | P a g e
Principles of Secure Coding - Secure Programming Design Principles - Week 2

Principle Description

Open Design Security should not depend on the secrecy of the design or implementation.

Least Privilege Subjects should have the minimum privileges necessary to perform their tasks.

Economy of Mechanism Systems should be as simple as possible to reduce vulnerabilities.

Complete Mediation Every access to a resource must be checked for authorization.

Fail-Safe Defaults Default configurations should deny access unless explicitly granted.

Multiple conditions should be required before granting access to reduce single


Separation of Privilege
points of failure.

Psychological Security mechanisms should be easy to use and understand to prevent users
Acceptability from bypassing them.

Security mechanisms should behave in an expected manner to avoid user


Least Astonishment
mistakes.

18 | P a g e
Module 3

Robust Code Definition:

Robust Code refers to writing programs that work well and do not break easily. It means the code should
handle mistakes, unexpected problems, or wrong inputs in a way that prevents the program from crashing.

Types of Robust Code Principles:

1. Paranoia: Assume that something could go wrong. Always be cautious and check things carefully.

2. Stupidity: Expect that the user might make mistakes or not know how to use the program. The
program should be able to handle this.

3. Dangerous Implements: Don't let users or programmers change important parts of the program that
could cause problems.

4. Things Can Happen: Even if something seems impossible, assume that future changes might cause
problems. Always check for those situations.

robustness in programming.

summary of key points and what can go wrong with non-robust code, specifically in the context of a
queue implementation in C.

Key Concepts:

• Queue: A structure that follows a Last In, First Out (LIFO) principle. Elements are added and
removed from the end of the queue.

• Queue Operations: Functions like qmanage to create or delete a queue, put to add an element,
and take_off_queue to remove an element.

Issues in Non-Robust Code:

1. Queue Creation/Deletion:

o Malloc Failure: If the memory allocation fails, it could lead to crashes. Not handling the
NULL pointer from failed malloc could cause the program to crash when trying to access
memory.

o Size Overflow: If the size calculation overflows (e.g., very large sizes on a 32-bit
machine), it could cause a situation where malloc receives a size of zero, leading to
undefined behavior.

o Double Free: If the queue pointer is deleted multiple times (without resetting to NULL),
it could cause the program to crash or become vulnerable to attacks (double free
vulnerability).

19 | P a g e
2. Adding/Removing Elements:

o Pointer Errors: If a pointer to the queue is messed up (e.g., the head or count values are
incorrect), operations on the queue might access invalid memory or lead to incorrect
behavior.

o Overflow/Underflow: If the queue is full or empty, it may either overwrite data or try to
access data that doesn’t exist (like accessing an element from an empty queue), both
causing crashes or undefined behavior.

Robust Code Principles:

• Sanity Checks: Ensure that all inputs and operations are checked for validity. For example,
checking whether malloc was successful or checking if the queue is full or empty before adding or
removing elements.

• Error Handling: Properly handle errors like malloc failures, invalid pointers, and invalid
operations (like adding to a full queue or removing from an empty one).

• Memory Management: Always make sure to check whether you’re trying to free a NULL pointer
and prevent double frees.

In a robust version of this code, these issues would be carefully addressed by adding error checks,
validating inputs, and handling unexpected situations gracefully.

---------------------------------------------------------------------------------------------------------------------------

Principle Explanation Example

Assume that nothing is In the queue library, instead of trusting that the caller
Paranoia trustworthy unless it’s created will maintain the queue structure consistently, a token is
by the program itself. passed, and the program validates it before using it.

C programs often face issues like incorrect function


Always assume that if
calls, such as misusing flags or sizes in the qmanage
Stupidity something can be invoked
function. Robust programming involves checking
incorrectly, it will be.
inputs carefully to avoid such mistakes.

The queue’s internal structure (head, size, count) must


Ensure data that should remain not be exposed to the caller to avoid accidental
Dangerous
constant across function calls is modifications. Using a private structure or static
Implements
not accessible externally. elements within functions prevents external changes to
these critical variables.

20 | P a g e
Principle Explanation Example

Defensive programming: In the qmanage function, it’s


Always plan for the unexpected important to check whether memory allocation (malloc)
Can't Happen by anticipating potential errors, succeeded. Even if it's unlikely, it's better to handle
even if they seem impossible. failure cases (like memory overflow or invalid memory)
gracefully.

Define error codes clearly and When a queue operation fails, instead of just returning a
associate descriptive messages generic error code, the system also stores an error
Error Handling
with those codes to make message in a buffer, making it easier for the caller to
debugging easier. understand what went wrong.

Use tokens that ensure a queue A nonce is included in the token to make it unique and
Token reference is valid and prevents ensure that once a queue is deleted, the token associated
Management misuse of a deleted or invalid with it cannot be reused. This prevents problems like
queue. double frees or incorrect references.

In the case of allocating memory for the queue, the


Carefully manage memory
program checks whether malloc succeeded and whether
Memory allocation and deallocation to
the requested size overflows. Similarly, it ensures
Handling avoid crashes or undefined
memory is freed correctly without causing a double free
behavior.
error.

Avoid vulnerabilities caused by When displaying error messages, the library avoids
Format String format string attacks by format string vulnerabilities by ensuring that all format
Protection controlling the format strings strings are controlled within the library itself, not from
internally. user input.

The error message buffer (ERRBUF) is explicitly null-


Buffer
Ensure that buffers are properly terminated to avoid buffer overflows when copying
Overflow
terminated to prevent overflow. strings into it. This ensures that any string copied into
Prevention
the buffer fits within its defined size.

These principles, when applied in coding, help to ensure that the program behaves predictably, is
secure, and avoids common pitfalls like buffer overflows, crashes, or undefined behavior.

21 | P a g e
In this video, the speaker discusses how well parts of a function work together, specifically focusing on
cohesion. The idea is that when a function performs multiple unrelated tasks, its cohesion is low, which can
make the function harder to understand and maintain. High cohesion means that all parts of a function work
toward a single goal, which makes the code cleaner and conceptually simpler. The recommendation is to
break functions with low cohesion into separate functions.

The speaker demonstrates this by introducing a set of functions to work with queues:

1. Create Queue and Delete Queue: These are separated into two functions to avoid confusion and
maintain high cohesion. Each function has a clear, distinct responsibility: creating a queue or
deleting a queue.

2. Put on Queue and Take off Queue: These functions are introduced to interact with the queue.
Instead of passing a pointer to an integer to store the number, Take off Queue returns the integer
directly to avoid the complexity of checking whether the pointer is valid.

The speaker also highlights the design of a queue structure and the token generation process. The token
is generated in a way that avoids errors related to invalid references and ensures that the function behaves
as expected by validating indices and parameters.

Key takeaways from the video include:

1. Simple Interfaces: Even internal functions should have simple and clear interfaces to reduce the
risk of mistakes.

2. Check Everything: It's important to validate all parameters, even those generated internally, to
prevent bugs.

3. Helpful Error Messages: Providing meaningful error messages is essential for debugging and
understanding failures.

4. Use of Asserts: In some cases, using asserts in critical parts of the program helps catch bugs early
by immediately terminating the program if an inconsistency is detected.

5. Debugging: Always include debugging checks, especially in complex systems, but make them
optional (e.g., using macros) if the environment has space constraints.

This approach emphasizes building reliable, modular, and well-structured code.

This part of the video focuses on queue management and the creation and deletion of queues, drawing
parallels to the fragile library's queue management. The following concepts are highlighted:

Creating a Queue:

1. Finding Space: When a new queue is created, the system checks for available space in the array
of queues. If the array is full, an error message is generated.

2. Allocation: Once space is found, memory is allocated for the queue. The malloc function is used
to allocate the required memory, and failure is handled by checking if the allocation was
successful.

22 | P a g e
3. Generating a Ticket: The ticket for the new queue is generated by calling the previously
discussed Ticket ref routine. If the ticket generation fails, any memory allocated is freed, and the
space in the array is reset to null.

4. Initialization: After successfully generating a ticket and allocating the queue, the queue is
initialized, and the ticket is returned to the caller.

Checklist for Creating a Queue:

• Consistency: Ensure the parameter list is consistent, and avoid passing pointers unless their type
and value can be validated.

• Array Overflow: Always check for potential array overflows and handle them either by reporting
or correcting them.

• System Calls and Library Functions: Never trust that external system or library calls will
succeed; always check their return values to handle failures properly.

Deleting a Queue:

1. Validating the Ticket: When deleting a queue, the system first checks if the provided ticket points
to a valid queue. This is done using the readref function. If the ticket is invalid, an error message is
returned.

2. Freeing Memory: If the ticket is valid, the corresponding queue is identified, its elements are
freed, and the queue reference is set to null. This prevents potential issues by ensuring the queue is
marked as free.

3. Double-Free Prevention: The video emphasizes the importance of avoiding double frees, where
memory is released multiple times. In this case, since the readref function checks the ticket
validity and returns an error if the queue has already been freed, there’s no need for additional
checks to prevent double freeing.

Lessons:

1. Always Validate Data: Ensure parameters refer to valid data structures, and design them to make
validation possible.

2. Clean Up After Deleting: When deleting data, always clean it up by overwriting sensitive
information (like strings) with null bytes or setting pointers to null. This helps prevent errors, as
any later attempts to use the deleted data will either result in an error or crash the program.
Crashing is preferred to continuing with invalid data, as it makes the problem easier to spot and
correct.

In conclusion, the video emphasizes careful management of memory, error handling, and cleaning up after
operations like queue creation and deletion to prevent vulnerabilities and bugs.

23 | P a g e
"Adding to and Removing from Queues" process:

Operation Details

Adding to Queue - Takes a ticket (Queue) and integer (item to add).

- Validates if the ticket corresponds to a valid Queue index.

- Checks if the Queue is full. If full, returns an error.

- If not full, adds the item to the Queue and updates relevant counters.

Removing from
- Takes a ticket and removes the first item in the Queue.
Queue

- Checks if the Queue is empty. If empty, returns an error.

- If not empty, advances the Queue head and returns the item.

Error Handling - For error checks, updates qe_errbuf.

- Ensures disambiguation of negative values from Queue errors by clobbering the


first byte of qe_errbuf.

- If an error occurs, checks the state of qe_errbuf to determine the error.

Why Avoid Passing - Avoid passing pointers to integer variables as it could cause confusion if the
Pointers value is mistakenly interpreted as an error.

Fail-Safe for - If an internal inconsistency occurs, a fallback error message ensures that the
Inconsistency program won't continue with undefined behavior.

This summarizes the process of adding and removing elements from a Queue, along with the error handling
and validation procedures used.

key points from the "Fragile Code" discussion:

Concept Details

Common Problems in
- Passing invalid pointers without validation.
Fragile Code

- Parameters that should be easily distinguishable, to avoid errors if they are


passed incorrectly.

Access to Internal
- Callers should not have access to internal structures.
Structures

24 | P a g e
Concept Details

- Assumptions about users, environments, and parameters can lead to security


Security Problems
vulnerabilities.

- Errors are harder to track down, making debugging and fixing more difficult.

Non-Security Problems - Maintenance becomes more complicated.

- Accidental errors are more likely in fragile code.

Robust Programming - Pay attention to basic programming principles.

- Handle both deliberate and unintentional mistakes in code.

- Use information hiding to protect internal details.

- Follow "can't happen" design principles, but be aware that unexpected cases
can occur.

Overflow Detection
- Overflow in C cannot be easily detected using simple multiplication checks.
Challenge

Example of Incorrect - Multiplying two numbers (e.g., 70 and 70) might produce a result that is larger
Overflow Check than both numbers but still overflows.

- Use the maximum representable integer (maxint) and check if multiplying the
Correct Way to Detect
numbers will exceed it by dividing maxint by one multiplier and comparing
Overflow
with the other.

This table provides a concise overview of the issues in fragile code and the best practices for avoiding
them.

25 | P a g e
26 | P a g e
27 | P a g e
28 | P a g e
Module4

What Are Formal Methods?

• Formal methods are ways to prove that a program works correctly using mathematics or logic.
This helps ensure the program does what it is supposed to do without errors.

• Think of it like a test that checks if a program is correct by following strict rules.

How Do Formal Methods Work?

1. First, you define what the program should do using very clear rules. These rules are written in a
special language that uses math or logic.

2. Second, you design the program and make sure it follows those rules.

3. Third, you build the program and check that it matches the design.

If everything is done correctly, the program should work as expected.

Key Lessons from Formal Methods

• It's very important to clearly state what you want the program to do.

• You need to check that all the goals are complete. Don't leave anything out.

• You also need to understand the environment the program runs in (like how it connects to other
systems or uses data).

Example: Login Program

A login program has a few important tasks:

• Check if the user is authorized (correct password).

• Change the program's access level so the user can't do admin tasks unless they're allowed.

• Keep a log of who logged in, but never store the password (for security).

Problems with Code (Example)

• If the program gets its information from the wrong place, like letting the user change how the
program checks the host name, it can be hacked.

• Another mistake is a flag in the login system that skips authentication (a user could misuse it to
get admin access).

Checklist for Safer Code

1. Always ask: Where is the data coming from (like the environment or users)? Is it safe?

2. Check if library functions work as expected.

3. Make sure to follow documentation carefully to avoid mistakes.

29 | P a g e
Conclusion

Formal methods help make programs safer and more reliable by proving they do what they’re supposed to.
But, you also need to understand how your program interacts with other systems and check everything
carefully to avoid mistakes.

summary of how HDM (Hierarchical Decomposition Methodology) and formal methods apply to the
login program:

What is HDM (Hierarchical Decomposition Methodology)?

• HDM is a structured way to design programs, breaking them down into smaller pieces, or
modules, in a top-down manner.

• You start with a high-level goal and then break it down into smaller, manageable tasks, making
sure each module does one thing well.

Applying HDM to the Login Program

1. Define Goals: For the login program, the goals are:

o Authenticate the user.

o Change system information to match the user’s identity.

o Update logs.

o Start a command interface (like a shell).

2. Break Down Tasks:

o Authentication: First, get the user’s details, then compare them with stored data to check
if they are correct.

o Changing User Info: Change the system’s user and group data to match the user’s ID.

o Updating Logs: Open, write to, and close the log file.

o Starting Shell: Get the appropriate shell (command line interface) for the user and start
it.

Formal Methods in the Login Program

• In formal methods, you define assumptions and prove that each part of the program works
correctly based on those assumptions.

• For the login program, here’s an example of assumptions:

30 | P a g e
o Preconditions:

▪ Check that environment variables don’t exceed a safe size (1,024 characters).

▪ Ensure no empty environment variables or ones that shouldn’t be exported.

o Postconditions:

▪ After exporting the environment variables, ensure they are correctly added to the
system list.

Key Lessons for Writing Secure Programs

1. Know Your Assumptions: Always check the assumptions you make about inputs and
environment. Don’t rely on things you haven’t verified.

2. Check Preconditions and Postconditions: Before and after each operation, make sure everything
is in the correct state.

3. Use Simple and Clear Code: Break down your program into small modules that do one thing
well (high cohesion). This keeps the code simple, understandable, and easier to debug.

4. Understand Library Functions: Be aware of what library functions do and don’t do, and always
check their documentation.

5. Handle Errors and Special Cases: Ensure your program handles special cases and errors, like
checking if a string fits in a buffer or if memory allocation succeeds.

Conclusion

Using formal methods like HDM and checking assumptions, preconditions, and postconditions can help
you design more secure and reliable programs. It’s about breaking down complex tasks into smaller,
manageable parts and validating each part to make sure it works correctly.

• Importance of Secure and Robust Coding: You learned why it's crucial for programs to be secure and robust. A lack of
security can lead to vulnerabilities, while poor robustness can cause the program to fail in unexpected ways.
• Identifying Non-Robust Code: You gained the ability to spot non-robust code and understand how to improve it. This
includes recognizing potential security flaws and weaknesses in program design.
• Principles of Secure Programming: You studied the foundational principles behind secure programming, including
methods to prevent vulnerabilities from being introduced into code.
• Transforming Poorly Written Code: You learned how to take poorly written, insecure code and improve it, making it
more secure and robust in the process.
• Understanding Formal Methods: You were introduced to formal methods and learned how to use mathematical reasoning
and verification techniques to ensure that the code works as intended.
• Contextualizing Secure Programming: Secure programming is not just about fixing bugs; it's also about following good
programming practices and ensuring that the code is aligned with security standards and efficient design.
• Design and Implementation: You explored both design and implementation aspects of secure coding. You now have an
understanding of how to integrate security during the design phase and how to implement it effectively in the code.
• Security Risks and Solutions in Common Languages: In future courses, you'll focus on specific security risks in
common programming languages like C#, C++, and Java and how secure coding practices can mitigate these risks.

31 | P a g e

You might also like