Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dubbo调用鉴权认证方案 #5461

Closed
CodingSinger opened this issue Dec 11, 2019 · 8 comments
Closed

Dubbo调用鉴权认证方案 #5461

CodingSinger opened this issue Dec 11, 2019 · 8 comments
Milestone

Comments

@CodingSinger
Copy link
Member

CodingSinger commented Dec 11, 2019

基本需求:

  • 一些敏感服务的provider,只允许经过授权的consumer应用发起的调用,不允许匿名调用。

方案设计:

  1. 基于AK/SK,即Access Key ID和Secret Access Key。
  2. AK/SK需要应用启动时向鉴权服务拉取,定期更新。为保证安全,用HTTPS通信。
  3. 签名和验签基于filter。

dubbo-auth.png

细节说明

  1. 签名过程,调用方可选择签名策略,选择根据调用元信息签名(方法信息、接口信息)和混合参数签名方法。

  2. 验签过程:provider收到调用请求时,根据AK查询缓存的SK(如果没有对应的AK,则立刻同步一次鉴权服务),并用同样方法计算signature,检查signature是否相同, 通过则执行调用,否则抛出异常。

鉴权服务接口设计

鉴权服务是Dubbo的外部服务,进行统一管理AK/SK,并为Dubbo应用提供AK/SK下发。

接口地址https://ip:80/secrets/{appName}

请求方式: GET

返回数据格式: JSON

返回数据定义:

 {
        "cumsomer":[  // 申请到访问其他服务的AK/SK对
            {
                "accessKey":"", // AK
                "secretKey":"", // SK
                "consumerSide":"", // 消费端appname
                "providerSide":"", // 服务端appname
                "timestamp":"",   // 有效期
                "options":""     // 其他信息
            }
        ],
        "provider":[   // 自己提供出去承认其他应用访问的AK/SK对
            {
                "accessKey":"", // AK
                "secretKey":"", // SK
                "consumerSide":"", // 消费端appname
                "providerSide":"", // 服务端appname
                "timestamp":"",   // 有效期
                "options":""     // 其他信息
            } 
        ]
        
    }
@chickenlj chickenlj pinned this issue Dec 11, 2019
@chickenlj chickenlj unpinned this issue Dec 11, 2019
@chickenlj chickenlj pinned this issue Dec 11, 2019
@w6et
Copy link

w6et commented Dec 14, 2019

提一个简单的方案,全局或者每个provider,可以指定allow_apps\deny_apps(block_apps)
1)如果配了allow_apps,那就按白名单玩,必须白名单里才能调用
2)如果配了deny_apps,那就按黑名单玩,非黑名单的都能调用
这样:
1)不用考虑证书失效or过期or置换情况;
2)基本够用:限制到app层面,一般够用了(因为是内部调用,假设上线也是经过check的,流程上是可以保障的)

备注一下:是控制app背后的ip访问限制

@CodingSinger
Copy link
Member Author

@amwei 嗯 你这个确实比较简单,实现也容易很多,基本靠一个provider端的filter会实现了,但是后续对于黑白名单的增加还得重启。上面说的方案引入了一个额外的系统,确实复杂度会提高,但是在安全性和扩展性方面都会有很大的改善,目前我们也在权衡。

@laddcn
Copy link
Contributor

laddcn commented Dec 20, 2019

鉴权服务和各个微服务之间是可信内网通信吗?如果外网负责环境的话是不是还要考虑下HTTPS和TLS的中间人攻击问题,AK/SK下发和更新过程中可能会被中间人截获。

@laddcn
Copy link
Contributor

laddcn commented Dec 20, 2019

当然这样考虑问题就会复杂了

@chickenlj chickenlj added this to the 2.7.6 milestone Dec 30, 2019
@nisiyong
Copy link
Contributor

nisiyong commented Jan 6, 2020

@CodingSinger

我们最近也在做服务身份认证的方案,你这种实现是中心化的实现。鉴权服务需要高可用,如果鉴权服务宕了,你们是如何考虑的?

对于服务黑白名单,我们考虑直接用sentinel来做即可,这是服务鉴权。在这之前做好身份认证即可,保证调用方不是伪造的。

@nisiyong
Copy link
Contributor

nisiyong commented Jan 6, 2020

这里也贴下我们的方案吧,一起探讨下。

基本流程

image

如上图,流程如下:

  1. 为每个应用生成一对公私钥,私钥给应用独立配置,所有公钥集中统一管理(我们采用配置中心公共配置),所有应用都能获取到所有公钥
  2. 服务A使用自己的私钥,根据应用名和时间等,用私钥对app和timestamp进行签名生成token(可采用JWT规范)
  3. 在每次调用时将token通过上下文透传给服务B
  4. 服务B接受到请求后,判断token是否合法(通过该应用的公钥验证token),否则拒绝请求
  5. 认证信息校验合法后,进行业务处理并响应

性能优化

由于token的生成和校验用了非对称加密算法,在性能上有一定的影响,为了解决该问题,我们引入“预生成”和“预校验”,结合内存缓存一起使用。

image

“预生成”逻辑:(假设每小时产生一个新的token)

  1. 在0h时,token-1可以在启动起同步生成初始化,作为上下文的token字段的值;并异步生成token-2,作为上下文next_token字段的值
  2. 在1h时,token-2上下文的token字段的值;并异步生成token-3,作为上下文next_token字段的值
  3. 在2h时,token-3上下文的token字段的值;并异步生成token-4,作为上下文next_token字段的值
    ...

“预校验”逻辑:(假设token的缓存失效时间为客户端弃用半小时后)

  1. 在0h时,接收到token-1并同步校验,校验成功加入内存缓存;并异步校验token-2,校验成功加入内存缓存
  2. 在1h时,接收到token-2可直接用内存缓存比较,无需计算;并异步校验token-3,校验成功加入内存缓存
  3. 在2h时,接收到token-3可直接用内存缓存比较,无需计算;并异步校验token-4,校验成功加入内存缓存
    ...

通过以上两种方式结合:

  • 可以避免非对称加密算法在业务线程中执行
  • 可以解决token平滑切换,解决毛刺问题

总结

该方案是基于去中心化设计的,而且只解决身份认证问题,证明调用方A就是真的A,而不是伪造的A。至于A能否调用B,或能调用哪个接口,我们考虑直接用Sentinel的黑白名单来做补充。

@liushuaifei
Copy link

liushuaifei commented Oct 11, 2021

定期更新可以改为握手时获取加监听变化,利用rpc服务发现的长链接信道。

@phenix229
Copy link

您好,鉴权认证的方案在dubbo-2.7.6中,是否可以使用?

@phenix229 phenix229 mentioned this issue May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants