# ASP.NET 安全

- URL: https://wuming.si/blog/930/
- Author: Aaron
- Published: 2015-03-30
- Language: zh-Hans
- Categories: Uncategorized
- Originally published at: https://blog.wo.ai/archives/930

### 

### **概述**

安全在web领域是一个永远都不会过时的话题，今天我们就来看一看一些在开发ASP.NET MVC应用程序时一些值得我们注意的安全问题。本篇主要包括以下几个内容 ：

  1. 认证
  2. 授权
  3. XSS跨站脚本攻击
  4. 跨站请求伪造

### **认证**

所谓认证，简单的来说就是验证一个用户的身份。这取决于我们开发的站点的类型，是否允许匿名访问，是否是属于管理员或者其它角色的用户等等。也就是说我们的整个程序或者某些功能是针对某些特定的用户开发的，那么我们可能就要进行认证来确定用户的身份。需要注意的是，认证与授权是是完全不一样的概念，我们要区别对待。打个比方，在ASP.NET MVC里面允许某一类用户访问某个Action就是授权。

ASP.NET MVC中主要有两种认证机制

  1. Forms 认证
  2. Windows 认证

**Forms 认证**

从字面上我们就可以得到一些信息，基于表单的认证提供给用户一个表单可以输入用户名和密码，然后我们可以在我们的程序中写自己的逻辑去验证这些信息。ASP.NET MVC为Forms认证提供了很多支持，并且有很强自定义性。从通过表单登录到用户信息存储在什么地方，到怎么样去验证这些用户信息。Forms认证默认是依靠cookie技术实现的，一旦某个用户登录站点，那么用户所使用的这个浏览器就会得到一个cookie并且在后面所有与这个站点的其它请求中都会将这个cookie包含在http的头中。ASP.NET能够检测到这个cookie，这个cookie中包含了用户的认证信息，那么后面就不需要再重复的认证用户了。

**Windows认证**

Windows 认证也就是大家熟悉的集成身份认证，因为它使用了集成在Windows操作系统中的用户组件来认证用户。一旦某个用户登录到域中，Windows能够在应用程序中自动认证他们。Windows认证一般在企业局域网内比较常用，一般企业局域网中所有的用户都需要用域身份来登录，这个有点像单点登录的体验，一旦进入域中就可以就可以很方便的同时登录域内的其它应用程序。

**配置Forms认证**

首先我们需要更改web.config中的authentication结点。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d195af63e5_5e4d414cgw1eqnq49bn9qj20az01hjrj.jpg)

这个配置信息很简单，首先我们要使用的authentication类型是Forms认证。通过loginUrl指定我们认证用户的页面。这个Account Controller和 Login View还有一些允许用户注册的View都被ASP.NET MVC的internet模板默认实现了。我们可以轻而易举在在ASP.NET MVC中实现Forms认证。

打开Visual Studio 2010 > New Project > Select ASP.NET MVC 4 Web Application 点击确认。

![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq7psgjuj20qa0ghafl.jpg)

然后选择Internet Application点击确认，Forms认证所需要的Controller 和View等等都会默认包含在我们的项目里面了。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/47064a3816_5e4d414cgw1eqnq49s6fdj20ir0gtq5j.jpg)

Authorize 属性![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d6d0fc40c_5e4d414cgw1eqnq4a2ei3j206502j3yi.jpg)

Authorize不关注我们如何认证用户，我们既可以用Forms认证也可以用Windows认证。Authorize会去检测当前用户是否有身份信息。如果我们在Index上加上Authorize属性那么匿名用户就不能访问我们的Index Action了。他们会被跳转到Account/Login，也就是我们上面在web.config中配置的loginUrl。

**如何配置Windows认证**

和Forms认证一样，首先我们需要更改一下web.config中的authentication结点。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2793b6cec3_5e4d414cgw1eqnq4a8gnoj20cj01gweo.jpg)

然后同样地，应用Authorize属性到我们的Index Action上。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2428a5a43d_5e4d414cgw1eqnq4atp31j206502j3yi.jpg)

我们可以将Authorize应用到一个单独的Action上，也可以应用到一个Controller上。当我们在某一个Controller上应用Authorize属性时，也就意味着这个Controller下所有的Action都必须是经过认证的用户才允许访问 。

如果使用IIS Express的话，我们需要更改配置信息来启用Windows认证。否则我们就会得到以下错误页面。

