开放API接口签名验证(web和app)

 

接口安全问题

  • 请求身份是否合法
  • 请求参数是否被篡改
  • 请求是否唯一
  • 对于敏感的api接口,需使用https协议

AccessKey&SecretKey (开放平台)

请求身份:

为开发者分配AccessKey(开发者标识,确保唯一)和SecretKey(用于接口加密,确保不易被穷举,生成算法不易被猜测)。

防止篡改:

参数签名

  1. 按照请求参数名的字母升序排列非空请求参数(包含AccessKey)(ASCII码排序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA;
  2. 在stringA最后拼接上Secretkey得到字符串stringSignTemp;
  3. 对stringSignTemp进行MD5运算,并将得到的字符串所有字符转换为大写,得到sign值。

请求携带参数AccessKeySign,只有拥有合法的身份AccessKey和正确的签名Sign才能放行。这样就解决了身份验证和参数篡改问题,即使请求参数被劫持,由于获取不到SecretKey(仅作本地加密使用,不参与网络传输),无法伪造合法的请求。

重放攻击

虽然解决了请求参数被篡改的隐患,但是还存在着重复使用请求参数伪造二次请求的隐患。

timestamp+nonce方案

nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用)。

然而,对服务器来说永久存储所有接收到的nonce的代价是非常大的。可以使用timestamp来优化nonce的存储

假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)。

实现:

请求接口:http://api.test.com/test?name=hello&home=world&work=java

  • 客户端

    1. 生成当前时间戳timestamp=now和唯一随机字符串nonce=random
    2. 按照请求参数名的字母升序排列非空请求参数(包含AccessKey) 
      stringA="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random";
    3. 拼接密钥SecretKey 
      stringSignTemp="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random&SecretKey=secret";
    4. MD5并转换为大写 
      sign=MD5(stringSignTemp).toUpperCase();
    5. 最终请求 
      http://api.test.com/test?name=hello&home=world&work=java&timestamp=now&nonce=nonce&sign=sign;
  • 服务端 
    服务端流程


  1. api请求客户端想服务器端一次发送用用户认证信息(用户名和密码),服务器端请求到改请求后,验证用户信息是否正确。

        如果正确:则返回一个唯一不重复的字符串(一般为UUID),然后在Redis(任意缓存服务器)中维护Token----Uid的用户信息关系,以便其他api对token的校验。

        如果错误:则返回错误码。

 

服务器设计一个url请求拦截规则:

(1)判断是否包含timestamp,token,sign参数,如果不含有返回错误码。

(2)判断服务器接到请求的时间和参数中的时间戳是否相差很长一段时间(时间自定义如半个小时),如果超过则说明该 url已经过期(如果url被盗,他改变了时间戳,但是会导致sign签名不相等)。

(3)判断token是否有效,根据请求过来的token,查询redis缓存中的uid,如果获取不到这说明该token已过期。

(4)根据用户请求的url参数,服务器端按照同样的规则生成sign签名,对比签名看是否相等,相等则放行。(自然url签名也无法100%保证其安全,也可以通过公钥AES对数据和url加密,但这样如果无法确保公钥丢失,所以签名只是很大程度上保证安全)。

(5)此url拦截只需对获取身份认证的url放行(如登陆url),剩余所有的url都需拦截。

 3.Token和Uid关系维护

    对于用户登录我们需要创建token--uid的关系,用户退出时需要需删除token--uid的关系。

获取全部请求参数:

               String sign = request.getParameter("sign");
		Enumeration<?> pNames =  request.getParameterNames();
		Map<String, Object> params = new HashMap<String, Object>();
		while (pNames.hasMoreElements()) {
			String pName = (String) pNames.nextElement();
			if("sign".equals(pName))continue;
			Object pValue = request.getParameter(pName);
			params.put(pName, pValue);
		}

生成签名:

        public static String createSign(Map<String, String> params, boolean encode)
			throws UnsupportedEncodingException {
		Set<String> keysSet = params.keySet();
		Object[] keys = keysSet.toArray();
		Arrays.sort(keys);
		StringBuffer temp = new StringBuffer();
		boolean first = true;
		for (Object key : keys) {
			if (first) {
				first = false;
			} else {
				temp.append("&");
			}
			temp.append(key).append("=");
			Object value = params.get(key);
			String valueString = "";
			if (null != value) {
				valueString = String.valueOf(value);
			}
			if (encode) {
				temp.append(URLEncoder.encode(valueString, "UTF-8"));
			} else {
				temp.append(valueString);
			}
		}
 
		return MD5Utils.getMD5(temp.toString()).toUpperCase();
	}

 


Token&AppKey(APP)

在APP开放API接口的设计中,由于大多数接口涉及到用户的个人信息以及产品的敏感数据,所以要对这些接口进行身份验证,为了安全起见让用户暴露的明文密码次数越少越好,然而客户端与服务器的交互在请求之间是无状态的,也就是说,当涉及到用户状态时,每次请求都要带上身份验证信息。

