ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
面对信息化时代,稍不注意就会脱轨,所以及时的补充知识才能让我们与时俱进,今天给大家带来的是关于token可以被窃取吗和盗取token的一篇文章,相信会给你带来较大的帮助! ## 11 | 登录前端实现 前端任务点,编写登录请求函数,和 用户注册 类似,前端拿到用户名和密码发起 POST 请求。 收到 token 如何持久化存储,如何让每次请求都携带 token 是这里的点。 用户登录的接口详情可以点 这里 。 这里有可以优化的点,未来可能需要添加验证码等附加信息,这个时候就需要添加函数参数,就会比较麻烦,可以将参数数据格式包装成一个对象。当然,这里还是使用第一种方法了。 这不是重点,重点是登录成功后,我们要做的事情。 按照接口约定,登录成功我们可以得到如下信息: 这里我们要用到 token 字段,是我们现在有 token 了,但一刷新就没了,所以我们要做一下持久化存储,你想存哪里就存哪里,只要你能找到。这里就存储 localStorage 中了,在 Chorme86 中你甚至可以存到一个本地的文本文件中,只不过读取速度比较慢罢了。 除了 token,我们还要将用户信息存下来,比如首页展示用的用户头像等信息。 关于本地信息的安全性问题,本地保存的用户信息并不作为数据请求的凭证,仅供展示使用,当用户更改本地的用户信息对于登录的状态不会有影响,因为后端的判断依据是 token,token 有效就登录成功,而不是说本地存储的用户信息是谁服务端就认为你是谁,前端是不可信的。这种登录方式的危险点在于用户 token 被盗,但这很难避免,最不安全的是人。。。 登录成功,返回首页,用户名或者是用户头像并没有同步更新,这是因为,这里是单页应用,你在 login 页面将登录用户信息存到 localStorage 中,然后跳转到了首页,此时页面没有刷新,而 localStorage 中的信息没有及时更新到 DOM 中,此时的用户信息还是你没有进入 login 页面的用户信息,自然是无法展示的,怎么解决呢?很简单,刷新一下。 当页面刷新时,用户信息会从 localStorage 中读取,显示的就是现在的登录用户了,但。。。 我不想刷新。 也很简单,搞成响应式数据就好了呀。来人呀,上Vuex。 当你将 token 存在 cookie 中,前端并不需要主动设置,默认就携带传给了服务端,而这里我们存到 Authorization 中,就需要我们设置一下,拦截请求,在请求发送前添加 token。 好的,来捋一捋流程。 用户访问 /login,被前端路由处理,指向Login.vue,用户看到登录框,填入自己的账号,当用户填写账号时,name password被实时监听,同时会对登录按钮的可操作产生影响,只有当用户将账密输入完整时,登录按钮可用。 前端收集用户信息,调用 network 中封装的 longin 请求函数,该请求发送前被拦截,添加 token,可能为空,使用账密登录时,token没实际效用。 后端检查成功给响应,前端将响应中数据的 token 通过触发 mutations 更新 Vuex 中 state,同时,将该 token 存到 localStorage,以免用户关掉页面导致 token 丢失。 登录成功跳到应用首页,用户头像等信息通过 Vuex 获取,因为 Vuex 中的数据是响应式的,此时从 login 跳转到首页,用户头像等信息也会得到相应的更新。 当用户新增文章时,只需向服务器传文章数据就可以了,而对于文章作者的相关信息则由后端从请求头中的 token 解析得到,这里需要注意,前端不要将本地的用户信息作为准确的作者信息,对于用户可以伪造的信息要做最小化的信任,用户完全有能力将本地用户名从张三改为李四,而最终作者是那个则需要由用户提供的 token 来判定,虽说 token 也有可能被伪造,但难度相对较大,往往是被窃取的可能性更大。 无密码登录其实还是需要“密码”的,只不过是换了一个临时性的对人不可读的字符串来代替罢了,并且每次请求帮你填好了。 在不考虑安全性的情况下本质上其实就是你将密码存到了浏览器里,然后你每次访问网站时让浏览器帮你输入用户名和密码,这个过程你是无感知的,这样自己就不用像个憨憨一样每次刷新就要填一遍表单。 填表是一件非常无聊的事。 要学一波 TypeScript 了呀。 ![](https://www.bangqike.com//d/file/p/2022/11/9154429506333704236.jpeg) ## 鉴权必须了解的 5 个兄弟:cookie、session、token、jwt、单点登录 本文你将看到: \*\*「前端存储」\*\*这就涉及到一发、一存、一带,发好办,登陆接口直接返回给前端,存储就需要前端想办法了。 前端的存储方式有很多。 有,cookie。cookie 也是前端存储的一种,但相比于 localStorage 等其他方式,借助 HTTP 头、浏览器能力,cookie 可以做到前端无感知。一般过程是这样的: 「配置:Domain / Path」 cookie 是要限制::「空间范围」::的,通过 Domain(域)/ Path(路径)两级。 「配置:Expires / Max-Age」 cookie 还可以限制::「时间范围」::,通过 Expires、Max-Age 中的一种。 「配置:Secure / HttpOnly」 cookie 可以限制::「使用方式」::。 \*\*「HTTP 头对 cookie 的读写」\*\*回过头来,HTTP 是如何写入和传递 cookie 及其配置的呢?HTTP 返回的一个 Set-Cookie 头用于向浏览器写入「一条(且只能是一条)」cookie,格式为 cookie 键值 配置键值。例如: 那我想一次多 set 几个 cookie 怎么办?多给几个 Set-Cookie 头(一次 HTTP 请求中允许重复) HTTP 请求的 Cookie 头用于浏览器把符合当前「空间、时间、使用方式」配置的所有 cookie 一并发给服务端。因为由浏览器做了筛选判断,就不需要归还配置内容了,只要发送键值就可以。 \*\*「前端对 cookie 的读写」\*\*前端可以自己创建 cookie,如果服务端创建的 cookie 没加HttpOnly,那恭喜你也可以修改他给的 cookie。调用document.cookie可以创建、修改 cookie,和 HTTP 一样,一次document.cookie能且只能操作一个 cookie。 调用document.cookie也可以读到 cookie,也和 HTTP 一样,能读到所有的非HttpOnly cookie。 现在回想下,你刷卡的时候发生了什么? 这种操作,在前后端鉴权系统中,叫 session。典型的 session 登陆/验证流程: \*\*「Session 的存储方式」\*\*显然,服务端只是给 cookie 一个 sessionId,而 session 的具体内容(可能包含用户信息、session 状态等),要自己存一下。存储的方式有几种: 「Session 的过期和销毁」\*\*很简单,只要把存储的 session 数据销毁就可以。\*\*\*\*「Session 的分布式问题」\*\*通常服务端是集群,而用户请求过来会走一次负载均衡,不一定打到哪台机器上。那一旦用户后续接口请求到的机器和他登录请求的机器不一致,或者登录请求的机器宕机了,session 不就失效了吗?这个问题现在有几种解决方式。 但通常还是采用第一种方式,因为第二种相当于阉割了负载均衡,且仍没有解决「用户请求的机器宕机」的问题。\*\*「node.js 下的 session 处理」\*\*前面的图很清楚了,服务端要实现对 cookie 和 session 的存取,实现起来要做的事还是很多的。在npm中,已经有封装好的中间件,比如 express-session - npm,用法就不贴了。这是它种的 cookie: express-session - npm 主要实现了: session 的维护给服务端造成很大困扰,我们必须找地方存放它,又要考虑分布式的问题,甚至要单独为了它启用一套 Redis 集群。有没有更好的办法? 回过头来想想,一个登录场景,也不必往 session 存太多东西,那为什么不直接打包到 cookie 中呢?这样服务端不用存了,每次只要核验 cookie 带的「证件」有效性就可以了,也可以携带一些轻量的信息。这种方式通常被叫做 token。 token 的流程是这样的: \*\*「客户端 token 的存储方式」 在前面 cookie 说过,cookie 并不是客户端存储凭证的唯一方式。token 因为它的「无状态性」,有效期、使用限制都包在 token 内容里,对 cookie 的管理能力依赖较小,客户端存起来就显得更自由。但 web 应用的主流方式仍是放在 cookie 里,毕竟少操心。 「token 的过期」\*\*那我们如何控制 token 的有效期呢?很简单,把「过期时间」和数据一起塞进去,验证时判断就好。 编码的方式丰俭由人。\*\*「base64」\*\*比如 node 端的 cookie-session - npm 库 默认配置下,当我给他一个 userid,他会存成这样: 这里的 eyJ1c2VyaWQiOiJhIn0=,就是 {"userid":"abb”} 的 base64 而已。 「防篡改」 是的。所以看情况,如果 token 涉及到敏感权限,就要想办法避免 token 被篡改。解决方案就是给 token 加签名,来识别 token 是否被篡改过。例如在 cookie-session - npm 库中,增加两项配置: 这样会多种一个 .sig cookie,里面的值就是 {"userid":"abb”} 和 iAmSecret通过加密算法计算出来的,常见的比如HMACSHA256 类 (System.Security.Cryptography) | Microsoft Docs。 好了,现在 cdd 虽然能伪造出eyJ1c2VyaWQiOiJhIn0=,但伪造不出 sig 的内容,因为他不知道 secret。\*\*「JWT」\*\*但上面的做法额外增加了 cookie 数量,数据本身也没有规范的格式,所以 JSON Web Token Introduction - jwt.io 横空出世了。 它是一种成熟的 token 字符串生成方案,包含了我们前面提到的数据、签名。不如直接看一下一个 JWT token 长什么样: 这串东西是怎么生成的呢?看图: 类型、加密算法的选项,以及 JWT 标准数据字段,可以参考 RFC 7519 - JSON Web Token (JWT)node 上同样有相关的库实现:express-jwt - npm koa-jwt - npm token,作为权限守护者,最重要的就是「安全」。业务接口用来鉴权的 token,我们称之为 access token。越是权限敏感的业务,我们越希望 access token 有效期足够短,以避免被盗用。但过短的有效期会造成 access token 经常过期,过期后怎么办呢?一种办法是,让用户重新登录获取新 token,显然不够友好,要知道有的 access token 过期时间可能只有几分钟。另外一种办法是,再来一个 token,一个专门生成 access token 的 token,我们称为 refresh token。 有了 refresh token 后,几种情况的请求流程变成这样: 如果 refresh token 也过期了,就只能重新登录了。 session 和 token 都是边界很模糊的概念,就像前面说的,refresh token 也可能以 session 的形式组织维护。狭义上,我们通常认为 session 是「种在 cookie 上、数据存在服务端」的认证方案,token 是「客户端存哪都行、数据存在 token 里」的认证方案。对 session 和 token 的对比本质上是「客户端存 cookie / 存别地儿」、「服务端存数据 / 不存数据」的对比。\*\*「客户端存 cookie / 存别地儿」\*\*存 cookie 固然方便不操心,但问题也很明显: 存别的地方,可以解决没有 cookie 的场景;通过参数等方式手动带,可以避免 CSRF 攻击。 「服务端存数据 / 不存数据」 前面我们已经知道了,在同域下的客户端/服务端认证系统中,通过客户端携带凭证,维持一段时间内的登录状态。但当我们业务线越来越多,就会有更多业务系统分散到不同域名下,就需要「一次登录,全线通用」的能力,叫做「单点登录」。 简单的,如果业务系统都在同一主域名下,比如wenku.baidu.com tieba.baidu.com,就好办了。可以直接把 cookie domain 设置为主域名 baidu.com,百度也就是这么干的。 比如滴滴这么潮的公司,同时拥有didichuxing.com xiaojukeji.com didiglobal.com等域名,种 cookie 是完全绕不开的。这要能实现「一次登录,全线通用」,才是真正的单点登录。这种场景下,我们需要独立的认证服务,通常被称为 SSO。 「一次「从 A 系统引发登录,到 B 系统不用登录」的完整流程」 \*\*「完整版本:考虑浏览器的场景」\*\*上面的过程看起来没问题,实际上很多[](https://www.bangqike.com/caijing/130385.html)[app](https://www.bangqike.com/caijing/130385.html)等端上这样就够了。但在浏览器下不见得好用。看这里: 对浏览器来说,SSO 域下返回的数据要怎么存,才能在访问 A 的时候带上?浏览器对跨域有严格限制,cookie、localStorage 等方式都是有域限制的。这就需要也只能由 A 提供 A 域下存储凭证的能力。一般我们是这么做的: 图中我们通过颜色把浏览器当前所处的域名标记出来。注意图中灰底文字说明部分的变化。 谢谢大家哦 ## [](https://www.bangqike.com/caijing/130385.html)[app](https://www.bangqike.com/caijing/130385.html)怎样防止token被盗取? token是个凭条,不过它比门票温柔多了,门票丢了重新花钱买,token丢了重新操作下认证一个就可以了,因此token丢失的代价是可以忍受的——前提是你别丢太频繁,要是让用户隔三差五就认证一次那就损失用户体验了。 客户端方面这个除非你有一个非常安全的办法,比如操作系统提供的隐私数据存储,那token肯定会存在泄露的问题。比如我拿到你的手机,把你的token拷出来,在过期之前就都可以以你的身份在别的地方登录。 解决这个问题的一个简单办法 1、在存储的时候把token进行对称加密存储,用时解开。 2、将请求URL、时间戳、token三者进行合并加盐签名,服务端校验有效性。 这两种办法的出发点都是:窃取你存储的数据较为容易,而反汇编你的程序hack你的加密解密和签名算法是比较难的。然而其实说难也不难,所以终究是防君子不防小人的做法。话说加密存储一个你要是被人扒开客户端看也不会被喷明文存储…… 方法1它拿到存储的密文解不开、方法2它不知道你的签名算法和盐,两者可以结合食用。 但是如果token被人拷走,他自然也能植入到自己的手机里面,那到时候他的手机也可以以你的身份来用着,这你就瞎了。 于是可以提供一个让用户可以主动expire一个过去的token类似的机制,在被盗的时候能远程止损。 话说一个人连自己手机都保护不好还谈什么安全…… 在网络层面上token明文传输的话会非常的危险,所以建议一定要使用HTTPS,并且把token放在post body里。 ## JWT-token—前后端分离架构的api安全问题 前后端分离架构带来的好处一搜一大堆,我们来看一下分离后后端接口的安全问题。 前后端分离架构现状: 这样的情况后端api是暴露在外网中,因为常规的web项目无论如何前端都是要通过公网访问到后台api的,带来的隐患也有很多。 1.接口公开,谁都可以访问 2.数据请求的参数在传输过程被篡改 3.接口被重复调用 ... session和cookie都是客户端与服务端通讯需要提供的认证,当客户端的值和服务器的值吻合时,才允许请求api,解决了第1个问题,但是当攻击者获取到了传输过程中的session或者cookie值后,就可以进行第2、3种攻击了 JWT标准的token包含三部分: 头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等 将上面的JSON对象进行 \[base64编码\] 可以得到下面的字符串。这个字符串我们将它称作JWT的Header Payload也是一个JSON对象。包含了一些其他的信息 这里面的前五个字段都是由JWT的标准所定义的。 将上面的JSON对象进行 \[base64编码\] 可以得到下面的字符串。这个字符串我们将它称作JWT的Payload 将上面的两个编码后的字符串都用句号 . 连接在一起(头部在前),就形成了 最后,我们将上面拼接完的字符串用 HS256算法 进行加密。在加密的时候,我们还需要提供一个 密钥(secret) 。如果我们用 mystar 作为密钥的话,那么就可以得到我们加密后的内容 这一部分叫做 签名 最后将这一部分签名也拼接在被签名的字符串后面,我们就得到了完整的JWT 签名解决了数据传输过程中参数被篡改的风险 一般而言,加密算法对于不同的输入产生的输出总是不一样的,如果有人 对Header以及Payload的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。 而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。 解决了篡改数据的问题,还有第3个问题,那就是攻击者不修改数据,只是重复攻击 比如在浏览器端通过用户名/密码验证获得签名的Token被木马窃取。即使用户登出了系统,黑客还是可以利用窃取的Token模拟正常请求,而服务器端对此完全不知道, 因为JWT机制是无状态的。 可以在Payload里增加时间戳并且前后端都参与来解决: ## php中的token怎么用 token一般理解为通行证,经过各种算法处理的唯一加密的字符串 比如用户登录,你只需cookie记录用户uid 和 token token没有超时的话,不用验证密码直接登录 这样也能保证用户信息、密码不被cookie窃取 token可以被窃取吗的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于盗取token、token可以被窃取吗的信息别忘了在本站进行查找喔。