在业务开发中,当某些接口不能对外暴露时,需要采取一系列措施来保护这些接口的安全性和隐私性。
以下是对该问题的详解及案例分析:
一、接口不能对外暴露的原因
1、安全性考虑
某些接口可能包含敏感信息或者涉及到系统的核心功能,因此需要限制对其访问,以确保系统的安全性。
2、商业考虑
有些接口可能包含了公司的商业机密或者核心竞争力,因此需要限制对其访问,以防止被竞争对手获取关键信息。
3、合规要求
根据某些行业标准或者法律法规的要求,某些接口可能需要进行严格的权限管理和监控,以确保符合相关的合规要求。
二、解决方案
2.1 内外网接口微服务隔离
【方案描述】:
将对外暴露的接口和对内暴露的接口分别放到两个微服务上,一个服务里所有的接口均对外暴露,另一个服务的接口只能内网服务间调用。
【案例分析】:
假设有一个电商平台,其用户注册和登录接口需要对外暴露,而订单处理接口只能由内部服务调用。此时,可以将用户注册和登录接口放在一个微服务中,而将订单处理接口放在另一个微服务中。通过微服务隔离,可以确保订单处理接口不会被外部用户直接访问。
【优点】:
实现上比较简单,不用额外做复杂的权限校验;易于管理,只需要控制服务的暴露范围。
【缺点】:
新增内网微服务会让整体架构复杂度上升,维护成本变高。此外,服务数量增多可能会导致调用链变长,影响性能。
示例:
使用 Spring Cloud Gateway 限制外部访问 spring:
cloud:gateway:routes:- id: internal_serviceuri: http://internal-service:8080predicates:- Path=/internal/** # 只允许访问 `/internal/**` 路径filters:- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 10redis-rate-limiter.burstCapacity: 20metadata:security: internal # 用于标识此接口仅限内网访问
原理:
API 网关 可以通过 IP 白名单或基于请求头等方式来对接口进行访问控制。通过配置可以确保只有从内网服务发出的请求能访问这些接口。
2.2 网关+Redis实现白名单机制
【方案描述】:
在Redis中维护一套接口白名单列表,外部请求到达网关时,从Redis获取接口白名单,在白名单内的接口放行,反之拒绝掉。
【案例分析】:
假设有一个企业内部管理系统,其中部分接口需要对外开放,而大部分接口只能由内部员工访问。此时,可以在Redis中维护一个接口白名单,将需要对外开放的接口添加到白名单中。网关拦截所有外部请求,并根据白名单判断请求是否合法。
【优点】:
对业务代码零侵入性,不需要在业务代码上修改;可以灵活调整白名单,动态增加或减少接口。
【缺点】:
白名单维护成本较高,尤其是当接口数量庞大、频繁变动时;每次请求都要查Redis,增加了系统响应耗时,对性能有一定影响。
示例:
基于 IP 白名单限制接口访问
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableWebSecurity
publicclass SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotectedvoidconfigure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/internal/**").hasIpAddress("192.168.0.0/16") // 允许内网 IP 访问.anyRequest().authenticated() // 其他请求需要身份验证.and().httpBasic(); // 启用基础 HTTP 验证(可根据需求修改)}
}
原理:
使用 Spring Security 配合 IP 地址检查,可以对指定路径(如 /internal/**)限制为特定 IP 地址范围(如内网 IP)。只有匹配的 IP 地址能够访问这些接口。
2.3 网关+AOP在业务侧判断访问权限
【方案描述】:
通过网关对所有经过的请求的header里添加一个字段来区分请求来源,业务侧接口收到请求后判断header里的字段,根据该接口是否属于内部接口来决定是否放行该请求。
【案例分析】:
假设有一个金融系统,其中部分接口需要对外开放以提供API服务,而大部分接口涉及敏感数据只能由内部服务调用。此时,可以在网关侧对所有经过的请求添加一个标识字段(如from=public),业务侧接口通过AOP切面检查该字段,如果请求来自外部且访问的是内部接口,则拒绝访问。
【优点】:
将内外网访问权限的处理分布到各个业务侧进行,消除了由网关来处理的系统性瓶颈;开发者可以在业务侧直接确定接口的内外网访问权限,提升开发效率的同时增加了代码的可读性。
【缺点】:
对业务代码有一定的侵入性,不过可以通过注解等形式最大限度地降低这种侵入性。
示例:自定义注解 + AOP 访问控制:
1、定义注解:首先定义一个注解,表示某些接口是内网接口。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InternalOnly {
}
2、实现 AOP 切面
然后创建一个 AOP 切面,检查请求的源 IP,只有内网请求可以访问被 @InternalOnly 注解标记的方法。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;@Aspect
@Component
publicclass AccessControlAspect {privatefinal HttpServletRequest request;publicAccessControlAspect(HttpServletRequest request) {this.request = request;}@Pointcut("@annotation(com.example.InternalOnly)")publicvoidinternalOnlyMethods() {}@Before("internalOnlyMethods()")publicvoidcheckIp() {String clientIp = request.getRemoteAddr();if (!clientIp.startsWith("192.168")) { // 只允许内网 IPthrownew AccessDeniedException("Access denied for external requests.");}}
}
3、应用注解:
@RestController
public class InternalController {@InternalOnly@GetMapping("/internal/data")public String getInternalData() {return "Internal Data";}
}
原理:
通过自定义注解标记内网接口,然后通过 AOP 在方法调用前检查请求的源 IP 是否符合内网访问的要求。若不符合,则抛出 AccessDeniedException。
三、综合建议
在实际应用中,可以根据业务需求和系统架构选择合适的解决方案。同时,还可以结合多种方案来增强系统的安全性和稳定性。例如,可以同时使用内外网接口微服务隔离和网关+AOP判断访问权限的方案,以确保敏感接口的安全性和隐私性。
此外,还可以采取其他安全措施来增强系统的防护能力,如使用HTTPS协议确保数据在传输过程中的安全性、对敏感数据进行加密存储、记录所有接口的访问日志并定期分析日志以发现潜在的安全问题等。
综上所述,当业务开发中接口不能对外暴露时,需要综合考虑安全性、商业保密和合规需求等因素,选择合适的解决方案来确保系统的安全性和稳定性。
原创 womubuji