认证与鉴权
一、什么是认证、什么是授权
1、认证(Authentication)
用户认证,就是验证此用户的身份。解决的是‘我是谁’的问题。就是从用户请求信息中获取用户信息的过程,认证是一个过程。
举个栗子🌰:当你在登录时,输入用户名密码,系统判断你的用户名与密码是否在已有的用户内并给出结果反馈,这个过程就是用户认证。
用户名+密码登录,手机、邮箱验证码,第三方登录等都属于用户认证的一种。
2、授权(Authorization)
用户授权,就是授予用户权限,能够进行后续的某些访问和操作。解决的是“我能干那些事”的问题。就是从获取到用户信息到授予用户权限的过程。
举个栗子🌰:每天乘电梯刷卡,刷卡的过程就是授权,授予了我们访问某某层的权限。就相当于是某个人或者某个机构赋予某人干某事的权限的过程。
认证 | 授权 |
---|---|
身份验证确认您的身份以授予对系统的访问权限 | 授权确定您是否有权访问资源 |
这是验证用户凭据以获得用户访问权限的过程 | 这是验证是否允许访问的过程 |
它决定用户是否是他声称的用户 | 它确定用户可以访问和不访问的内容 |
身份认证通常需要用户名和密码 | 授权所需的身份验证因素可能有所不同,具体取决于安全级别 |
身份认证是授权的第一步,因此始终是第一步。 | 授权在认证成功后完成。 |
二、什么是Cookie、什么是Session
凭证
实现认证和授权的前提是需要一种**媒介(证书)**来标记访问者的身份,这个媒介(证书)就是凭证
在互联网应用中,常见的就是在登录之后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌。
1、Cookie
- HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
- **cookie 存储在客户端:**cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
- **cookie 是不可跨域的:**每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)
2、Session
当我们使用Cookie时,实际就是服务端向访它他的客户端给与一个通行凭证,无论谁访问都必须携带自己通行凭证。这样服务器就能从通行凭证上确认客户身份了。这就是Cookie的工作原理
cookie 可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果 Cookie 很多,这无形地增加了客户端与服务端的数据传输量,由此就诞生了Session来解决这样的问题,
Session的原理是当同一个客户端每次和服务端交互时,不需要每次都传回所有的 Cookie 值,而是只要传回一个 ID,这个 ID 是客户端第一次访问服务器的时候生成的, 而且每个客户端是唯一的。这样每个客户端就有了一个唯一的 ID,客户端只要传回这个 ID 就行。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端里的请求里是否已包含了一个session标识–sessionID,如果已经包含一个sessionID,则说明以前已经为此客户端创建过session,服务器就按照sessionID把这个session检索出来使用如果客户端请求不包含sessionID,则为此客户端创建一个session并且声称一个与此session相关联的sessionID,
sessionID的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串(服务器会自动创建),这个sessionID将被在本次响应中返回给客户端保存。
3、Cookie 和 Session 的区别
- **安全性:**Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
- 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
- **有效期不同:**Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
- **存储大小不同:**单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
三、什么是Token
token是在访问服务端资源时候需要携带的一种验证凭证
简单的token组成:userID(用于标识唯一的用户身份)+time(当前时间的时间戳)+sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
验证流程
1.客户端使用用户名跟密码请求登录
2.服务端收到请求,去验证用户名与密码
3.验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
4.客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
5.客户端每次向服务端请求资源的时候需要带着服务端签发的 token
6.服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
- 每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里
- 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
- token 完全由应用管理,所以它可以避开同源策略
Token 和 Session 的区别
- Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token使服务端无状态化,不会存储会话信息。
- Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。
- 所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂且认为是安全的。而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的。不可以转移到其它 App上,也不可以转到其它用户上。Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。所以简单来说:如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了。
四、什么是JWT
JWT全称为:JSON Web Token。适合分布式的授权模式。是目前最流行的跨域认证解决方案
用户登录成功后,认证服务器会返回一个带有签名认证的JWT。JWT保存在客户端(如浏览器或APP),每次访问应用服务器时,将JWT放到http的header 的Authorization 字段里面。
Authorization: Bearer <token>
不同于Session的集中管理,JWT自身就包含了用户信息,每台应用服务器可以自己独自判断JWT是哪个用户、是否合法、是否过期,无需再向认证服务器确认,也没有Session同步的问题。JWT至少包含以下信息:
- sub: Subject,一般为用户ID。
- exp: Expiration Time。过期时间。
- signature: 签名。用于验证JWT是否合法。
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
使用JWT
1、在请求时在请求头的Authorization 带上token
2、可以在url上带上token字段
3、也可在跨域的时候放在Post请求的请求体内
五、实践是检验真理的唯一方式
1、cookie实践
设置格式:this.ctx.cookies.set(key,value,options)
获取格式: this.ctx.cookies.get(key)
如果在设置的时候加密了 需要 this.ctx.cookies.get(key,{encrypt: true})
清除格式:this.ctx.cookies.set(key,null)
// 设置
this.ctx.cookies.set('auth', 'test', {maxAge: 24 * 3600 * 1000, // 过期时间1天httpOnly: true,signed: true, // 对cookie进行签名,防止被修改encrypt: true, // 对cookie进行加密, 如果加密,则在获取的时候需要对cookie进行解密});
// 获取
this.ctx.cookies.get('auth',{encrypt: true}
// 清除
this.ctx.cookies.set('auth',null}
options参数 maxAge: 设置这个键值对在浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。 expires: 设置这个键值对的失效时间,如果设置了 maxAge,expires 将会被覆盖。如果 maxAge 和 expires 都没设置,Cookie 将会在浏览器的会话失效(一般是关闭浏览器时)的时候失效。 path: 设置键值对生效的 URL 路径,默认设置在根路径上(/),也就是当前域名下的所有 URL 都可以访问这个 Cookie。 domain: 设置键值对生效的域名,默认没有配置,可以配置成只在指定域名才能访问。 httpOnly: 设置键值对是否可以被 js 访问,默认为 true,不允许被 js 访问。 secure: 设置键值对只在 HTTPS 连接上传输,框架会帮我们判断当前是否在 HTTPS 连接上自动设置 secure 的值。 除了这些属性之外,框架另外扩展了 3 个参数的支持:
overwrite:设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头。 signed:设置是否对 Cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true。 encrypt:设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false。
我们来使用node写三个接口
router.get('/api/user/setauth', controller.user.SetAuth);router.get('/api/user/auth', _Cookie, controller.user.Auth);router.get('/api/user/clearauth', _Cookie, controller.user.ClearAuth);
// _Cookie是一个校验cookies的中间件 如果请求不带cookie 就会被请求拦截
public async SetAuth() {this.ctx.cookies.set('auth', 'test', {maxAge: 24 * 3600 * 1000, // 过期时间1天httpOnly: true,signed: true, // 对cookie进行签名,防止被修改encrypt: true, // 对cookie进行加密, 如果加密,则在获取的时候需要对cookie进行解密});this.ctx.body = { message: '设置cookie成功', code: 200 };}public async Auth() {// cookieconst cookie = this.ctx.cookies.get('auth', { encrypt: true });this.ctx.body = { message: `刚才设置的cookie是: ${cookie}`, code: 200 };}public async ClearAuth() {// cookiethis.ctx.cookies.set('auth', null);this.ctx.body = { message: 'cookie清除成功', code: 200 };}
我们先请求/api/user/setauth
来将cookie设置好
然后我们再请求·/api/uset/auth
来查看刚才设置的cookie
然后我们再请求/api/user/clearauth
来清除设置好的cookie
最后我们再次请求/api/user/auth
此次请求就会被中间件拦截
2、session实践
设置格式:this.ctx.session.[key]=value
获取格式: this.ctx.cookies.[key]
// 设置 session可以设置多种数据类型this.ctx.session.auth = 'test';
// 获取
const sessionvalue = this.ctx.session.auth//配置session的很多配置与Cookie相似 可以参考cookie config.session = {// 设置session cookis里面的keykey: 'SESSION_KEY',// 设置过期时间maxAge: 24 * 3600 * 1000,httpOnly: true,// 设置是否加密encrypt: true,// 设置每次刷新页面的时候session是否都会被延期renew: true,};
我们依旧来使用node写两个接口
router.get('/api/user/setsession', controller.user.setSession);
router.get('/api/user/session', controller.user.getSession);
public async setSession() {this.ctx.session.auth = 'test';this.ctx.body = { message: '设置session成功', code: 200 };}public async getSession() {const session = this.ctx.session.auth;this.ctx.body = { message: `刚才设置的session是: ${session}`, code: 200 };}
我们先来请求/api/user/setsession
可以看到session已经设置成功
接下来我们请求 /api/user/session
来获取刚才生成的session
此时可以看到,我们可以获取到设置的session值,并且请求的cookie里已经写入了SESSION_KEY
3、jwt实践
设置格式: app.jwt.sign(options,sectet)
获取内容格式:app.jwt.verify(token,sectet)
不同的框架 ,设置的方法有所不同
// 设置
const token = app.jwt.sign({userid,exp: Math.floor(Date.now() / 1000) + (24 * 60 * 60), // token 有效期为 24 小时// exp: Math.floor(Date.now() / 1000) + 10, // 测试 --- token 有效期为 10秒}, app.config.jwt.secret,);
// 解密获取
const tokenvalue = ctx.app.jwt.verify(token, secret);
我们依旧使用Node来写两个接口
router.post('/api/user/login', controller.user.Login);router.post('/api/user/getUserInfo', _jwt, controller.user.GetUserInfo);
// _jwt是验证token的中间件
import { Context } from 'egg';
const consola = require('consola');
const JwtCheck = (secret: string) => {return async (ctx: Context, next: any) => {const token = ctx.request.header.authorization as string; // 拿到tokenlet decode = '';if (token !== 'null' && token) {try {const formatToken = token.split(' ')[1];// 解密 tokendecode = ctx.app.jwt.verify(formatToken, secret);ctx.decode = decode;await next();} catch (error) {consola.error(error);if (error.name === 'TokenExpiredError') {consola.info('Token过期!');ctx.body = {msg: 'token已过期,请重新登录',code: 401,};return;}ctx.body = {msg: 'token已失效,请重新登录',code: 401,};return;}} else {ctx.body = {code: 401,msg: 'token不存在',};return;}};
};
export default JwtCheck;
public async Login() {const { ctx, app } = this;const { userid } = ctx.request.body;consola.log('userid', userid);// 生成 tokenconst token = app.jwt.sign({userid,exp: Math.floor(Date.now() / 1000) + (24 * 60 * 60), // token 有效期为 24 小时// exp: Math.floor(Date.now() / 1000) + 10, // 测试 --- token 有效期为 10秒}, app.config.jwt.secret);ctx.body = { message: '登录成功!', code: 1, data: { token } };}// 获取用户信息public async GetUserInfo() {const ctx = this.ctx;ctx.body = { message: `获取成功,登录的用户的用户ID为:${ctx.decode.userid}`, code: 1 };}
首先我们通过调用/api/user/login
登录接口来设置token
然后我们来调用接口/api/user/getUserInfo
来判断token的有效性并获取userid
记得要在请求头的 Authorization字段加上 Bearer
就可以看到我们登录的userid 😀参考文章: www.cnblogs.com/xosg/p/1025…
blog.csdn.net/jnshu_it/ar…学习网络安全技术的方法无非三种:
第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。
第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
第三种就是去找培训。
接下来,我会教你零基础入门快速入门上手网络安全。
网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。
第一阶段:基础准备 4周~6周
这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
第二阶段:web渗透
学习基础 时间:1周 ~ 2周:
① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
配置渗透环境 时间:3周 ~ 4周:
① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。
渗透实战操作 时间:约6周:
① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
以上就是入门阶段
第三阶段:进阶
已经入门并且找到工作之后又该怎么进阶?详情看下图
给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!