Token身份验证

  1. 用户登录向服务器提供认证信息(如账号和密码),服务器验证成功后返回Token给客户端;
  2. 客户端将Token保存在本地,后续发起请求时,携带此Token
  3. 服务器检查Token的有效性,有效则放行,无效(Token错误或过期)则拒绝。

安全隐患:Token被劫持,伪造请求和篡改参数。

Token+AppKey签名验证

与上面开发平台的验证方式类似,为客户端分配AppKey(密钥,用于接口加密,不参与传输),将AppKey和所有请求参数组合成源串,根据签名算法生成签名值,发送请求时将签名值一起发送给服务器验证。这样,即使Token被劫持,对方不知道AppKey和签名算法,就无法伪造请求和篡改参数。再结合上述的重发攻击解决方案,即使请求参数被劫持也无法伪造二次重复请求。

实现

登陆和退出请求

登陆和退出流程

后续请求

  • 客户端 
    和上述开放平台的客户端行为类似,把AccessKey改为token即可。

  • 服务端 
    服务端流程


源码

请移步聚合支付平台,博主正在开发的一款开源项目,其中接口验证采用的就是上文中开放平台的验证方案,欢迎大家Star!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
框架简介: 本框架适由PHP+MYSQL语言开发,纯API接口,可快速对接外部appweb、各类软件开发; 本框架采用成熟稳定的Discuz3.4论坛系统,MVC框架环境下开发; 本框架无缝整合Discuz用户系统内置功能,采用插件形式开发的独立框架、分离代码、支持二次开发扩展; 通过本框架,可无限扩展数据输出接口,通过外部访问api接口,对数据进行操作、输出等功能; 本系统所有功能实现及控制均采用api外部接口,数据输出形式以JSON为主,可接收外部GET、POST参数; 客户端支持Python、Java、C、易语言、PHP、易安卓、火山移动、部分游戏开发引擎、等所有主流开发语言。 适用环境: 建议:PHP版本>5.4以上; 建议:DISCUZ版本>3.0以上; 建议:MYSQL版本>5.0以上; 其他环境,请大家自行测试 框架流程: 客户端:通过框架协议将数据提交到入口文件; 服务端-控制器:接到数据后,通过控制流程进行分流; 服务端-模型:接到分流指令,进行模块化数据处理; 服务端-视图:接到处理后数据,通过JSON返回客户端接收。 框架处理流程:传入数据-->入口文件-->控制器-->模型处理-->数据返回! 框架特色: 独立框架:独立开发的api专用框架协议,采用DB、原生代码三种方式独立封装核心库,不附带任何多余指令,代码简洁、速度快; 代码分离:本框架下所有代码与discuz框架分离,与discuz版本和其他插件不冲突,原生代码不对数据库有任何非官方流程操作,保证数据和结构逻辑不被破坏; 独特加密:本框架下采用动态双向、可自定义加密技术,有效保证token值保持动态变化验证技术,此加密技术可以添加特征码、干扰码。另外根据自身情况,可定制个人加密方式来强化,更是天衣无缝,世界唯一的个人专用加密技术; 动态验证:在独特加密的基础上应运而生动态时效,设定密文有效时间,时间一到必须重新更新验证数据,每一次更新密文都不一样,确保数据安全; 参数防护:数据传输都经过discuz安全机制进行过滤,但是discuz对参数负值、字符串转义过滤不严谨,容易造成错误,本框架强化数值、字符串的格式化,有效封堵恶意注入攻击! 核心处理:本框架核心逻辑、验证功能均在框架内处理,有效杜绝因外部软件安全等级低,被破解导致的逻辑错误,造成的安全隐患; 二次扩展:本框架可以在discuz框架内功能范围内,无限扩展任何自定义逻辑功能,也可以对discuz框架内所有功能模块,以及所有插件进行数据操作和调用; 访问验证:本框架结合discuz框架内置禁止IP、禁止访问会员组功能,实现对代理IP、会员组登录控制; 时间验证:本框架通过客户端时间与服务端时间进行验证,保证数据逻辑安全; 文件验证:本框架通过自定义客户端md5签名验证,确保客户端文件的完整性,有效防止对文件的破解、更改; 收费模式:扣点模式、购买用户组模式、计时扣费模式; 充值功能:结合discuz框架内置充值、充值卡功能,对用户进行积分充值; 代理功能:结合discuz框架内置充值、充值卡功能,用户可申请售卡打折权限,获取分红; 推广功能:结合discuz框架内置推广邀请人,被邀请人使用充值卡充值时,邀请人获取一定比例奖励; 心跳包功能:返回用户在线活动,验证机器码,对过期未发送心跳包进行下线处理; 变量功能:提供强大的远程变量、私人变量,单个变量理论可存储数据4G,让开发者更完美的开发软件; 卡号登陆:实行卡号直接登陆,与帐号绑定,卡号状态设置,独立控制更方便管理; 接口控制:强大的接口控制系统,每个接口独立设置每秒、每小时访问上线,并进行处理; 整合接口:本框架下通过自定义接口功能,添加外部api调用接口,通过本框架进行数据调用,扩展更强功能;(待开发) 接口模块: 登录模块:用户登录、插件配置、注册用户; 用户模块:用户信息、扩展信息、获取头像; 积分模块:积分增减; 好友模块:消息发送、好友信息; 充值模块:积分充值; 代理模块:提卡销售; 扩展模块:新增用户扩展数据存储、备注; 调用模块:帖子调用、会员排行; 日志模块:接口日志: 提现模块:申请提现、后台打款; 用户组模块:购买、充值、切换; 论坛模块:列表、发帖、回帖 排行模块:会员积分排行、扩展资料排行 手机模块:短信发送、手机绑定账号、手机登录 QQ模块:QQ登录 后续功能……
### 回答1: 在 .NET Core Web API 中进行 Token 验证通常涉及以下步骤: 1. 安装 Microsoft.AspNetCore.Authentication.JwtBearer 包。 2. 在 Startup.cs 文件的 ConfigureServices() 方法中添加身份验证服务,包括 JWTBearerOptions 配置。 3. 在 Startup.cs 文件的 Configure() 方法中启用身份验证中间件。 以下是一个基本的示例: ```csharp using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; public void ConfigureServices(IServiceCollection services) { // 配置身份验证服务 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = Configuration["Jwt:Issuer"], ValidAudience = Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"])) }; }); // 其他服务注册... } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 启用身份验证中间件 app.UseAuthentication(); // 其他中间件注册... } ``` 上述代码中,我们使用了 `AddAuthentication()` 方法来配置身份验证服务,并指定了 JWTBearerDefaults.AuthenticationScheme 作为默认身份验证方案。 接着,我们使用 `AddJwtBearer()` 方法来配置 JWTBearerOptions,其中 `TokenValidationParameters` 属性用于指定 Token 验证参数,例如验证发行者、受众、过期时间、签名密钥等。 最后,在 Configure() 方法中,我们调用 `UseAuthentication()` 方法来启用身份验证中间件,以确保每个请求都进行身份验证。 ### 回答2: 在.NET Core Web API中配置Token验证,可以按照以下步骤进行操作: 1. 添加NuGet包:在项目中添加Microsoft.AspNetCore.Authentication和Microsoft.AspNetCore.Authentication.JwtBearer两个NuGet包。 2. 配置认证服务:在Startup.cs文件的ConfigureServices方法中添加以下代码,以启用Bearer令牌验证: ``` services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, // 验证发行人 ValidateAudience = true, // 验证受众 ValidateLifetime = true, // 验证生命周期 ValidateIssuerSigningKey = true, // 验证颁发的签名密钥 ValidIssuer = "your_issuer", // 设置发行人 ValidAudience = "your_audience", // 设置受众 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key")) // 设置签名密钥 }; }); ``` 3. 配置授权:在Startup.cs文件的Configure方法中添加以下代码,以启用授权中间件: ``` app.UseAuthentication(); app.UseAuthorization(); ``` 4. 添加[Authorize]特性:在需要验证Token的Controller或Action上添加[Authorize]特性。 现在,当客户端请求受保护的Controller或Action时,将自动检查请求中的Token是否有效。如果Token验证失败,将返回401 Unauthorized状态码。如果验证成功,则可以继续处理请求。 ### 回答3: 在.NET Core WebAPI中配置Token验证主要涉及以下几个步骤: 1. 导入所需的包:首先,需要在`Startup.cs`文件中的`ConfigureServices`方法中导入所需的包。使用`Microsoft.AspNetCore.Authentication.JwtBearer`包来配置JWT验证。 2. 配置认证服务:在`ConfigureServices`方法中使用`services.AddAuthentication`来添加认证服务,并指定默认的身份验证方案。例如: ```csharp services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; // 是否要求HTTPS options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, // 验证发行者 ValidateAudience = true, // 验证接收者 ValidateLifetime = true, // 验证令牌有效期 ValidateIssuerSigningKey = true, // 验证签名 ValidIssuer = "your_issuer", ValidAudience = "your_audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key")) }; }); ``` 在上述代码中,可以根据自己的需求调整参数值,如验证发行者、接收者、令牌有效期、签名等。 3. 应用认证中间件:在`Configure`方法中,使用`app.UseAuthentication()`来应用认证中间件。确保此代码位于路由中间件之前。例如: ```csharp app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); ``` 4. 使用`Authorize`特性:在需要进行Token验证的Controller或Action上,可以使用`Authorize`特性来标记,以进行访问控制。例如: ```csharp [Authorize] public class MyController : ControllerBase { // ... } ``` 5. 在请求中包含Token:最后,在发送请求时,需要在请求头中包含Bearer Token,以进行验证。例如: ``` Authorization: Bearer your_token ``` 通过以上配置,就可以在.NET Core WebAPI中实现Token验证。这样,当请求到达API时,API验证Token的有效性,并对请求进行授权控制,确保只有拥有有效Token的用户可以访问受保护的资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值