Getting started on ASP.NET Core & React - episode 05

Getting started on ASP.NET Core & React - episode 05

Contents

  1. Episode 1 – Introduction
  2. Episode 2 – Backend / Infrastructure
  3. Episode 3 – Frontend Setup
  4. Episode 4 – Data flow
  5. Episode 5 – Tests / Security (you are here)
  6. Episode 6 – It’s your turn
  7. Episode 7 – migrate from ASP.NET Core 1.1 to 2.0

Introduction

First bunch of features are done and it’s time to look at very important matter – security. As long as we create apps only for ourselves we don’t care about it. Sometimes we release one of those applications somewhere on the Internet and we still don’t care about security. Why? We forgot or we’re just not aware of the risks. Second very common scenario – small apps for our neighbors with small local business – every possibility to practice is good,  yep? Especially if someone is going to pay us for that. But there is no time and budget to think about security! Once again we don’t care. We’re going to show you why this kind of thinking is not good. Second part of this episode – tests. How to write applications easy to extend and maintain? Tests play the first role on this matter, so we’re going to cover also this topic.

To-do list for this episode:

  1. Security
  2. Backend tests
  3. Frontend tests

1. Security

As we said in introduction very often, especially when we’re learning, we don’t care about security. We create apps for local businesses. Sometimes we put there small accounts system. Let’s say you can register, login and make some appointment. There is nothing to do even if someone would steal users accounts, right? Everything what he can do there is to make an appointment – it’s not so bad, you can think. So should we care? Answer is of course yes. Why? Even if we couldn’t do anything bad at specific site where we steal account, we can obtain very, very important data – user login and password. I think we can easily say that ~80-90% of people have the same login and account to every site/portal he is using. So we steal account of some small local web site where we can’t do anything more with it, but in some extreme situations we can even login to someones bank account using those credentials (about Facebook account and gmail I’m not even saying).

Security is a very big topic, so we’re going to show just part of security issues – the most popular ones.

1. Cross-site Request Forgery (CSRF)

Actually this one is quite interesting, because our app is vulnerable to this attack. First let’s try to perform CSRF attack.

Our SoftwareHouse app is quite small, but we have there Add and Delete project features. Let’s try to use one of this forms to perform attack.

  1. Create index.html files on desktop and paste there below code:

    It’s form almost the same as we’ve got in our Projects/Add.cshtml view. As you can see there is action attribute where we put address fo attacked application. In our case it’s localhost with appropriate port.
  2. Run SoftwareHouse project.
  3. Make sure you’re logged out from application.
  4. Open index.html in browser.
  5. You’re redirected to login page.

Ok, but what happens if we’re logged in? Let’s try this.

  1. Log in to our portal.
  2. From new tab open index.html
  3. New project with “Hacked” name has been added.

Not good. Form from index.html file used cookie saved in browser and thanks to that was able to successfully perform action.

Now let’s imagine that someone prepared similar index.html and put it somewhere on the Internet. He prepared also fake email and sent it to us. We see new email with message that we won 1000$ and to receive money we must click the link. Of course we click and we see blank page. We think, maybe something is broken, never mind, we close the page. We even don’t know what happened in background.

Here you can look at some old examples of vulnerable sites to CSRF attack.

As you can see this attack is not easy, because attacker need some info about attacked application, but it’s possible. He could have access, but with limited permissions and he could try to use this method to obtain administrator permissions or transfer money from one account to another.

How to fix this problem?

In ASP.NET there is prepared mechanism for this.

  1. Go to ProjectsController and add ValidateAntiForgeryToken attribute to Add and Delete methods.
    Add method:

    Delete method:
  2. Next go to Views/Projects/Add.cshtml and Details.cshtml and use AntiForgeryToken helper

    Add.cshtml:

    Details.cshtml:

That’s it. Run project once again and try to perform attack. This time if you open dev tools in console tab you’ll see following error message:

