Skip to content

Commit

Permalink
Merge pull request #280 from turingschool/mm-security-concerns
Browse files Browse the repository at this point in the history
Security Concerns
  • Loading branch information
memcmahon authored Aug 30, 2023
2 parents 61f9e05 + 3f19356 commit 26ce18e
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 1 deletion.
Binary file added assets/images/module4/week4/ManageUserSecrets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/module4/week4/appsettings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/module4/week4/hashImage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion module4/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ In Module 4, students will continue to expand their knowledge of MVC and learn t

### Week 3
* Maintaining State: [Prep](./preparation/Week2/MaintainingState) | [Lesson](./lessons/Week2/MaintainingState) | [Lab](./labs/Week2/MaintainingState)
* Security Concerns
* Security Concerns: [Lesson](./lessons/Week3/SecurityConcerns) | [Lab](./labs/Week3/SecurityConcerns)
* [PD: Coffee Chats](./lessons/Week3/CoffeeChatPD)

### Week 4
Expand Down
77 changes: 77 additions & 0 deletions module4/labs/Week3/SecurityConcerns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
layout: page
title: Security Concerns Lab
---

<section class='call-to-action' markdown='1'>

Encourage students to reach out to each other during this lesson. If they complete it, they will be almost there on implementing authorization; we don't need them to get through the whole thing, but it would be good to wrap up with a short discussion of how we would compare two digests (database value to user input).

</section>

## Implementing Security Measures

In the lesson today, we discussed concepts. Now, we are going to put these concepts into practice! Open your MVC Message Logger application (the mod3 project). Add the following features:

### Remove Connection Strings

Using either secrets management or environment variables, remove the database connection string from your application.

_Make sure that you run your application to make sure that it still works!!_

✅Write up an explanation of the steps you took to achieve this, and send it to your instructors!

### Hashing Data

Update your application to:

* Include a password on the user model
* When a user is created, the password should be stored as a digest in the database
* Ask for a user's password when they try to log in
* They should only be able to add new messages if they provide a matching password

You can use these user stories to help guide the implementation:

```
As a User
When I visit '/users/new'
Then I see a form to create a new user with a name, username, and password
```

```
As a User
When I Complete the form
Then I am redirected to the new user's page
And I can create messages for that user
```

✅Send a screenshot of the controller action that creates a user to your instructors!

```
As a User
When I visit '/users'
And I click on 'Log In'
Then I am taken to '/users/<username>/login'
```

```
As a User
When I visit 'users/<username>/login'
Then I see a form asking for a password
When I enter the password for that user
Then I am redirected to that user's page
And I can create messages for that user
```

```
As a User
When I visit 'users/<username>/login'
Then I see a form asking for a password
When I enter an incorrect password for that user
Then I am redirected back to '/users'
```

✅Reach out to another member of the cohort for some code-review!

231 changes: 231 additions & 0 deletions module4/lessons/Week3/SecurityConcerns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
---
layout: page
title: Security Concerns
---

## Learning Goals
* Understand some security concerns of web development
* Implement hashed data storage
* Implement secrets management

## Data Security on the Web

Throughout your time at Turing, our applications have been relatively safe - our databases and servers live only on our machines and don't have any sensitive data associated with them. When you work on a dev team, that will not be the case; the applications that you work on locally will be **deployed** to the public internet. When an application is deployed, it means that the safety of our local machine is gone - our database and the server running our app has to be housed somewhere else... on the internet 😱

The bad news: the internet is a dangerous place. Fortunately, we have some tools that developers can use to help lessen the danger of security breaches. Today we are going to discuss some of the most common strategies developers use to protect data - this is not a complete list, but will get you thinking about the kinds of questions we need to answer when securing our applications!

<section class='call-to-action' markdown='1'>

### Gallery Walk

We are going to create a Gallery of Security. You will be assigned one of the topics listed below, and have 10 minutes to research on your own. Then we will organize into groups, and your groups will have 20 minutes to create a slide (one single slide) that introduces this topic to the rest of the cohort.

* Authentication/Authorization and API keys
* API Rate Limiting
* Overpost Prevention using Data Transfer Objects (DTOs)
* Preventing SQL Injection

</section>

<section class='instructor-notes' markdown='1'>

Here are some key points we want students to get for each topic above:

