"Third" security policy for the Quick start of ASP. NET MVC (MVC5+EF6)

Source: Internet
Author: User
Tags http post response code csrf attack

First ASP. NET MVC QuickStart Database Operations (MVC5+EF6)

"Second" ASP-Quick Start Data annotations (MVC5+EF6)

"Third" security policy for the Quick start of ASP. NET MVC (MVC5+EF6)

"Fourth" complete example of the ASP. NET MVC QuickStart (MVC5+EF6)

The Free jquery Control Library (MVC5+EF6), "Foreign article", the Quick start of ASP.

Please pay attention to the three stone blog: Http://cnblogs.com/sanshi

Forms Authentication in Forms Authentication (forms authentication) WebForms

Before explaining the security policies provided by MVC, it is also simple to look at Forms authentication (forms authentication), which is common in WebForms, and this process of authentication is straightforward:

    1. The user provides login information (such as user name and password).
    2. After the logon information is validated, a FormsAuthenticationTicket object that contains the user name is created.
    3. This ticket object is encrypted and the encrypted result is saved as a string in the browser cookie.

All HTTP requests after that will take this cookie and be compared by WebForms, while exposing the following two properties:

    1. HttpContext.User.Identity.IsAuthenticated
    2. HttpContext.User.Identity.Name

In Web. config, we generally need to configure the login page (loginurl), the post-login jump page (defaulturl),

Information such as retention time after login (timeout):

<system.web><authentication mode= "Forms" >      <forms loginurl= "~/default.aspx" timeout= "120" Defaulturl= "~/main.aspx" protection= "All" path= "/"/></authentication><authorization>      <deny Users= "?"/></authorization></system.web>

The above configuration denies anonymous access for all users, and of course we change the access permissions for the specified directory outside of <system.web>, such as:

<location path= "res" >       <system.web>         <authorization>              <allow users= "*"/>         </authorization>       </system.web></location>

This configuration allows anonymous users access to the Res directory (typically static resources).

Forms Authentication in MVC

MVC has rewritten the validation model, but the basic principle has not changed, and we are more concerned with the difference:

    1. Directory-based permissions control in WebForms.
    2. In MVC, the controller or controller's methods are controlled by permission.

This is not difficult to understand, because MVC does not have a URL corresponding to the physical directory, and the same controller method may correspond to multiple access URLs, which is configured by the routing engine and is briefly described in the first article.

Authorize annotations

In MVC, the resources we want to protect are not folder directories, but controller and controller methods, so MVC provides an authorization filter (authorize filter) to protect it, which is provided as a data annotation.

[Authorize]public class studentscontroller:controller{...       }

Here, the entire controller is protected against anonymous user access, and access is given an error page:

Configure Forms Authentication

Now add the configuration information:

<system.web><authentication mode= "Forms" >  <forms loginurl= "~/home/login" defaulturl= "~/ Students "timeout=" "protection=" All "path="/"/></authentication></system.web>

Specify the login page ~/home/login, after the login page is ~/students, and now to browse the page:

Http://localhost:55654/Students

This visit has two HTTP requests, and the URL of the browser address bar has changed:

Http://localhost:55654/Home/Login?ReturnUrl=%2fStudents

This place is familiar to us, the ReturnUrl parameter specifies the page that needs to be adjusted after the login is successful, and ~/home/login is the login page we just configured in Web. config.

The first of the two HTTP requests, the response code is 302, which is a redirect response, and the browser automatically recognizes the 302 response and jumps to the URL specified in the response header. So the second request was initiated by the browser, but we haven't defined the login page yet, so the return 404 was not found.

Create a login page

Define the Home/login controller method:

public class homecontroller:controller{Public       actionresult Login ()       {              return View ();}       }

Right-click inside the action method and select [Add View ...] Menu items:

In the wizard dialog box that pops up, select [Empty (without Model)] and we'll create the view content manually:

Completed View page:

@{    viewbag.title = "Login";}     <input type= "text" name= "UserName"/>    <input type= "password" name= "password"/>    <input type= " Submit "value=" Login "/>}

Click the [Login] button and the form will be submitted to the login method via the POST request:

[HttpPost] [Validateantiforgerytoken]public actionresult Login (String UserName, String Password) {       if (UserName = = "Sanshi" && Password = = "Pass")       {              formsauthentication.redirectfromloginpage ("Sanshi", false);       }       return View ();}

The administrator's username and password are hardcoded and may need to be read from the database in the actual application.