Failed to load resource: the server responded with a status of 400 (Bad Request)

which means that attack failed.

You can think what this AnitForgeryToken is. Let’s go once again to dev tools and look at elements on Add project form. You will see that there is additional hidden input:

It’s result of @Html.AntiForgeryToken helper. It produce some encoded token which is send to controller and AntiForgeryToken attribute just validates this token. Attacker who wants to post form without this token isn’t able to do this.

2. Cross-site scripting (XSS)

This time our application is not vulnerable for this attack. This is most common attack right now, so we’re going to do some really quick feature to show you the risk.

Let’s say we want to give user a possibility to format a little project description. Insert new line, make header etc. HTML tags would be great right? So, we’re going to allow user to do that.

  1. Go to Views/Projects/Details.cshtml
  2. Change @Model.Description to @Html.Raw(Model.Description)
    It should looks like this after change:

Ok, now we’re able to use HTML tags in description of our project. Let’s check out how it’s working.

We’re going to add new projectOnce it’s created let’s look at its details pageNice, we have formatted description. Feature is done. But we created also big security hole in our app. Let’s add next project with following description:

Once it’s created go to its details page

Script has been executed. It’s just normal javascript alert, but it means that every script provided by user can be executed. If so, there are really just two or three steps to steal user account. How? For example using so called “cookie stealing”. You can write small javascript code which reads all cookies from browser and send it to attacker (you even don’t need to write it, there are plenty of this kind of scripts available to download on the Internet). This way attacker is able to log in on your account.

We had to do some changes in our code in order to allow this attack be executed successfully. Let’s look at this once again. We changed on Details.cshtml @Model.Description to @Html.Raw(Model.Description). What would happened if we add project with <script></script> description and display it using just @Model.Description? <script></script> would be encoded and due to this fact it would be displayed safely. You can read more about it here.

Ok, we looked at two popular attacks. Of course there are many, many more. You can look at OWASP TOP 10 which presents ranking of most popular attacks. In the first place there is SQL Injection attack, but as long as you’re using ORM tools like Entity Framework and you’re not writing plain SQL queries, but using LINQ-to-entities queries you shouldn’t worry about any SQL Injection.

2. Backend tests

Second important topic in real-world application – test. There is no way to develop big or even middle size application without tests. Ok, maybe this is possible and there are a lot of old projects which are working without any tests, but it’s very risky (I would even say impossible) to change there anything.

Thanks to tests we’re sure that any new feature will not break any current, working application functionalities. This means that we’re able to bring this features faster and we can save a lot of money on bug fixing after release.

Tests also helps you write good code. It not means that if you write tests than your code magically will be better. What I mean is – thanks to tests after you realized specific feature or some part of it than you can easily refactor your code without worrying that you will break sth. Tests are your guarantee that functionality after some code changes are still working correctly.

What about time? Tests we’re going to do are just automated way of testing application. It means that if you don’t write tests you’re doing it manually – checking the same thing hundred of times debugging application during typical day. It’s boring and it’s waste of time.

Ok, those are some basic advantages of tests now let’s write some backend tests to our Software.House project.

  1. Add new Project (Unit Test Project) SoftwareHouse.Tests
  2. Once it’s created – add reference to .Contract, .DataAccess and .Services projects
  3. Install NuGet package – Microsoft.EntityFrameworkCore.InMemory
  4. Add class ProjectsServiceTests and paste there following code:

There as few new attributes:

  • [TestClass] – we’re using it to mark classes with test methods
  • [TestInitialize] – method with this attribute is executed before each test
  • [TestCleanup] – method with this attribute is executed after each test
  • There also is one more attribute which we’ll be using for a moment – [TestMethod] – which is intended to mark, as you can guess, our tests methods.

In our case we have Init method where we create DbContext instance, we’re using here in-memory database (this is a moment where Microsoft.EntityFrameworkCore.InMemory is needed), so we don’t have to care about database clean up (rolling back transactions etc.). Next we have Cleanup method which just removes whole in-memory database. Because those methods have TestInitialize and TestCleanup attributes database will be created and deleted for each test. This means that each test will be working with new, clean database.

