基于签名实现的接口鉴权

本文探讨了在IT开发中如何通过使用Token和签名来保护用户权限和会话安全,强调了Token并非绝对安全,还需配合签名值进行请求合法性校验。文章详细介绍了签名计算的设计,包括签名字符串、签名key的选择以及接口合法性校验流程。

一、Token与签名

一般客户端和服务端的设计过程中,大部分分为有状态和无状态接口。一般用户登录状态下,判断用户是否有权限或者能否请求接口,都是根据用户登录成功后,服务端授予的token进行控制的。但并不是说有了token,请求就是安全的,那么万一token泄露了怎么办呢?谁都可以调用我的服务了吗?

就比如去银行取钱,需要用到银行卡。但不能因为你不小心把银行卡弄丢了,捡到的人就可以拿着你的银行卡去银行办理业务了。他们还需要对你的身份进行验证,你也要知道银行卡密码。

所以token只是用户权限以及会话的凭证,除了会话的凭证,我们也要校验请求的合法性,以防止token泄露而导致客户的损失。

而签名摘要计算则是用来进行请求合法性校验。经常同学们会把这两种搞混。以为使用token就是安全的。

二、签名计算设计

签名摘要的计算一般分为签名值和签名的key,signature生成方式如下:

signature = Base64(HMAC-SHA256(LOWER(MD5(key)), StringToSign))
2.1 签名字符串的设计

设计签名字符串时,我们要想好,我们要针对不同的攻击策略,设计什么样的请求头部

常用的签名字符串设计如下:

StringToSign =  Content-MD5 + "\n"
               + CanonicalizedHeaders

CanonicalizedHeaders构建方法如下:

1.以service为前缀的的Headers,但是不包括service-signature,如下

  • service-nonce:客户端生成32位随机字符串,所有客户端5分钟内不能重复,重复时平台回复nonce重复,客户端需要重新请求。

  • service-date:请求生成的时间,与服务器本地时间差超过5分钟,认为鉴权失败。

  • service-session-id:客户端会话id,用于本次登录后的所有请求会话标识。

  • service-client:客户端信息,包括客户端类型、客户端版本、操作系统等。

2.Header名称全部小写,值前后应不包含空格

3.Header的名称和值之间用“:”相隔,组成一个完整的header

4.根据header名称的字符顺序,将header从小到大进行字典排序,每个header之后跟一个“\n”

StringToSign生成示例

eB5eJF1ptWaXm4bijSPyxw==\n
service-client:ewogICAgImRhdGEiOiB7CiAgICAgICAgImNsaWVudFR5cGUiOiAieHh4IiwKICAgICAgICAiY2xpZW50VmVyc2lvbiI6ICIzLjAiCiAgICB9Cn0=\n
service-date:2022-07-22T14:43:07Z\n
service-nonce:d36e316282959a9ed4c89851497a717f\n
service-session-id:0123456\n
2.3. 签名key设计

一般客户端请求的接口类型有三种,分别是有登录状态和无登录状态以及登录这个特殊接口。无登录状态前的接口都是服务为了提供能力而做的一些接口,相比而言都是提供通用能力的。不涉及客户个人信息相关。安全风险较小。

用户登录后的接口一般都是涉及到客户信息的接口,隐私泄露风险较大。因此对于每一种状态可采用不同的key值设计。讲风险降到最低。

2.3.1. 用户未登录签名key值

用户未登录时,平台提供通用能力,调用服务端接口时使用约定好的固定SK进行接口签名鉴权即可。固定SK由后台提供16位的随机字符串。

2.3.2. 用户登录签名key值

我们知道,所有在客户端和前端保存的key值永远不是最安全的,有可能被拆包而发现对应的加密SK,从而被不法分子破解,因此用户登录时,传输密码时,如果使用固定key,有可能body体被解开,密码被泄露的风险。

登录时用户会输入密码,而服务端也知道用户加密后的密码,那么使用用户输入的密码当做key则是最安全的方式。并且交互过程中不需要将用户密码放在body体重传到后端进行校验,只需校验签名的准确性即可。这样就可以极大的增加用户密码的安全性。

用户登录验证时会输入用户的密码,则登录时用户密码作为签名的key进行鉴权校验。加密key为:SHA256(LOWER(MD5(passwd)),salt),salt为用户的盐值,可以使用用户的手机号。

2.3.3. 用户登录签名key值

用户登录成功之后,所有接口都要有鉴权,为了每个用户安全起见,针对每个用户颁发自己的SK,登录成功后获取。这样客户端将sercet保存到内存中,可以有效防止SK泄露。

  • 用户注册成功后,针对用户账户后台生成16位的sercet

  • 用户登录成功后,后台返回用户的sercet

  • 登录之后的接口鉴权使用sercet进行鉴权。

三、接口合法性校验流程

请求合法性校验流程如下:

1、首先对接口的请求头的nonce进行5分钟内是否重复的校验,可以有效的防止重放攻击。

2、然后对时间戳进行校验,防止客户端时间篡改攻击。

3、之后对请求的MD5进行校验,防止对请求体进行篡改。

4、最后将nonce,date,md5以及session进行组合签名校验,校验签名值是否成功。可以有效防止上面单一修改验证通过,但签名值校验不通过的问题。

基于以上的校验,基本上可以防止大部分攻击场景。当然为了更加安全,你还可以增加黑白名单限制、接口访问限流、用户常用设备绑定、用户异地登录等保护用户财产的安全性设计。

