ASP.NET Request Forgery (XSRF/CSRF) protection in This Core

Page update date :
Page creation date :

Environment

Visual Studio
  • Visual Studio 2019
ASP.NET Core
  • 3.0
  • 3.1

What is cross-site request forgeri?

Cross-site request forgery (CSRF/XSRF) is for those that are processed only within the site of interest. An attack on a vulnerability that performs such an update process from an external site.

For example, suppose you have the ability to post comments on a Website. Normally, i think you will post by entering a comment from the site, This send process is most often used to throw data at the target URL.

Therefore, if you send similar data to the URL from someone other than the target site, It's the same treat you posted.

If only an attacker would do this, it would not be a threat. The scary thing about CSRF is that attackers can build fake sites or embed hidden URLs in the site. It's where someone else unintentionally accesses it and becomes an attacker.

I won't go into depth here, so please find out more about cross-site request forgeri.

ASP.NET Core incorporates this countermeasure into the framework.

Check cross-site request forgery to work

Try to see if the update process is actually performed from external sites or tools.

Index.cshtml creates an input form that sends the text you entered to the server. Then place viewdata so that the server displays messages that you have created to match the input text.

Index.cshtml

@{
  ViewData["Title"] = "Home Page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<form method="post">
  <input type="text" name="text" />
  <button type="submit">送信</button>
</form>

<p>@ViewData["Message"]</p>

Server-side HomeController.cs processes the sent text and outputs it to a Visual Studio trace. Set the same text to ViewData so that it can be displayed to the client.

HomeController.cs

public class HomeController : Controller
{
  // 省略

  [HttpPost]
  public IActionResult Index(string text)
  {
    System.Diagnostics.Trace.WriteLine($"「{text}」が入力されました。");
    ViewData["Message"] = $"「{text}」が入力されました。";
    return View();
  }

  // 省略
}

Try to perform the functionality you just created in the normal steps. When you run debugging and the screen appears, enter the text and click the Submit button.

The processed text appears on the screen as expected.

Because it is also output to the trace, the visual studio output window also displays text. In fact, we do things like registering input data in a database, but we're not going to simplify the code here.

Now, try to access the program from outside the target site while debugging and running. For simplicity, i'll post a post using a tool called Visual Studio Code. If you can send POST, you can use other tools or build another site program for the attack.

When you install an extension called REST Client in Visual Studio Code, You can use a feature that allows you to easily check the operation of the REST API just by opening the .http file.

When you create a .http file similar to the following in a text file, and then open the file in Visual Studio Code, You can send GET or POST by clicking send request.

If you create the following POST data, you will be sent almost the same amount of data as you type text on the screen and press the submit button. (Localhost port number should be the same as the execution environment.)

RestTest.http://www.restTest.http

### Form で POST 送信
POST https://localhost:44372/home/index HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="text"

なんらかのテキスト
------WebKitFormBoundary7MA4YWxkTrZu0gW--

When you send it, you can see that the server is receiving text and processing it.

Visual Studio Code can get the results. If you take a closer look at the result code, you can see that the value set for ViewData is displayed. (It is displayed in Unicode, but the text is displayed correctly if viewed in a Web browser.)

Address cross-site request forgeri vulnerability

As I mentioned at the beginning, ASP.NET Core incorporates measures against cross-site request forgery in the framework. A common measure is to issue a unique token to the client in advance on a screen that requires post, etc. You don't have to accept processing unless you throw the token to the server.

Of course, if you access the URL directly from an external site, the token is unknown and will not accept processing.

First, i would like to talk about issuing tokens to the client (HTML), but the fact is that the framework is not able to do this. Will go. If you specify a POST method in the form tag, you can incorporate token parameters into HTML without permission.

In the HTML below, it is the input name="__RequestVerificationToken" type="hidden". This is sent to the server together when the send button is pressed. By the way, it is not appended by the GET method.

On the server side, Startup.cs services. AddControllersWithViews method options. Filters to AutoValidateAntiforgeryTokenAttribute, all actions This token check is automatically added to (to be exact only the HTTP methods of POST, PUT, PATCH, and DELETE).

If you want to add this constraint only to specific actions, not all actions, per controller, per action It is also possible to set.

Conversely, if you want to impose restrictions on most actions, but you want to exclude specific actions, If you set the IgnoreAntiforgeryToken attribute to the controller and action, it is OK.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews(options =>
  {
    // 全ての「POST, PUT, PATCH, DELETE」アクションに自動で ValidateAntiForgeryToken を付与。
    // 個別に除外したい場合は「IgnoreAntiforgeryToken」属性を指定すること
    // API では HTML 側にトークンを発行できないのでコントローラーに「IgnoreAntiforgeryToken」を指定する必要がある。
    options.Filters.Add(new Microsoft.AspNetCore.Mvc.AutoValidateAntiforgeryTokenAttribute());
  });
}

Let's see how it works. First of all, the transmission process is done from the screen normally.

The results were reflected on the screen as expected.

It is also output to the trace.

Now, let's try to access it from the outside.

Access ed, but Bad Request was returned. It's a different result than when you're not taking measures. It is understood that it is guarded because it is not output to the trace.

Summary

This time I tried to implement measures against cross-site request forgeri. It was very easy to implement because it was already built into the framework.

Building a Web site requires a lot more vulnerability than CSRF. You can check what's out there, or you can use tools like OWASP to check for vulnerabilities in your site.