Here you can read more about testing using in-memory database.

Let’s write our first test. Add following method to ProjectsServiceTests class:

As you can see we’re going to test Add method from ProjectsService. In order to do this, we have to create ProjectsService instance, but there is needed ProjectsRepository, so we must create one. We execute Add method and to verify if new project was added we close and open once again DbContext to make sure that we’re checking fresh data.

How to run tests? There are two ways. First you can open Test Explorer (Test -> Windows -> Test Explorer) and use “Run All” option.Second way, right-click somewhere in editor and from context menu choose “Run Tests”. There is one important note – if you right-click in TestMethod just this one method will run, but if you right-click outside of any method all tests from class will run.Of course there is also “Debug test” option, which means that you can debug tests exactly the same way as you do this with running application.

Let’s try prepare second test – verify if we can’t add two projects with the same name. Paste following code:

As you see, first Add method execution should success, but second should fail. We also check if there was added just one project to database (just to make sure).

Those two tests are, so called, Integration Tests. It means that we’re testing whole functionality. In our case we were testing Add method from ProjectsService but in background we were also testing implementation from ProjetsRepository and even from database (there could be also some restrictions etc.). Second testing approach is called Unit Tests. In Unit Tests we’re testing just one thing, so going back to our case, we should test only Add method from ProjectsService without touching ProjectsRepository and database. How to do this? First we must say that this would be impossible (or at least very hard) without interfaces. Because our repository has interface we can write fake repository which implements IProjectsRepository and use this one in tests. It could looks like this:

In fake repository we place concrete implementation which is called “mock”.

Another option is to use Moq. You can install it from NuGet. There is a tutorial how to use it. Let’s try to write Unit Test using Moq, use following code:

As you see we create IProjectRepository mock and setup GetAllMethod the same way as we did that in FakeProjectsRepository. Earlier we had to create new class, here we can do it dynamically. Because now ProjectsRepository logic is replaced by mock, when we’re testing GetAll method from ProjectsService we’re testing just code from ProjectsService. Nothing else.

Look here to read more about difference between Integration and Unit Tests

We have prepared three tests, but there are more methods in ProjectsService and ProjectsRepository. This is your task to test them all 🙂

Last few words about tests.

We created tests for existing code, but there is also second approach – TDD – which stands for Test Driven Development which means that we first write test and than we write actual code. You can read more about it here and here.

There are some good practices how to write tests. For example Given-When-Then pattern which helps us to organize tests code, also can be used to organize tests names. Next thing, code coverage which is very often misinterpreted, read about it here. And finally tests itself, they shouldn’t contain any logic and should be as simple as possible – prepare data, execute action and verify results. There is nice article about tests and few short tips how to write good tests.

3. Building React components in the test driven way

Front-end of 2017 means much more than simple jQuery scripts. Due to growing popularity of approaches like SPA and frameworks like Ember, Angular or React, programmers nowadays put a lot more complex business logic in client-side solutions than before. Apart from shipping new features, things like maintainability became much more important. As described earlier, tests help us achieve greater ‘maintainability-metric’ and ensure us that everything works as it should.

As a front-end developers we can create many different types of tests. Starting from basic unit tests, through tests related to structure of our UI, ending with so called “end-to-end (E2E) tests” where we’re trying to test our app from simulated environments (like browser engines and APIs).

Today we’re going to create slightly different tests than you saw before in the back-end part – you will see how to check if structure of our React components is correct in different scenarios. Our approach will be more “TDD-oriented”, because tests will be created earlier than the actual code.

 

Ready? Set… Go!

As you may know, by using Bootstrap framework’s CSS utilities we can make the look of links and buttons more consistent:

