• ASP.NET MVC编程——验证、授权与安全


    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提供了三个可重新的虚方法AuthorizeCoreHandleUnauthorizedRequestOnAuthorization,那么在执行授权动作的过程中他们是如何被调用的呢?看下源码的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.EncodeHtml.AttributeEncodeUrl.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.configcookie进行设置

    <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)使用UpdateModelTryUpdateModel

    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

    转载与引用请注明出处。
    
    时间仓促,水平有限,如有不当之处,欢迎指正。
  • 相关阅读:
    linux本地文件上传之RZ/SZ和sftp
    sql优化
    sql server 类oracle vm_contact() 函数创建
    sql server 执行大.sql文件
    group by having和connect by
    sql server内置函数
    oracle内置函数
    oracle字符串处理函数
    oracle字符串处理相关
    团队-象棋游戏-模块开发过程
  • 原文地址:https://www.cnblogs.com/hdwgxz/p/8637421.html
Copyright © 2020-2023  润新知