![](http://ww3.sinaimg.cn/mw690/5e4d414cgw1eqnqbkjm3hj20ff06naas.jpg)

我们可以到IIS Express的配置中去启用Windows认证，打开Windows Explorer进入我的文档> IIS Express > config > applicationhost.config。然后将windowsAuthentication enabled设置为true。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d79ec6c20_5e4d414cgw1eqnq4bgwhzj209603c74k.jpg)

然后我们就可以拿到一些用户的信息。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/62771b6aee_5e4d414cgw1eqnq4boywwj20ce04agls.jpg)

### **授权**

授权允许我们传递一些参数去设置规则，我们可以告诉Authroize属性只有某些具体用户才可以访问某个Action。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f0cbb59e6_5e4d414cgw1eqnq4c7efjj20il03igm1.jpg)

同时 ，我们还可以为Authorize属性指定 Roles。这些Roles默认匹配到我们web服务器的Windows Group或者是域管理器里面的用户组。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd94d758bb_5e4d414cgw1eqnq4ctygrj20hu03d0t6.jpg)

在Forms认证中, ASP.NET为我们提供了一个角色管理器（role provider）我们可以通过它来方便和将我们的角色信息存储到SQL中，并且进行管理。我们只需要点击一个按钮即可：![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec09cb8d4e_5e4d414cgw1eqnq4cv4k0j209j0533z8.jpg)

点击上面这个按钮之后，它会帮我们运行ASP.NET configuration tool。这个站点只能在本地运行，我们可以在这个站点管理我们的角色，这个站点默认使用的数据连接就是我们配置在web.config中的连接字符串。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d93205aaf3_5e4d414cgw1eqnq4d52rlj20nq0crwhm.jpg)

### **XSS跨站脚本攻击**

在web领域，有几个比较常见的安全隐患，其中一个比较流行的就是跨站脚本攻击。一些恶意的用户通过一些手段让我们的站点加载一些恶意的脚本，那么如果其它用户访问到这些脚本就有可能成为受害者。除了脚本，包括active-x控件，甚至一些恶意的Html都可以成为XSS的武器。XSS可以做到哪里事情 ？

  1. 窃取cookie
  2. 更改用户设置
  3. 下载恶意软件
  4. 更改内容
  5. 账户劫持

简单的说，我们可以通过XSS访问用户的个人信息以及身份信息。

**XSS示例**

![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq4dunjsj20dy0dn74s.jpg)

这是一个简单的录入员工信息的页面，我们输入一些html代码然后保存页面。ASP.NET默认会去检测我们的request，发现类似html代码会直接拒绝我们的请求。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/213c0ed8df_5e4d414cgw1eqnq4ez9i9j20zk07s0y4.jpg)

当然，有些时候我们需要允许用户输入html，那么只要在我们的Action上打上ValidateInput(false)即可。

![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq4ewfbaj20es03vmxs.jpg)

这样我们就可以成功的提交 我们的请求了。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e8e972fdd1_5e4d414cgw1eqns8io6lfj20c8067gm7.jpg)

如上图所示，这样我们又遇到了另外一个问题。在ASP.NET MVC中razor默认会对所有输出进行html编码。这是ASP.NET MVC针对XSS攻击的另一道防火墙。通过为属性打上AllowHtml属性，我们可以允许某一个属性包含html的值，这样我们就可以移除Action上的ValidateInput属性。通过Html.Raw 我们可以将html输出到客户端。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/30d76c4a2b_5e4d414cgw1eqnq4frl3tj20d703ejs4.jpg)

**Anti XSS library**

如果我们允许用户输入html的话，有些人可能会尝试输入一些脚本 (不要说你没有想过在博客园输入一些脚本来玩玩？)

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0759cd5267_5e4d414cgw1eqnq4fq0k4j209i09hwet.jpg)

幸运的是，Microsoft为我们提供了一个组件，我们可以通过nugget或者Library Package Manager Console( Visual Studio > Tools > Library Package Manager > Package Manager Console 输入 Install-Package AntiXss回车 )

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41e6118ab1_5e4d414cgw1eqnq4goqguj20fb035wf6.jpg)

只需要简单的一句话，就可以移除所有的有害代码，是不是感觉又被Microsoft搞蠢了？

## **CSRF跨站请求伪造**

跨站请求伪造也是一种危险的主流攻击。试想一下，某个用户登录到网站想修改一些个人信息，如果服务器端使用了Forms认证，那么在这个用户登录之后就会得到一个包含身份信息的cookie并且在后面所有这个站点下的请求中传递。当然这个并没有错，毕竟如果每次都去验证用户名和密码是一次不小的开销，验证一次之后将登录信息保存到cookie中，至少在用户不关闭浏览器之前，我们不用再重新去验证用户。

**安全隐患在哪里？**

如果浏览器端依然保留着我的身份信息，那在我访问其他恶意的站点的时候。这些恶意的站点就可以自己封装一个表单并提交到我们的服务器，虽然这个请求时恶意站点伪造的，但是因为它带有用户的身份，所以服务器是会正常处理的。小到更改用户资料，大到转走用户的账户余额都成为可能。

所以我们在处理请求的时候，不仅仅需要验证用户身份信息，还需要确保发送数据的表单是由我们服务器产生的。这样就可以避免其他恶意用户伪造表单发送数据。

**CSRF示例**![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/959fd9fd86_5e4d414cgw1eqnq4h469hj20cz0cz0ub.jpg)

这里有一段很常见的代码，通过Edit Action来编辑用户信息。我们已经为Edit 打上了Authorize属性，也就是说用户是需要登录才能访问这个Action的。从普通开发的角度来看，这个程序是不会有什么问题的，我们首先通过正常渠道添加了一个用户。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e887c149c_5e4d414cgw1eqnq4hdin0j209m03fglr.jpg)

接下来，很雷很雷的事情发生了。你收到一封邮件说你中奖了，给了你一个链接，或者在某个网站上本身就嵌入了一些恶意代码，而你不幸手一抖，就点了。接下来结果有可能是这样滴。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0480a208b2_5e4d414cgw1eqnq4hrupnj20cr03x3ys.jpg)

你的数据很轻松就被篡改了。如果账号是有余额的，你就哭吧。来看看这个页面 是如何实现的。

![](http://ww1.sinaimg.cn/mw690/5e4d414cgw1eqnq4i4wogj20lu0bi41w.jpg)

非常的简单，我们只需要将form的action指向实际的action就可以了。这个页面一旦被加载，这个表单就会自动提交，那我们的数据就被黑了，一切都是那么的简单。

**如何避免？**

ASP.NET MVC 为我们提供了Html.AntiForgeryToken() 方法，我们只需要在form中添加这句话。MVC 会为我们生成一个唯一标识放在form中的一个隐藏域中，该标识还会被存放到cookie中在客户端和服务器的请求中传输。另外我们要做的就是为我们的Action打上ValidateAntiForgeryToken的属性。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/02147368e7_5e4d414cgw1eqnq4iqmlgj20kp0dctbx.jpg)

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b75b53d65e_5e4d414cgw1eqnq4jzswlj20ca06hjs7.jpg)

如果请求不包含这个cookie，那服务器就会拒绝这个请求，从而避免CSRF的攻击。

![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be600c6631_5e4d414cgw1eqnq4kg5mlj20o309477w.jpg)

### 相关文章

  * [ASP.Net MVC开发基础学习笔记（1）：走向MVC模式](http://blog.jobbole.com/84992/)
  * [2011年.NET社区回顾：韬光养晦的一年](http://blog.jobbole.com/13591/)
  * [.NET开发者必备的工具箱](http://blog.jobbole.com/84030/)
  * [ASP.Net MVC开发基础学习笔记（5）：区域、模板页与WebAPI初步](http://blog.jobbole.com/85008/)
  * [ASP.Net MVC开发基础学习笔记（4）：校验、AJAX与过滤器](http://blog.jobbole.com/85005/)
  * [.Net 开发者必备的11款开发工具](http://blog.jobbole.com/18232/)
  * [使用缓存的9个误区（上）](http://blog.jobbole.com/17487/)
  * [ASP.Net请求处理机制初步探索之旅（5）：ASP.Net MVC请求处理流程](http://blog.jobbole.com/85033/)
  * [ASP.Net MVC开发基础学习笔记（3）：Razor视图引擎、控制器与路由机制学习](http://blog.jobbole.com/84991/)
  * [ASP.Net MVC开发基础学习笔记（2）：HtmlHelper与扩展方法](http://blog.jobbole.com/84997/)

[ASP.NET 安全](http://blog.jobbole.com/85573/)，首发于[博客 – 伯乐在线](http://blog.jobbole.com)。