Show sign-in status in layouts

Next, we need to place the login information in the layout page (shared/_layout.cshtml) and the [Exit System] Button:

@if (User.Identity.IsAuthenticated) {       using (Html.BeginForm ("Logout", "Home", FormMethod.Post, new {id = " Logoutform "}))       {              @Html. AntiForgeryToken ()              <ul class=" nav navbar-nav navbar-right ">                     <li ><a href= "javascript:;" >hello, @User .identity.name</a></li>                     <li><a href= "javascript:;" id= "logout" > Exit system </a></li>              </ul>       }}else{       <ul class= "nav navbar-nav navbar-right" >              <li > @Html. ActionLink ("Login", "Login", "Home") </li>       </ul>

This code has two layers of logic:

    1. If the user has verified the identity, a form is displayed with [Hello, Sanshi] and a login button. Limited to the built-in style of Bootstrap, where only a tag can be used instead of the input tag, and a script is registered at the bottom of the page to handle button click events.
    2. If it is an anonymous user, the [login] hyperlink is displayed.

Implementing the [Exit System] Feature

The client processing script that registers the [exit System] button, because when the form label is generated (Html.BeginForm), we set the id attribute of the form label, so simply submit the form when you click the [Exit System] Button:

<script>       $ (function () {              $ (' #logout '). Click (function () {                     $ (' #logoutForm '). Submit ();              });       }); </script>

The background logic of the [exit System] button requires the client cookie to be emptied before the client jump is performed:

[HttpPost] [Validateantiforgerytoken]public actionresult Logout () {       formsauthentication.signout ();       Return redirecttoaction ("Index", "Home");

Run effect

Look at the page run effect, the first is the login page:

After successful login, jump directly to ~/students page:

Cross-site request forgery (CSRF)

In the previous HTTP POST request, we saw the following code in the view and controller several times:

    1. Html.antiforgerytoken () is called in the view.
    2. The method in the controller adds a [Validateantiforgerytoken] annotation.

This looks like a pair of writing is actually to avoid the introduction of cross-site request forgery (CSRF) attack.

This attack has been known for about 2001 years, when Netflix, the 2006 US online film Leasing website, burst out multiple csrf vulnerabilities, and YouTube, a popular video site in 2008, was attacked by CSRF, a Mexican bank customer who was attacked by CSRF in the same year, Anti-virus maker McAfee has also burst csrf attacks (quoted from Wikipedia).

The reason that many large web sites also encounter CSRF attack, is because the CSRF attack itself process is relatively long, many developers may in a few years have not encountered CSRF attack, so the cognition of CSRF is more vague, did not cause enough attention.

Simulation examples of CSRF attacks

We'll walk through a mock example of how the CSRF attack works, and then look back at the security policies provided by MVC.

A seemingly secure Bank transfer page

Let's say we're a bank web developer, and now we need to write a transfer page where the customer logs in and enters the account number and the amount of money transferred, which can be transferred:

[Authorize]public actionresult TransferMoney () {       return View ();} [HttpPost] [Authorize]public actionresult TransferMoney (string toaccount, int money) {       //place Transfer business code       Viewbag.toaccount = Toaccount;       Viewbag.money = money;       return View ();}

Since this process requires authentication, we have added annotations [authorize] to the two operations methods of TransferMoney to block anonymous user access.

If you access Http://localhost:55654/Home/TransferMoney directly, you will be redirected to the login page:

After logging in, come to the transfer page, we look at the transfer of the View Code:

@{    viewbag.title = "Transfer Money";} 

There is a logical judgment in the view code that displays different content depending on whether Viewbag.toaccount is empty:

    1. Viewbag.toaccount is empty, it indicates page access.
    2. Viewbag.toaccount is not empty, the transfer is successful, you need to display the prompt information of successful transfer.

Look at the page run effect:

function Complete! There seems to be no problem, but here is another csrf loophole, hidden and difficult to find.

I'm a hacker, Show me the money

There are two characters here, a client of bank A, hacker B.

Hacker B found this loophole in the bank, wrote two simple pages, page one (click_me_please.html):

<! DOCTYPE html>

The first page contains only a hidden iframe tag, pointing to the second page (click_me_please_iframe.html):

<! DOCTYPE html>

The second page places a form tag and places the hacker's own bank account and transfer amount on it, submitting the form when the page opens (the OnLoad property of the body).

Now hackers put these two pages into the public network:

Http://fineui.com/demo_mvc/csrf/click_me_please.html

Then bulk send the user the message with the attack link, and the bank's customer a just logged in to the banking system, and the hand is cheap click on the link:

Then you will see this page:

You may think in your mind, who is so bored, and then depressed to close this page. Then customer a will be more depressed, because Hacker B's bank account [999999999] has been successful more than 3000 dollars!

How did you transfer the money, not an authentication?

Yes. The transfer really requires authentication, and now the problem is that you're logged into the banking system, you've done the authentication, and you've opened the hacker link in the browser's new tab, let's see what happened:

Here are three HTTP requests, the first one is [tease you to play] the page, the second is the inside of the IFRAME page, the third is the IFRAME after loading the post request, that is, the specific transfer page. Because the IFRAME is hidden, the user does not know what happened.

Let's take a look at the third request:

Obviously this transfer was successful, and the cookie with the user authentication information, all the backstage do not know that the request is from the hacker's page, the transfer of the successful return content:

How to stop CSRF attacks

From the above example, we can see that csrf originates from the implementation mechanism of forms authentication.

Because the HTTP itself is stateless, that is, every request for the Web server is completely new, the server does not know any state of the previous request, and authentication requires us to the second access to know whether the state of the login (not every request to verify the account password), this is a contradiction in itself!

The solution to this paradox is that Cookie,cookie can save a small amount of information in the browser, so forms authentication uses cookies to store encrypted identity information. All the values stored in the cookie are sent to the server in every HTTP request (whether get or post, static or dynamic), which gives Csrf an opportunity.

So, the root of CSRF is that the server can learn the authentication information from the cookie without knowing whether the HTTP request is actually initiated by the user.

Referer Verification

Referer is part of the HTTP request header information, which is accompanied by a referer message whenever the browser sends a request to the server, indicating the page address of the current originating request.

A normal transfer request, we can see that the Referer and the browser address bar are consistent:

Let's take a look at just the hacker page:

You can see that the content of Referer is the same as the page address of the current originating request, note the comparison:

    1. Browser URL: click_me_please.html
    2. HTTP request Address: Home/transfermoney
    3. Referer:click_me_please_iframe.html, note that this is the page that initiated the request, not necessarily the URL displayed in the browser's address bar.

Based on this principle, we can simply referer verify the POST request for the transfer:

[HttpPost] [Authorize]public actionresult TransferMoney (string toaccount, int money) {       if (Request.Url.Host! = Request.UrlReferrer.Host)       {              throw new Exception ("Referrer validate fail!");       }        Place the transfer business code here        viewbag.toaccount = toaccount;       Viewbag.money = money;       return View ();}

At this time access http://fineui.com/demo_mvc/csrf/click_me_please.html, malicious transfer failed:

CSRF validation supported by the MVC default

MVC provides a more thorough way of CSRF validation by default by verifying that the current request is really from the user's action.

On the View page, add a call to the Html.antiforgerytoken function inside the form:

@if (Viewbag.toaccount = = null) {    using (Html.BeginForm ())    {        @Html. AntiForgeryToken ()        <input type = "text" name= "Toaccount"/>        <input type= "text" name= "Money"/>        <input type= "Submit" value= "Transfer"/ >    }}else{    @: You have transferred [@ViewBag. Money] to your account [@ViewBag. toaccount]! }

This will generate a token named __requestverificationtoken in the form label and in the cookie separately:

Then add [Validateantiforgerytoken] annotations to the Controller method:

[HttpPost] [Authorize] [Validateantiforgerytoken]public actionresult TransferMoney (string toaccount, int money) {       //place Transfer business code       here Viewbag.toaccount = Toaccount;       Viewbag.money = money;       return View ();}

On the server side, the two tokens are verified to be consistent (not equal) and will be error-proof if inconsistent.

The following manual changes the value of this hidden field in the form to see the error message:

Similar to the truth, run Hack page http://fineui.com/demo_mvc/csrf/click_me_please.html, malicious transfer failed:

At this point, although the __requestverificationtoken in the cookie was submitted to the background, the hacker was unable to know the __requestverificationtoken value in the form field, so the transfer failed.

Excessive commit attacks (over-posting)

In the edit Student controller method, there is a bind feature annotation, let's review:

[HttpPost] [Validateantiforgerytoken]public actionresult Edit ([Bind (Include = "id,name,gender,major,entrancedate")] Student Student) {       if (modelstate.isvalid)       {              db. Entry (student). state = entitystate.modified;              Db. SaveChanges ();              Return redirecttoaction ("Index");       }       Return View (student);}

This is to prevent over-posting attacks, which is relatively simple to understand, the include attribute of the bind attribute is used to specify a whitelist, and all properties in the whitelist participate in the model binding.

Suppose you add a field [title] to the student model:

public string Job {get; set;}

Without the bind attribute, when updating the student information, a malicious user can submit a job's value by impersonating a POST request (described in the second article), causing the user's job to change in the database. The Bind feature is designed to prevent this from happening.

The Bind feature also provides a way to set the blacklist, similar to the following:

[Bind (Exclude = "Job")]

However, it is generally recommended to use a whitelist so that even if the model changes, it does not affect the existing functionality.

========="2017-01-07" Update ==========================================

When the model is bound, the bind attribute is specified with the Bind property list, and the job attribute is not specified, so the model is bound to Job=null

If you have previously set up job= "engineer", then use the following code:

Db. Entry (student). state = Entitystate.modified;db. SaveChanges ();

After that, the job will be set to NULL, executing the SQL statement:

exec sp_executesql N ' UPDATE [dbo]. [Students] SET [Name] = @0, [Gender] = @1, [Major] = @2, [Job] = NULL, [entrancedate] = @3where ([ID] = @4) ', N ' @0 nvarchar ($), @1 in T,@2 nvarchar ($), @3 datetime2 (7), @4 int ', @0=n ' Zhang Sanxi 8 ', @1=1,@2=n ' Department of Materials Science and Engineering ', @3= ' 2000-09-01 00:00:00 ', @4=1go

Visible, although I changed the Name field only, all fields are updated to the data, and the job is overwritten with null.

This is the result that we do not want to see.

Workaround One:

We can not update the job field by setting the job property to not change:

Db. Entry (student). state = Entitystate.modified;db. Entry (student). Property (s = = s.job). ismodified = false;db. SaveChanges ();

The SQL statement at this point:

exec sp_executesql N ' UPDATE [dbo]. [Students] SET [Name] = @0, [Gender] = @1, [Major] = @2, [entrancedate] = @3where ([ID] = @4) ', N ' @0 nvarchar ($), @1 int,@2 nvarchar ( @3 datetime2 (7), @4 int ', @0=n ' Zhang Sanxi 9 ', @1=1,@2=n ' Department of Materials Science and Engineering ', @3= ' 2000-09-01 00:00:00 ', @4=1go

Workaround Two:

We can also get the student object from the database first and then update some fields:

var _student = db. Students.find (student.id); _student. Name = student. Name;_student. Gender = student. Gender;_student. Major = student. Major;_student. Entrancedate = student. Entrancedate;

Db. SaveChanges ();

At this point there will be two SQL queries, the first one is retrieved by ID, and the second is an update:

exec sp_executesql N ' SELECT TOP (2)     [extent1].[ ID] as [id],     [extent1].[ Name] as [name],     [extent1].[ Gender] As [Gender],     [extent1].[ Major] As [Major],     [extent1].[ Job] as [job],     [extent1].[ Entrancedate] as [entrancedate] from    [dbo].[ Students] as [Extent1]    WHERE [extent1].[ ID] = @p0 ', n ' @p0 int ', @p0 =1goexec sp_executesql N ' UPDATE [dbo]. [Students] SET [Name] = @0where ([ID] = @1) ', N ' @0 nvarchar ($), @1 int ', @0=n ' Zhang Sanxi ', @1=1go

Special NOTE: The SQL UPDATE statement at this point is no longer all updates, but only the changed data (because with the first query, EF knows the field values of the database so that it can be known that it needs to be updated).

========="2017-01-07" Update ==========================================

Summary

This article first introduces the implementation of forms authentication under MVC and the difference between forms authentication and WebForms. Then focus on the cross-site request forgery attack (CSRF), because this attack process is long, the understanding is more obscure, we specially produced an attack case, hope that can arouse the attention of developers. Over-posting attack is relatively simple, but we need to strictly abide by the security guidelines in the actual coding, there is no luck in the mind. Of course there are other types of attacks, such as cross-site scripting attacks (XSS), cookie theft, open redirect attacks, and so on, which are not covered by space.

Starting with the next article, we will gradually enrich the functionality of the example by adding a search form to the table page to display tabular data based on different query criteria.

Download Sample source code

"Third" security policy for the Quick start of ASP. NET MVC (MVC5+EF6)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.