dubbo 安全方案
2019-11-05 本文已影响0人
乘以零
如果dubbo服务必须开放在外网上 如何控制权限验证呢?想了下有一下集中方案
1.开启linux 防火墙 ,只让白名单中的ip访问固定的端口(或禁止黑名单访问)
白名单
iptables -A INPUT -s 192.168.0.0/8 -p tcp --dport 22 -j ACCEPT
黑名单
iptables -A INPUT -s 192.168.0.0/8 -p tcp --dport 22 -j DROP
# or
iptables -A INPUT -s 192.168.0.0/8 -p tcp --dport 22 -j REJECT
2.dubbo 的 token 机制
http://dubbo.apache.org/zh-cn/docs/user/demos/token-authorization.html
<dubbo:provider interface="com.foo.BarService" token="true" />
这种方法,防止直连dubbo,只能通过注册中心的方式,然后把注册中心的ip或端口号禁用掉。
但如果禁用掉了注册中心,服务又不能通过直连的方式调用,那这个服务在外网和内网有区别么???
如果不禁用注册中心的端口,采用注册中心用户名密码制
<dubbo:registry username="" password="" />
但是,我们大部分使用的注册中心为zookeeper,zookeeper用的ACL机制,子节点不能继承父节点的权限,所以,当注册中心使用zk时候,这个方法不可行。可以换成别的注册中心。
3.采用nginx代理
原dubbo的端口20880,代理后的端口为20881,然后把20880防火墙禁止外网访问,nginx加上权限校验。
shell 创建用户名 密码
> cd /etc/nginx/
> htpasswd -c -d /etc/nginx/passwd.db username
> password
nginx.conf
stream{
upstream dubbo{
server 127.0.0.1:20880;
}
server{
auth_basic "User Authentication";
auth_basic_user_file /etc/nginx/passwd.db;
listen 20881;
proxy_pass dubbo;
}
}
4.采用dubbo filter机制,这样每个工程都要加上相应的filter
provider 加
@Activate(group = Constants.PROVIDER)
public class AuthProviderFilter implements Filter {
//这个用户名 密码可以写在配置文件中
private String username = "abcde";
private String password = "12345";
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext.getContext().setAttachment("auth.username", username);
RpcContext.getContext().setAttachment("auth.password", username);
Result result = invoker.invoke(invocation);
return result;
}
}
consumer 加
@Activate(group = Constants.CONSUMER)
public class AuthConsumerFilter implements Filter {
//这个用户名 密码可以写在配置文件中
private String username = "abcde";
private String password = "12345";
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String u = RpcContext.getContext().getAttachment("username");
String p = RpcContext.getContext().getAttachment("password");
//认证成功
if (username.equals(u) && password.equals(p)) {
Result result = invoker.invoke(invocation);
return result;
}
// 认证失败 报错
throw new RpcException("auth error");
}
}
也可以合在一起
@Activate(group = { Constants.CONSUMER, Constants.PROVIDER })
public class AuthFilter implements Filter {
//这个用户名 密码可以写在配置文件中
private String username = "abcde";
private String password = "12345";
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//如果是消费端
if (RpcContext.getContext().isConsumerSide()) {
String u = RpcContext.getContext().getAttachment("username");
String p = RpcContext.getContext().getAttachment("password");
//认证成功
if (username.equals(u) && password.equals(p)) {
Result result = invoker.invoke(invocation);
return result;
}
} else {
RpcContext.getContext().setAttachment("auth.username", username);
RpcContext.getContext().setAttachment("auth.password", username);
Result result = invoker.invoke(invocation);
return result;
}
throw new RpcException("auth error");
}
}