It’s about css classes – btn is the root one, and also there are some specific variations of it, like btn-success for green background. We can unify both elements by creating shared Button component based on React. There will be only one universal Button component to use and modify in the future, so it should help us in providing additional consistency and reusable, rich buttons across all pages. It should work in two modes – as a link, or as typical button.

And in fact – it’s already there (Button.tsx), implemented in previous episode.

Problem is that test coverage for this component is equal to zero – we can’t be sure if during further development of our app it will still work as we want. By introducing tests we can ‘freeze’ working functionality, and after every breaking change our tests will tell us that something bad happened.

 

So now we can do two things – we can write some tests for existing codebase (cheap, but risky) or start from scratch with test-first approach (more expensive, but it would give us guarantee that we didn’t forget about anything).

After taking a quick look at the size of our component we’ve decided that we can start from scratch (it won’t be super expensive to rewrite everything, but keep in mind that with bigger modules it’s not always possible). So, let’s start removing the content from file with component definition:

Can we test somehow that our Button is broken? We can try to execute a build using webpack command:

Yeah… webpack isn’t very happy about the state of our Button. Three props of our Button components are missing now – there are no link, href and extraClassNames, so the output is quite expected. But what if props will be there? Let’s update our interface and rebuild everything once again:

Let’s check the output of webpack command now:

Oh no! Everything works correctly! Yes, it’s the false positive result – it means that we can no longer see if our component is broken because from the build perspective the definition of our component looks good! First problem with our Button could be noticed only during the runtime and that’s definitely too late for us. So how can we check what’s the real state of our component during development? As we’ve said, we can write some tests for it.

 

Our new friends – Jest and Enzyme

We could spend some time now figuring out how to create basic tests environment for our project, but at the same time we can reuse some existing test runners and solutions for this.

For testing purposes we’re going to introduce two new tools in our stack – Jest and Enzyme.

Jest

https://facebook.github.io/jest/ – Painless JavaScript Testing

Jest is super-friendly JavaScript test runner created by Facebook. It’s focused on easiness of setup and painless testing experience. It uses many conventions to reduce time we need to spend on environment configuration, it supports TypeScript and can be integrated with other testing tools.

Docs are available here – https://facebook.github.io/jest/docs/getting-started.html

Enzyme

https://github.com/airbnb/enzyme – JavaScript Testing utilities for React

With Enzyme we’ll be able to do all kinds of manipulation with our React components, like rendering full and shallow versions of them, traversing their trees and checking the content using well-known selectors.

 

Installation

Both tools can be installed via npm – all we need to do is to update our package.json file by adding few new packages in devDependencies section:

All of them can be installed using just one command:

Because of the fact that we’re using TypeScript, along with jest and enzyme we also need three additional packages – TypeScript transformer (ts-jest), types definition (@types/jest) and one package with React test utils (react-addons-test-utils).

To use jest from command line you can also install it globally first (npm install -g jest).

One last thing we need to do is to tell Jest that we’re using TypeScript – jest configuration in package.json will do it’s job:

And we’re ready! You can test your configuration by executing jest command – as a result you should see zero available tests. Let’s write some then!

 

First test suite

We’ll start by creating basic test suite (a group of tests) next to the Button.tsx file – it will be called Button.test.tsx (to follow Jest’s convention for discovering test files). First requirement is that:

  • we’d like to render different DOM element (a or button) based on passed link (boolean flag) prop

Our suite will look like this then (Button.test.tsx):

Describe and it methods come from Jasmine framework used by Jest, and they help us organize our suite. Describe wraps some bigger parts of our tests in logical groups, and it is used to create single test. So two it calls means nothing else than two tests.

To test rendering result of our component we’re using ‘shallow rendering’ feature from enzyme to create object representation (wrapper) of our component (shallow, because children will be omitted). With created wrapper we can check it’s content by calling find method with proper selector. So in the first test we’re checking if <a> element will be rendered after passing truthy link prop, and in the second we’re looking for <button> after falsy link prop.