* Authentication/Authorization and API keys
* In order to secure data, applications will verify that you are who you say you are (authentication), and may provide additional data based on what role you have in an organization (authorization). In many applications, this is done with a login system, where current user is stored in a session. With API calls, this is generally achieved with API keys, rather than a login system.
* API Rate Limiting
* Many APIs will limit the number of requests that can be made from a specific client. This limit could be a hard number, like no more that 1000 requests. Or, it could be a time-specific rate, like only 5 requests per minute.
* This helps prevent servers from being overwhelmed, and discourages continuous data scraping.
* Overpost Prevention using Data Transfer Objects (DTOs)
* If we have resources in our database with sensitive properties (like user ssns), we can use a DTO as a public-facing resource.
* A DTO only exposes certain properties of a model class, so that there is less danger of an API call retrieving or resetting sensitive data.
* Preventing SQL Injection
* Un-secured html forms, and their corresponding controller actions could be susceptible to someone inputting SQL queries into a text input. This is a problem if you are taking user-input and making direct SQL queries with it. Using an ORM like EntityFramework _helps_ prevent this.

</section>

## Implementing Security Measures

In addition to the topics you all just researched, developers also must consider the sensative data we _need_ in our applications: sensitive data that make our application work, and sensitive user data.

Data that makes are application work are things like our database user and password. Up to now, we have used a generic user and password so that when we push our code to github we are not exposing a personal password (like the one you use for your email, instagram, etc*). We can use **environment variables and secrets management** to prevent pushing this information to remote repositories.

If our application has users, we may need to store _their_ passwords or other sensitive data. We can use **data hashing** to store sensitive data more securely.

*You should probably use different, randomized passwords for every account 😬

### Environment Variables

Let's assume we are working on an application that has a database connection. When we are developing the application, we are connecting to the database on our local machine; but, when we deploy the application to the web, we will connect to a database stored somewhere else (a different computer). This means there are two **environments** that our application can work in: development and production (deployed). Each environment will have its own database connection string, set in an environment-specific appsettings.json:

<img src="/assets/images/module4/week4/appsettings.png" style="width: 30%;">

```
// appsettings.Development.json
"ConnectionStrings": {
"GoodBooksMvcDb": "Server=localhost;Database=GoodBooksMvc;Port=5432;Username=postgres;Password=password123"
}
```

```
// appsettings.Production.json
"ConnectionStrings": {
"GoodBooksMvcDb": "Server=<THE ADDRESS OF OUR PROD SERVER>;Database=GoodBooksMvc;Port=5432;Username=superAdmin;Password=J#7kL$r9T*qP2@5Z"
}
```

We _could_ keep track of all of our connection strings in the application, but that opens us up to security risks. Because our application is deployed on the web, we do not want to record the database configuration anywhere public (like github). So, we can use **environment variables** instead.

Environment Variables are stored globally on our machines. Once an environment variable is created, it is available from nearly anywhere on our computer; this means that multiple programs could use the same environment variables.

With an [environment variable set up](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3), we can remove the connection string configuration in our appsettings.json, and get the connection string directly from the environment.

```c#
builder.Services.AddDbContext<GoodBooksMvcContext>(options =>
options.UseNpgsql(Environment.GetEnvironmentVariable("GOODBOOKS_DBCONNECTIONSTRING")).UseSnakeCaseNamingConvention());
```

**Warning** After creating environment variables, you will want to re-start visual studio before running any database commands!

<section class='instructor-notes' markdown='1'>

It is okay to show the environment variable setup, but we can let students know that we don't expect them to do this - we will prefer secrets management.

</section>

### Secrets Management

Another solution to the problem of needing sensitive data for our applications to run is **Secrets Management**. Similar to environment variables, this strategy allows us to move the storage of sensitive data _outside_ of our project directory; outside of the range of our git tracking!

In Visual Studio, managing secrets is fairly straightforward. You can add project specific secrets in the project menu:

<img src="/assets/images/module4/week4/ManageUserSecrets.png" style="width: 60%;">

This will open a new file - secrets.json. Here, you can create key/value pairs for data that you need to keep ... secret ...

```json
// secrets.json
{
"GOODBOOKS_DBCONNECTIONSTRING": "Server=localhost;Database=GoodBooksMvc;Port=5432;Username=postgres;Password=password123"
}
```

Using the Secrets Manager, you can call keys directly from `builder.Configuration`.

```c#
builder.Services.AddDbContext<GoodBooksMvcContext>(options =>
options
.UseNpgsql(builder.Configuration["GOODBOOKS_DBCONNECTIONSTRING"]
.UseSnakeCaseNamingConvention());
```

The secrets.json file is stored on your local machine, outside of the project file structure. In your .csproj file, there will now be a unique identifier that the project uses to locate the file.

```
// GoodBooksMvc.csproj
<PropertyGroup>
...
<UserSecretsId>e20e7f2a-cb30-4dd4-8139-ed66697eb566</UserSecretsId>
</PropertyGroup>
```

<section class='instructor-notes' markdown='1'>