<think>好的,我现在需要帮助用户找到基于API接口的网关层方案。用户已经提供了一些引用内容,我需要仔细分析这些信息,并结合自己的知识来给出合适的回答。 首先,用户提到的三个引用分别涉及不同的方法。引用[1]讨论了在网关层统一的几种方式,比如使用HashMap、配置文件、配置中心或数据库存储需要的URL。引用[2]展示了网关如何通过限码进行接口级别的,涉及登录流程和限验证。引用[3]提到了使用JWT和JJWT工具进行token签发和验证。 用户的需求是寻找网关层API接口实现方案。需要结合这些引用中的方法,给出几种可行的方案,并比较它们的优缺点。同时,用户可能希望了解具体的实现步骤或技术选型,比如如何使用JWT、如何配置路由规则等。 接下来,我需要整理出几种常见的方案: 1. **路径匹配**:根据URL路径进行匹配,可以在网关配置文件中预定义需要的路径,或者动态从数据库/缓存加载。这种方法简单但不够灵活,难以处理复杂限。 2. **限码**:每个接口关联限码,用户token中携带限信息,网关验证限码是否匹配。这需要限码与接口的映射管理,可能涉及RBAC模型。 3. **JWT令牌**:使用JWT传递用户身份和限,网关解析并验证JWT的有效性及签名。JWT可以包含用户角色或限,网关根据这些信息控制访问。 4. **动态规则**:结合配置中心(如Nacos、Apollo)动态更新规则,网关实时获取最新规则,提高灵活性。 5. **混合模式**:结合上述几种方法,例如使用JWT传递基础信息,同时通过限码进行细粒度控制,或者动态加载路径。 需要分析每种方案的适用场景、优缺点,以及实现时的注意事项。例如,路径匹配适用于简单场景,但维护成本高;JWT适合无状态验证,但需处理令牌撤销问题;动态规则适合频繁变更的环境。 此外,引用中提到的技术如JJWT工具、配置中心、过滤器机制,都需要在方案中提及,说明如何具体应用这些技术来实现。 最后,要确保回答结构清晰,分点说明,并生成相关问题,帮助用户进一步探索。同时,检查是否符合用户要求的格式,如使用正确的LaTeX、引用标注等。</think>### 网关层 API 接口方案实现方式 #### 一、核心模式 1. **路径匹配** - **实现方式**:在网关配置文件中定义需接口路径,例如使用YAML配置: ```yaml secure-urls: - /api-order/** - /api-user/profile ``` 网关过滤器通过正则匹配请求路径,拦截未授的访问[^1]。 - **优点**:简单易实现,适用于固定接口规则。 - **缺点**:灵活性低,需重启服务更新配置。 2. **限码动态** - **实现流程**: 1. 用户登录后,授服务生成包含限码的Token(如JWT格式)[^3]。 2. 网关解析Token中的限码,与接口要求的限码对比(例如`order-info`限码对应`/order/info`接口)[^2]。 3. 未匹配则返回`403 Forbidden`。 - **技术要点**: - 使用JJWT库生成/验证Token: ```java Jwts.builder().claim("perms", ["order-info"]).signWith(secretKey).compact(); ``` - 限码与接口映射关系可存储在数据库或缓存中。 3. **JWT令牌** - **核心步骤**: 1. 网关验证JWT签名有效性(防止伪造)。 2. 检查Token过期时间及限声明(Claims)。 3. 结合RBAC模型,验证用户角色是否拥有接口访问[^3]。 - **增强方案**: - 使用非对称加密(如RSA)提高安全性。 - 添加黑名单机制应对Token泄露问题。 #### 二、动态规则管理方案 1. **配置中心集成** - 将规则存储在Nacos/Apollo等配置中心,网关监听配置变更,实现实时更新[^1]。 - 规则格式示例: ```json { "/api-payment/**": ["payment-read", "payment-write"], "/api-report/download": ["report-admin"] } ``` 2. **注解自动采集** - 在微服务接口代码中添加自定义注解(如`@RequirePermission("order:read")`)。 - 服务启动时扫描注解,将接口路径与限码的映射关系持久化到数据库[^1]。 - 网关通过定时任务或消息队列同步最新规则。 #### 三、技术选型对比 | 方案 | 适用场景 | 维护成本 | 性能影响 | |---------------------|----------------------------|----------|----------------| | 路径匹配 | 接口规则稳定的内部系统 | 低 | 低(正则匹配) | | 限码动态 | 需细粒度控制的业务系统 | 中 | 中(DB查询) | | JWT+RBAC | 分布式无状态架构 | 高 | 低(本地验证) | | 配置中心动态规则 | 高频变更限策略的企业环境 | 高 | 低(内存缓存) | #### 四、实现示例(Spring Cloud Gateway) ```java public class AuthFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path = exchange.getRequest().getPath().value(); String token = extractToken(exchange.getRequest()); // 1. 验证Token有效性 if (!JwtUtils.validateToken(token)) { return setResponse(exchange, 401, "Invalid token"); } // 2. 获取限码并匹配接口 List<String> perms = JwtUtils.getPermissions(token); String requiredPerm = loadRequiredPermFromCache(path); // 从Redis读取接口所需限 if (!perms.contains(requiredPerm)) { return setResponse(exchange, 403, "Access denied"); } return chain.filter(exchange); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值