Let’s run our tests by executing npm test command:

And that’s the result we’ve been waiting for! We can finally see that our component is broken! What’s the problem now? React’s render method is missing. Let’s change it then in a way that we’ll be rendering basic button first:

And again, let’s run the tests:

Great! Because we’re rendering button by default, one test is passing now! But that’s not all – we’d like to check the value of link prop and render not only button, but a in some cases. Let’s update render method right now:

And re-run the tests:

Great! Our custom Button component render it’s content in two ways, based on the value of link prop, and we have a proof for that! Let’s implement now three missing requirements:

  • it should be possible to inject some text content to our component
  • if Button is used as a link, it should be possible to pass a href prop with value set to some string, otherwise hash should be used as a placeholder
  • in both versions our Button should use Bootstrap classes to style itself, and there should be possibility to extend them if needed

Tests for first case will look like that:

First we’re checking if it’s possible to set href property and find an element by it’s value, then we check if fallback to hash is implemented in case of missing href, and finally we check if there’s no possibility to render button with href.

Of course our tests will fail now (you can test it by yourself), so now let’s implement missing parts to meet the requirements:

Nothing super-complicated, but it’s good enough to see green color in the output from tests:

So the href prop is used properly. Now we can check if our components are able to render any content passed to them:

 

So basically we’re rendering our components two times, and then we’re checking if html output looks exactly the same as we want. The answer is…:

Not exactly.

We can see that our tests are failing now, because both <a> and <button> elements are empty. Output from Jest is really amazing and helpful when it comes to looking for failing tests causes. To fix our tests we need to use this.props.children to inject some content in React component:

And when it comes to test results…

I really like this output full of green lines 😉

One last thing to add – our component doesn’t have enough style! It should use Bootstrap classes to fix that as soon as possible! Basic rule is that every button or link should contain btn class, and it can also use additional classes if they were passed via props. Again, let’s start with tests for it:

To make them passing we need to update our render method:

We are using two arrays to create final string for React’s className prop – one with default class ‘btn’ and the second, optional, containing extra class names (or empty if null), and joining them with space.

Our new tests are green, but we created regression bug:

Some predictions from previous tests are no longer valid. They aren’t, because html string changed slightly, due to additional classes which now are part of our component. To fix them, you need to add class=”btn”  to expected output – try to do this right now and check if tests will be all-green again.

To check if everything works as we want we can finally run our application and see once again if button used for creating projects looks good:

Not only it looks and works good, but also it finally has acceptable level of test coverage.

You can apply this approach to every single component in your application. Of course in more complex components you may need to do a bit more, for example to handle 3rd party dependencies or async calls, but when it comes to testing look and structure of your UIs basics are here.

4. Summary

Today we did another big improvement in terms of scalability and maintainability of our project.

Based on our examples you learned how to fix most common security bugs which can be found in many web applications of today like XSS and CSRF. Also, we created a bunch of tests to be sure that everything meet the requirements and can be extended in the future without worrying that programmer will break something without any knowledge.