For the next discussion, we want to make sure students understand that storing these variables on your computer (either in secrets, or in env variables) still has risks - you might need to send this information via slack/email/post-it. They should leave the lesson knowing that there are cloud-based services that will perform similar functions, but in a way that teams can access the _same_ variables: AWSSecrets, AzureKey, etc...

</section>

<section class='call-to-action' markdown='1'>

In small groups, discuss some pros and cons of using:
* Environment Variables
* Secrets Management
* Keeping all necessary data _in_ your project

</section>

### Hashing Data for Storage

We sometimes need to store sensitive user data in our database. For example, we might need to store passwords. It would be too much of a security risk to store those passwords exactly as a user enters them; we can use a strategy called **Hashing** to transform meaningful data into a meaningless string of characters.

<img src="/assets/images/module4/week4/hashImage.png" style="width: 80%;">

[From Wikipedia](https://en.wikipedia.org/wiki/Hash_function): “A hash function is any function that can be used to map data of arbitrary size onto data of a fixed size”.
In the image above, each name is mapped to a number. Where two names are assigned to the same number we have a **collision** (this is bad). In this example, every name is matched to a two digit number; there are only so many two digit numbers, so it is highly likely that we will have a collision. In production-level hash functions, data is assigned to a much longer sequence of numbers and letters.

There are a number of [common hash function types](https://en.wikipedia.org/wiki/List_of_hash_functions) that are used in modern web development. The one we will use today is SHA256.
<section class='call-to-action' markdown='1'>

Create a new console application and put this code in the `program.cs` file. Run it a few times, and then annotate what each line of code. You will likely need to do some research in order to figure out what each line is doing!

```c#
HashAlgorithm sha = SHA256.Create();

string firstInput = "Hello, World!";
Console.WriteLine("Input: " + firstInput);
byte[] firstInputBytes = Encoding.ASCII.GetBytes(firstInput);
byte[] firstInputDigested = sha.ComputeHash(firstInputBytes);
StringBuilder firstInputBuilder = new StringBuilder();
foreach (byte b in firstInputDigested)
{
Console.Write(b + ", ");
firstInputBuilder.Append(b.ToString("x2"));
}
Console.WriteLine();
Console.WriteLine("Digest: " + firstInputBuilder);

Console.WriteLine("\n\n");

var secondInput = "Howdy";
Console.WriteLine("Input: " + secondInput);
byte[] secondInputBytes = Encoding.ASCII.GetBytes(secondInput);
byte[] secondInputDigested = sha.ComputeHash(secondInputBytes);
StringBuilder secondInputBuilder = new StringBuilder();
foreach (byte b in secondInputDigested)
{
Console.Write(b + ", ");
secondInputBuilder.Append(b.ToString("x2"));
}
Console.WriteLine();
Console.WriteLine("Digest: " + secondInputBuilder);
```

Be ready to share your annotations!

🌶️If you have time, are there ways that we could clean up this code?

</section>

Hashing data is a good way to securely store data, but it is not fool-proof. Let's imagine hack into my application and are able to retrieve all my usershashed passwords. You find that the account with username `boss@example.com`` has this hashed password:

```
16e6b8af370f0d6b6e67c65bb6f4499c01a974f1dcd14a5f9429c6931531e6c4
```

Based on the length of the digest you guess its a SHA256. You know that some users, particularly bosses, are lazy and they do dumb things like re-use their 4-digit ATM pin for their password. But the application required a password of eight digits, so they might have repeated the pin.

If these assumptions are correct, you are close to cracking into this user's account - it might only take you a few minutes of coding to find their password. We can use brute force to find the combination of numbers that produces a matching hash value when run through the same algorithm.

<section class="instructor-notes" markdown='1'>

Depending on time, you could have students try to crack the code, or you could describe the process of brute-force cracking. By trying every combination of numbers, you can try to match the hashvalues of the PIN and the guess.

</section>

To protect against this kind of bad data entry (people using easily guess-able password patterns). Developers use a technique called **salting**. A salt is an extra set of characters appended to any sensitive data before hashing. It gives us longer, less predictable data. Check out [this blog post](https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/) for more info!


### White Hat and Ethical Hacking

Security is a major concern for all technical platforms. If security is a topic that interests you, you could make an entire career out of it. You might hear this career path referred to as White Hat, or Ethical Hacking. Ethical Hackers help companies understand the vulnerabilities that they have, and help them strategize better security. You can think of this side of tech as an arms race between the software developers and the bad people trying to break in. One gets better, then the other gets better. And the white hat hackers are helping the developers!

For more information on current security risks and strategies, explore:
* [OWASP](https://owasp.org/) - an organization that regularly posts about current security threats. They also have some great language-specific cheat sheets!
* [HackTheBox](https://www.hackthebox.com/) - a training space for cyber-security.

0 comments on commit 26ce18e

Please sign in to comment.