https://coolshell.cn/articles/19395.html
HTTP Basic
就是使用 username
和 password
来进行登录
技术原理
1 拼接username和 password, username:password(用冒号分隔)
2 Base64编码, Base64("username:password")
3 放到HTTP头中, Authorization: Basic aGFvZW86Y29vbHNoZWxsCg
4 服务端验证
但是Base64
不是加密协议,而是编码协议
,所以就算是有HTTPS作为安全保护,给人的感觉还是不放心
Digest Access HTTP 摘要认证
原理
-
1 调用方
发起一个普通的HTTP请求
-
2 服务端返回错误, 且在HTTP头里的 WWW-Authenticate 包含如下信息
WWW-Authenticate: Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" nonce 为服务器端生成的随机数
-
3 客户端做加密
HASH1=MD5(MD5(username:realm:password):nonce:cnonce)
cnonce 客户端生成的随机数
-
4 如果
qop
中包含了auth
做 HASH2=MD5(method:digestURI)
method 就是HTTP的请求方法(GET/POST…),digestURI 是请求的URL
- 5 如果
qop
中包含了auth-init
做 HASH2=MD5(method:digestURI:MD5(entityBody))
entityBody 就是HTTP请求的整个数据体
- 6 得到 response
` response = MD5(HASH1:nonce:nonceCount:cnonce:qop:HASH2)`
没有 qop
则 response = MD5(HA1:nonce:HA2)
-
7 客户端向服务端请求
GET /dir/index.html HTTP/1.0 Host: localhost Authorization: Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="%2Fcoolshell%2Fadmin", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41"
App Secret Key + HMAC
用于给消息签名的技术
保证消息在传递的过程中没有被人修改, 对消息进行一个MAC算法,得到一个摘要字串,然后,接收方得到消息后,进行同样的计算,然后比较这个MAC字符串
-
把
HTTP的请求(方法、URI、查询字串、头、签名头,body)
打个包叫CanonicalRequest
,作个SHA-256
的签名,然后再做一个base16的编码
-
把上面的这个签名和签名算法 AWS4-HMAC-SHA256、时间戳、Scop,再打一个包,叫
StringToSign
。 -
准备签名,用
AWSSecretAccessKey
来对日期签一个DataKey
,再用 DataKey 对要操作的Region签一个DataRegionKey
,再对相关的服务签一个DataRegionServiceKey
,最后得到 SigningKey. -
用第三步的
SigningKey
来对第二步的StringToSign
签名。
-
HTTP Request
Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
AKIDEXAMPLE 是 AWS Access Key ID
服务器端会根据这个AppID来查相关的 Secret Access Key,然后再验证签名
JWT – JSON Web Tokens
-
用户使用
用户名
和口令
到认证服务器上请求认证
-
服务器端生成
JWT Token
认证服务器还会生成一个 Secret Key(密钥)
对JWT Header和 JWT Payload分别求Base64。在Payload可能包括了用户的抽象ID和的过期时间。
用密钥对JWT签名 HMAC-SHA256(SecertKey, Base64UrlEncode(JWT-Header)+’.’+Base64UrlEncode(JWT-Payload))
-
把
base64(header).base64(payload).signature
作为JWT token
返回客户端 -
客户端使用
JWT Token
向应用服务器发送相关的请求。
这个JWT Token就像一个临时用户权证
一样
服务器收到请求后
检查 JWT Token,确认签名
认证服务器
有这个用户的Secret Key(密钥),所以,应用服务器得把JWT Token传给认证服务器。
认证服务器通过JWT Payload 解出用户的抽象ID,然后通过抽象ID查到登录时生成的Secret Key,然后再来检查一下签名。
认证服务器检查通过后,应用服务就可以认为这是合法请求了
对称加密, 加密解密都是认证服务器(私钥)
非对称加密, 加密认证服务器(私钥) 解密应用服务器(公钥)
OAuth 1.0 委托授权协议
例子
(User 照片所有者-用户)
使用一个Consumer(第三方照片打印服务)
来打印他在Service Provider(照片存储服务)某网站上的照片
,
用户不想把自己的用户名和口令交给那个第三方的网络打印服务
,又想让那个第三方的网络打印服务来访问自己的照片
1 [Consumer] 获取 Request Token
2 [Service Provider] 认证用户, 并授权Consumer
3 [Consumer] 获取 Access Token, 调用API访问用户的照片
详细流程
User,Consumer 和 Service Provide,又叫 3-legged flow,三脚流程
-
Consumer(第三方照片打印服务)
需要先上Service Provider
获得开发的Consumer Key
和Consumer Secret
(申请有效的开发者信息)
-
当
User
访问Consumer
时,Consumer
向Service Provide
发起请求请求Request Token
(需要对HTTP请求签名)用户授权第三方平台开始
-
Service Provide
验明Consumer
是注册过的第三方服务商后,返回Request Token(oauth_token)
和Request Token Secret (oauth_token_secret)
Service Provider验证第三方开发者信息的有效性
-
Consumer
收到Request Token
后,使用HTTP GET 请求把 User切到 Service Provide 的认证页
上(其中带上Request Token),让用户输入他的用户和口令。跳转 Service Provider 的用户登录认证
-
Service Provider
认证User
成功后,跳回Consumer
,并返回Request Token (oauth_token)
和Verification Code(oauth_verifier)
回调, 获取 Verification Code
-
接下来就是
签名请求
,用Request Token
和Verification Code
换取Access Token (oauth_token)
和Access Token Secret (oauth_token_secret)
请求 access_token
-
最后使用
Access Token
访问用户授权访问资源
OAuth 2.0
Digest Access,AppID+HMAC,JWT,再到OAuth 1.0
,这些API认证
都是要向Client发一个密钥(或是用密码)然后用HASH或是RSA来签HTTP的请求, 安全签名机制
OAuth 2.0
完全不同于1.
0, 依赖于TLS/SSL的链路加密技术(HTTPS)
放弃了签名的方式
Authorization Code Flow
(3 legged flow)
最常使用的OAuth 2.0的授权许可类型
流程:
-
用户(Resource Owner)
访问第三方应用(Client)
的时候,第三方应用会把用户带到认证服务器(Authorization Server)
上去 , 请求的是/authorize API
https://login.authorization-server.com/authorize? client_id=6731de76-14a6-49ae-97bc-6eba6914391e &response_type=code &redirect_uri=http%3A%2F%2Fexample-client.com%2Fcallback%2F &scope=read &state=xcoiv98CoolShell3kch client_id 为第三方应用的App ID response_type=code 为告诉认证服务器,我要走Authorization Code Flow。 redirect_uri 意思是我跳转回第三方应用的URL scope 意是相关的权限 state 是一个随机的字符串,主要用于防CSRF攻击。
-
Authorization Server
收到这个URL请求后,检查client_id
,redirect_uri
和scope
是否合法
如果合法,则弹出一用户认证个页面,让用户授权(如果用户没有登录,则先让用户登录,登录完成后,出现授权访问页面)。
认证 + 授权
-
用户
授权同意访问以后,Authorization Server
会跳转回Client
,并以其中加入一个Authorization Code
添加 auth code, 回调 (redirect_uri) client第三方应用 https://example-client.com/callback? code=Yzk5ZDczMzRlNDEwYlrEqdFSBzjqfTG &state=xcoiv98CoolShell3kch
-
Client
就使用Authorization Code
获得Access Token
获取token POST /oauth/token HTTP/1.1 Host: authorization-server.com code=Yzk5ZDczMzRlNDEwYlrEqdFSBzjqfTG &grant_type=code &redirect_uri=https%3A%2F%2Fexample-client.com%2Fcallback%2F &client_id=6731de76-14a6-49ae-97bc-6eba6914391e &client_secret=JqQX2PNo9bpM0uEihUPzyrh
-
获得
token 信息
{ "access_token": "iJKV1QiLCJhbGciOiJSUzI1NiI", "refresh_token": "1KaPlrEqdFSBzjqfTGAMxZGU", "token_type": "bearer", "expires": 3600, "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciO.eyJhdWQiOiIyZDRkM..." } access_token 就是访问请求令牌了 refresh_token 用于刷新 access_token id_token 是JWT的token,其中一般会包含用户的OpenID
-
请求资源数据
Client Credential Flow
(2 legged flow)
简化版的API认证, 认证服务器
到服务器
的调用, 没有用户参与
流程
-
Client
用自己的client_id
和client_secret
向Authorization Server
要一个Access Token
POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=client_credentials &client_id=czZCaGRSa3F0Mzpn &client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
-
使用
Access Token
访问相关的资源{ "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", "token_type":"bearer", "expires_in":3600, "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk", "scope":"create" }
注意 tips
-
编码Base64Encode
、签名HMAC
、加密RSA
编码 为了更的传输,等同于明文,
签名 为了信息不能被篡改,
加密 为了不让别人看到是什么信息
-
应该遵循HTTP的规范,把
认证信息
放在Authorization HTTP
头中 -
不要使用
GET
的方式在URL中放入secret之类
的东西,因为很多proxy或gateway的软件会把整个URL记在Access Log
文件中 -
认证授权服务器
(Authorization Server)
和应用服务器(App Server)
最好分开 -
密钥Secret
相当于Password,用来加密的,最好不要在网络上传输
,如果要传输,最好使用TLS/SSL的安全链路