It’s worth to know that in real-life projects these areas of software development are often maintained in a full-time mode by specialists like security and quality assurance engineers, which are responsible for caring about health of projects they are maintaining. Shipping new features is super exciting from programmer’s perspective, but you have to know that it’s only one thing from the long list of activities related to real-life software development. It also means that there’s enough space for everyone, not only for ones interested in specific programming language or framework 😉

  • Aleš Vojáček

    Is this post the last one in this series?

    • Adrian Bystrek

      We’ll add more informations about that in a few days 🙂

      • Aleš Vojáček

        Ok. I’m still tryig to find out when is better to use SPA (react, aurelia) and so on, than MVC only. I thought that that is good for not simple forms etc, but your example is oposite. It is for read only page and for everything else you are using MVC.

        • Adrian Bystrek

          It’s hard to answer to this question in a few words. It’s topic for another whole post or even few posts 😛 Generally everything depends on context which you deal with (what are requirements for your project).

          Just to be clear – you can use SPA, MVC only or even mix one approach with another (as we did in this tutorial). Everything is possible and everything has advantages and disadvantages. What’s important – you shouldn’t think of MVC as sth older than SPA and conclude that now we should use only SPA approach.

          For more info about when to choose SPA/MVC you can look on the Internet, for example here http://stackoverflow.com/questions/21862054/single-page-application-advantages-and-disadvantages or just type “spa vs mvc” in google and you will obtain a lot of sites where people disscuss about that.

          We’ll try also to make some post on this topic soon 🙂

          • Aleš Vojáček

            Ok, so in this tutorial, it makes sense, use React for detail of “project” instead of getting new mvc view for it?
            I will wait where this tutorial lead us. I

          • Przemek Smyrdek

            To answer your question – it all depends on your goals.

            In real-life examples each case should be analyzed first to be sure that introduced solution will be optimal to solve given problem – it’s hard to say that ‘in general’ something should be done in that way, and something else in that way. Different teams have different experience and use different tools – optimal solution for team in Germany will be different than for team in Czech Republic and it doesn’t mean that some of them are doing things in wrong way! It all depends on the requirements, and also the context is super important – do we need a quick demo? A super stable app? Is performance a crucial thing for us?

            You need to remember that scope of our course is much smaller than most real-life projects, and because of that we’re introducing some shortcuts to give you end-to-end overview how to build this kind of things. Without these shortcuts it would be extremely hard to finish each post, because we can talk for many hours about each paragraph and about different problems which could occur during implementation of different parts here.

            One thing you should care about is consistency. Similar parts of your app should work in the same way. There’s nothing wrong with both full SPA and both server-side approach, but it depends on the specific case. And that’s all 🙂

        • Przemek Smyrdek

          One use case for SPA is for example when you have many strictly coupled pages (list -> details) and so on, and you’d like to have ‘faster’ (faster is relative) navigation between them. Let’s say that both of them would use the same modules / services / whatever, so they need to be initialized only once in memory on the client-side. After navigation from list to details in most cases you would only need to re-render the new page, because many modules have already been initialized before. It’s common pattern in i.e. mail clients like gmail or in other sites with this list -> details structure, because many components can be initialized once, and you can visit details page many times (like during reading 30 e-mails) which will use those pre-initialized things.

          On the other hand coupling between pages in SPA approach isn’t always preferred solution. Modern browsers and their features like prefetching scripts and content of pages in the same domain can be used as a substitute of SPA and tight coupling between different sections in your app. As Adrian answered, it depends on your use case – I don’t believe in this hype for SPA all the things 😉 That’s why for example React is much more often used as a drop-in solution in existing pages (where you can’t just remove everything and apply SPA), because with it you don’t rewrite your whole front-end, like with i.e. Angular 4.

  • Aleš Vojáček

    I have problems with start testing Button.test.tsx . With npm test I still getting :
    > aspnetreact@0.0.1 test E:PlayGroundLearningASPNetReactAspNetReact.WebAspNetReact.Web
    > echo ‘Error: no test specified’

    ‘Error: no test specified’

    • Aleš Vojáček

      I found that in Button.test.tsx I hae squiglies under enzyme, but it is installed and intellisense can find that 🙁

      • Przemek Smyrdek

        Unfortunately Visual Studio still has some problems with resolving modules from node_modules folder, so you shouldn’t care too much about errors there (at least if build via Webpack is working).

    • Przemek Smyrdek

      Try to update scripts section in package.json add “test”: “jest” line there, check it here: https://github.com/Lazys/Getting-started-on-ASP.NET-Core-React-software-house/blob/master/SoftwareHouse/SoftwareHouse.Web/package.json

      • Aleš Vojáček

        Great that was it 🙂 Thank you

        • Przemek Smyrdek

          Thanks for following each episode with us!