-
Notifications
You must be signed in to change notification settings - Fork 165
RSocket Security
Alibaba RSocket Broker的安全模型介绍。RSocket Broker采用零信任架构方案,如要求所有的接入应用都要经过验证,JWT token设计上增加授权信息等。
- 安全访问控制: 对所有连接到RSocket Broker的应用必须经过认证、授权和加密
- 无边界设计: RSocket Broker并不会对从特定网络来的连接进行特殊处理,与应用能获得的服务没有关系,完全是基于身份控制
- 上下文感知: 根据应用接入时的网络环境或设备的了解,来授予所获得的服务,这个目前并没有实现,但是可以通过RSocket Broker后台进行干预
目前RSocket Broker的安全策略主要源自TLS和JWT Token。其中TLS主要负责通讯的加密,而连接认证则是基于JWT Token,力求保证每一个新建的连接都是被验证的。
目前RSocket Broker支持的TLS规范为TLSv1.3和TLSv.1.2,从而确保通讯通道的安全。考虑到TLS代理的性能损失、内部部署的场景,默认TLS是不启用的。
关于JWT的详细介绍,大家可以参考官方站点 https://jwt.io/ ,DZone上的这篇文章也不错 JWT Token: Lightweight, Token-Based Authentication 目前JWT Token的验证策略是RSA256,默认秘钥长度为2048。使用RSA私钥负责生成JWT Token,使用RSA公钥负责验证JWT Token,这样可以避免中心化验证服务的性能瓶颈和复杂性,同时基于公钥验证不会有安全泄露风险。
在介绍详细的验证和授权机制前,让我们看一下JWT Payload的结构,也就是Payload中包含哪些信息?
JWT Payload的元素信息:
- "iss" (Issuer): Token的签发者,目前为"RSocketBroker"
- "id"(Certification ID): 证书ID,这个可选的。例如在IoT场景,我们可能希望每一个设备都使用不同的证书,这样方便我们跟踪这些设备,如果给设备推送信息。
- "sub" (Subject) : JWT的面向的对象,这里为应用名称,如Spring Boot场景就是"spring.application.name"对应的值。我们建议不同的应用申请不同的Token,不要混用。
- "aud" (Audience) :JWT的接收人,这里为申请JWT Token的申请人或者负责人,如果token有问题,方便我们联系对应的人员。多名人员以逗号分隔,内容如姓名、email、手机号等。
- "iat" (Issued At): Token的颁发时间(issued timestamp)
- "exp" (Expiration Time):Token的过期时间
- "orgs" (organizations): JWT Token所属的机构ID,可以为多个,逗号分隔。 机构ID主要使用在多租户场景,不同的机构ID之间的服务不能相互调用。如果两个机构之间需要相互调用,请包含共同的机构ID,如"alibaba,taobao", "alibaba,alipay",这样可以保证两个机构之间可以通讯。
- "sas" (Service Accounts): 应用的服务账户列表,这个和K8S的Service Account机制一样,同一个Service Account下的应用可以相互通讯,缺失名称为default。注意: 即便机构ID相同,service account还必须相同,这样才可以通讯。多个服务账号名称之间都好分隔。
- "roles" (Roles): 角色列表,如"external", "partner", "internal", "vip", "admin"等,这个和安全认证中的role是一样的
- "authorities" (ACL): 权限列表,表示该token拥有访问特定权限,例如"account.read", "account.write"等权限点,当然也可以为"com.example.UserService"等服务接口.
在JWT Token的信息中,认证是没有问题的,考虑得到实际的安全场景,原则上还要求添加授权信息,如角色列表和权限列表。
在某些场景下,我们想在RSocket鉴权的时候,验证对方的IP地址,如是否在IP白名单内,从而保证一定的安全性。 在RSocket Java 1.1.0版本, DuplexConnection提供了remoteAddress()方法,你只需要通过鉴权时的requester对象的connection字段就可以就可以拿到连接方的IP地址。 下述代码中的FieldUtils类来自Apache commons-lang3。 样例如下:
public Mono<RSocket> createResponder(ConnectionSetupPayload setupPayload, RSocket requester) {
//CompositeMetadata compositeMetadata = new CompositeMetadata(setupPayload.metadata(), false);
//security authentication
try {
DuplexConnection connection = (DuplexConnection) FieldUtils.readField(requester, "connection", true);
InetSocketAddress remoteAddress = (InetSocketAddress) connection.remoteAddress();
} catch (Exception ignore) {
}
SimpleResponderImpl handler = new SimpleResponderImpl(setupPayload, requester);
return Mono.just(handler);
}
当然你也可以通过RSocket的plugin机制,来验证连接方的远程IP地址,如下:
RSocketServer.create()
.acceptor(responderFactory.responder())
.interceptors(registry -> {
registry.forConnection((type, duplexConnection) -> {
//check remote address
return duplexConnection;
});
})
处于安全考虑,应用接入的IP地址会被RSocket Broker所记录。
在内部的系统中,会员的一些信息,如手机号码、邮件等,这些属于敏感服务,不是所有的应用都可以访问这些服务。 你可以将该服务对应的token中的service account设置为UserPrivacy,其他应用如果想访问这些服务,在申请token的时候,JWT Token中的sas值可能就为"default,UserPrivacy",表示该应用可以访问会员的敏感服务。 而普通应用,由于服务账号中并没有包含"UserPrivacy",所以不能访问会员的敏感服务,做到非常好的安全保障。
JWT中包含orgs字段,标明应用所说的机构信息,根据该信息,可以做到机构内服务和外部隔离。 如果你需要将某一应用开放给其他机构访问,需要机构ID和Service Account两者配合。
- 包含共有的机构ID,如Token中的orgs都包含"alibaba"这个机构ID
- 包含共有的Service Account: 我们还需要设置一下共有的service account,不然对方的应用可能就访问你内部的所有服务,这个不是我们希望的。所有对应的Service Account可能就是"alipay_taobao",注意不要随意添加名称,不然可能会导致越权访问。
如果你的服务是开放给所有的应用调用的,但是你希望一些服务是提供给运维或者CRM的,这个时候,你可以给对应的Token添加roles或者authorities,这样只有授权的应用才可以调用这些服务。
- Zero Trust Architecture: NIST Special Publication 800-207 https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-207.pdf
- Binary: byte stream
- Async message
- Multi transports
- Reactive Semantics
- request/response
- request/stream
- fire-and-forget
- channel
- TCP+TLS
- WebSocket+TLS
- UDP(Aeron)
- RDMA