1 验证
一般采用表单验证完成登陆验证, 建议结合 SSL 使用为限制控制器只能执行 HTTPS, 使用 RequireHttpsAttribute
2 授权
对账户的权限的控制可以通过在控制器或控制器操作上加 AuthorizeAttribute 属性
扩展授权过滤器
扩展授权过滤器可以定义继承自 AuthorizeAttribute 的类, 也可以定义同时继承自 FilterAttribute, IAuthorizationFilter 接口的类
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
- public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
- {
- public AuthorizeAttribute();
- // 获取或设置有权访问控制器或操作方法的用户角色
- public string Roles { get; set; }
- // 获取此特性的唯一标识符
- public override object TypeId { get; }
- // 获取或设置有权访问控制器或操作方法的用户
- public string Users { get; set; }
- // 重写时, 提供一个入口点用于进行自定义授权检查
- // 返回结果: 如果用户已经过授权, 则为 true; 否则为 false
- // 异常: System.ArgumentNullException:httpContext 参数为 null
- protected virtual bool AuthorizeCore(HttpContextBase httpContext);
- // 处理未能授权的 HTTP 请求
- protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
- // 在过程请求授权时调用
- // 异常: System.ArgumentNullException:
- //filterContext 参数为 null
- public virtual void OnAuthorization(AuthorizationContext filterContext);
- // 返回结果: 对验证状态的引用
- // 异常: System.ArgumentNullException:
- // httpContext 参数为 null
- protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
- }
AuthorizeAttribute 提供了三个可重新的虚方法 AuthorizeCore,HandleUnauthorizedRequest,OnAuthorization, 那么在执行授权动作的过程中他们是如何被调用的呢? 看下源码的 OnAuthorization 方法, 发现在这个方法中先调用 AuthorizeCore, 然后调用 HandleUnauthorizedRequest 被调用了
- public virtual void OnAuthorization(AuthorizationContext filterContext)
- {
- if (filterContext == null)
- {
- throw new ArgumentNullException("filterContext");
- }
- // 如果子操作的缓存处于活动状态, 那么就抛出异常
- if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
- {
- throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
- }
- // 判断控制器或控制器操作是否允许匿名访问, 如果可以就 return
- bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
- if (skipAuthorization)
- {
- return;
- }
- // 进行权限验证
- if (AuthorizeCore(filterContext.HttpContext))
- {
- HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
- cachePolicy.SetProxyMaxAge(new TimeSpan(0));
- cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
- }
- else
- {// 处理未通过权限验证的情形
- HandleUnauthorizedRequest(filterContext);
- }
- }
当子操作缓存处于活动状态, 那么抛出异常然后检验是否可匿名访问, 如果可以匿名访问就不进行验证;
综合以上分析, 扩展 AuthorizeAttribute 要注意:
1) 在子类 AuthorizeCore 中, 调用父类的 AuthorizeCore 方法
base.OnAuthorization(filterContext);
2) 在子类的 AuthorizeCore 方法中验证用户的权限
3) 通过子类的构造函数传入用户的权限值
代码示例如下:
- public class CustomAuthorizeAttribute : AuthorizeAttribute
- {
- private UserRole role;
- public CustomAuthorizeAttribute(UserRole role)
- {
- this.role = role;
- }
- protected override bool AuthorizeCore(HttpContextBase httpContext)
- {
- bool ret = false;
- // 获得用户信息 (从本地 Session 或分布式缓存中获取)
- var userInfo = ......
- if(userInfo==null)
- {
- // 信息为 null, 一般认为登陆超时或没有登陆
- }
- if(userInfo.Role == UserRole.Org)
- {
- ret = true;
- }
- else
- {
- // 提示无权限
- }
- return ret;
- }
- protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
- {
- if (filterContext == null)
- {
- throw new ArgumentNullException("filterContext");
- }
- if (filterContext.HttpContext.Request.IsAjaxRequest())
- {// 针对 ajax 请求进行处理
- }
- else
- {// 非 aiax 进行处理
- // 跳转到指定页面
- string strUrl = ......;
- filterContext.Result = new RedirectResult(strUrl);
- }
- }
- public override void OnAuthorization(AuthorizationContext filterContext)
- {
- base.OnAuthorization(filterContext);
- }
- }
- public enum UserRole
- {
- Org = 1,
- Vip = 2,
- Guest = 3
- }
3 安全
总的原则:
所有层或各个子系统各自负责好自己的安全
任何用户数据和来自其他系统的数据都要经过检验
在满足需求的情况下, 尽量缩小账户的权限
减少暴露的操作数量和操作参数
关闭服务器不需要的功能
4 防范攻击
4.1 跨站脚本攻击 (XSS)
被动注入: 用户的输入含有恶意脚本, 而网站又能够不加检验地接受这样的输入, 进而保存到数据库中
主动注入: 用户将含有恶意脚本的内容输入到页面文本框中, 然后在屏幕上显示出来
防御方法:
1) 使用 Razor 语法输出的内容已经被编码, 可以不做任何其他处理
例如:
<h4>@Model.Field</h4>
html.ActionLink,Html.Action 等方法会将路由参数编码输出
2) 大部分的 XSS 攻击可通过对输入内容进行编码来阻止: Html.Encode,Html.AttributeEncode,Url.Encode
3) 对 Js 进行编码
使用 Ajax.JavaScriptStringEncode
4) 将 AntiXSS 库作为默认的编码器 (不建议使用, 不灵活)
ASP.NET 4.5 集成 Anti-XSS Library, 可以通过配置来对整个网站的输出进行编码
- <system.web>
- <httpRuntime targetFramework="4.5" encoderType="System.Web.Security.AntiXss.AntiXssEncoder,System.Web"/>
- </system.web>
4.2 跨站请求伪造 (CSRF/XSRF)
防御方法:
1) 使用 Html 隐藏域存储用户令牌, 令牌可以存储在 Session 里或者 cookie 里
2) 在视图表单中使用 @Html.AntiForgeryToken(), 在控制器操作上添加属性 [ValidateAntiForgeryToken], 注意表单一定要使用 @Html.BeginForm 生成
实现机制: AntiForgeryToken 方法向用户浏览器 cookie 中写入一个加密的数据, 并在表单内插入一个隐藏栏位, 每次刷新页面时隐藏栏位的值都不同, 每次执行控制器操作前, 都会验证隐藏栏位和浏览器 cookie 中的值是否相同, 只有相同才允许执行控制器操作
使用限制:
客户端浏览器不能禁用 cookie
只对 post 请求有效
若有 XSS 漏洞, 则可轻易获取令牌
对 Ajax 请求不能传递令牌, 即对 Ajax 无效
3) 使用幂等的 Get 请求, 仅使用 Post 请求修改数据 (仅仅是一定程度上限制这种攻击而已)
4) 使用动作过滤器, 验证 UrlReferrer
扩展的动作过滤器:
- public class CSRFFilter:AuthorizeAttribute
- {
- public override void OnAuthorization(AuthorizationContext filterContext)
- {
- if (filterContext.HttpContext == null)
- {
- throw new HttpException("请求无效");
- }
- if (filterContext.HttpContext.Request.UrlReferrer == null)
- {
- throw new HttpException("请求无效");
- }
- if (filterContext.HttpContext.Request.UrlReferrer.Host != "sit.com")
- {
- throw new HttpException("来自非法网站");
- }
- }
- }
4.3 cookie 盗窃
cookie 有两种形式
1) 会话 cookie: 存储在浏览器内存中, 浏览器每次请求通过 Http 头进行传递
2) 持久性 cookie: 存储在硬盘上, 同样通过 Http 头进行传递
二者的区别: 会话 cookie 常在会话结束时失效, 而持久性 cookie 在下一次访问站点时仍然有效
被窃取的原因: 依赖于 XSS 漏洞, 注入一段恶意脚本就能窃取
防御方法:
1) 在 web.config 对 cookie 进行设置
<httpCookies httpOnlyCookies="true"/>,httpOnlyCookies 指定为 true 表达仅服务器可以访问, 浏览器无法访问
2) 在编写代码时为每个 cookie 单独设置
- Response.Cookies["cok"].Value = Guid.NewGuid().ToString();
- Response.Cookies["cok"].HttpOnly = true;
4.4 重复提交
防御方法:
1) 使用 bind 特性, 设置想要绑定的属性来, 防止这种攻击也可以设置不要绑定的字属性, 但优先选择设置要绑定的属性
例:
可以指定多个字段, 用逗号分隔
- public ActionResult TestViewData([Bind(Include = "Field,Field1,Field1")]ModelF mf)
- {
- ......
- }
2) 使用 UpdateModel 或 TryUpdateModel
3) 使用 ViewModel, 明确规定 View 使用的数据模型
4.5 开放重定向
防御方法:
使用 Url.IsLocalUrl 检测是否为本地 url
4.6 SQL 注入攻击
防御方法:
通过参数注入非法获得或修改网站数据
使用参数化查询来防止 SQL 注入攻击
参考:
1.Jess Chadwick/Todd Snyder/Hrusikesh Panda, 徐雷 / 徐扬
译 ASP.NET MVC4 Web 编程
2.Jon Galloway/Phil Haack/Brad Wilson/K. Scott Allen, 孙远帅 / 邹权译 ASP.NET MVC4 高级编程 (第四版)
3. 黄保翕, ASP.NET MVC4 开发指南
4. 蒋金楠, ASP.NET MVC4 框架揭秘
- 5.https://www.asp.net/mvc
- -----------------------------------------------------------------------------------------
来源: https://www.cnblogs.com/hdwgxz/p/8637421.html