接口参数签名校验,是WebApi接口服务最重要的安全防护手段之一. 结合项目中实际使用情况,介绍下前后端参数签名校验实现方案。

签名校验规则

http请求,有两种传参形式:

1.通过url传参,最常见的就是get请求(实际上post,put,delete都可以使用这种传参方式),如:

http://api.XXX.com/getproduct?id=value1

2.通过request body传参,最常见的就是post请求,如下图所示



我们针对于以上两种传参方式,采用不同的签名校验规则(注:签名算法规则仅供参考)。WebApi是不支持通过url和body同时传参数的,所以在服务端可以通过HttpContext.Current.Request.QueryString 获取到form参数进行判断,执行不同逻辑,如下代码所示:

var form = HttpContext.Current.Request.QueryString; // 请求的url参数
var data = string.Empty;
if (form.Count > 0)
{
//第一步:取出所有form参数
IDictionary<string, string> parameters = new Dictionary<string, string>();
for (var f = 0; f < form.Count; f++)
{
var key = form.Keys[f];
parameters.Add(key, form[key]);
} // 第二步:把字典按Key的字母顺序排序
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
var dem = sortedParams.GetEnumerator(); // 第三步:把所有参数名和参数值串在一起
var query = new StringBuilder();
while (dem.MoveNext())
{
var key = dem.Current.Key;
var value = dem.Current.Value;
if (!string.IsNullOrEmpty(key)) query.Append(key).Append(value);
}
data = query.ToString();
}
else
{
//请求输入的内容,即body内容
var stream = HttpContext.Current.Request.InputStream;
stream.Position = 0;
var responseJson = string.Empty;
var streamReader = new StreamReader(stream);
data = streamReader.ReadToEnd();
stream.Position = 0;
}

通过上述逻辑之后,data变量中存储的就是接口参数内容。 以下是实际签名校验逻辑

/// <summary>
/// 签名校验
/// </summary>
/// <param name="timeStamp">时间戳(按秒)</param>
/// <param name="data">参数内容</param>
/// <param name="signature">前端签名值</param>
/// <returns></returns>
public bool Validate(string timeStamp, string data, string signature)
{
var hash = MD5.Create();
//拼接签名数据
var signStr = timeStamp + data;
//将字符串中字符按升序排序
var sortStr = string.Concat(signStr.OrderBy(c => c));
var bytes = Encoding.UTF8.GetBytes(sortStr);
//使用32位大写 MD5签名
var md5Val = hash.ComputeHash(bytes);
var result = new StringBuilder();
foreach (var c in md5Val) result.Append(c.ToString("X2"));
var s = result.ToString().ToUpper();
//与前端传过来的签名参数进行比对
return s == signature;
}

Action拦截器实现对某些Api进行签名校验

创建WebApi的Action拦截器HandlerSecretAttribute

/// <summary>
/// 签名安全拦截过滤器
/// </summary>
public class HandlerSecretAttribute : ActionFilterAttribute
{
private readonly ExcuteMode _customMode; /// <summary>默认构造</summary>
/// <param name="Mode">认证模式</param>
public HandlerSecretAttribute(ExcuteMode Mode)
{
_customMode = Mode;
} /// <summary>
/// 安全校验
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuting(HttpActionContext filterContext)
{
//是否忽略权限验证
if (_customMode == ExcuteMode.Ignore) return; //从http请求的头里面获取AppId
var request = filterContext.Request;
var method = request.Method.Method;
var appId = ""; //客户端应用唯一标识
long timeStamp; //时间戳, 校验10分钟内有效
var signature = ""; //参数签名,去除空参数,按字母倒序排序进行Md5签名 为了提高传参过程中,防止参数被恶意修改,在请求接口的时候加上sign可以有效防止参数被篡改
try
{
appId = request.Headers.GetValues("appId").SingleOrDefault();
timeStamp = Convert.ToInt64(request.Headers.GetValues("timeStamp").SingleOrDefault());
signature = request.Headers.GetValues("signature").SingleOrDefault();
}
catch (Exception ex)
{
throw new UserFriendlyException("签名参数异常:" + ex.Message);
} #region 安全校验
//TODO:实际逻辑处理
base.OnActionExecuting(filterContext);
#endregion
}
}

具体的使用,如下图所示:

如果是需要全局注册,请在WebApi.config中配置,如下图所示:

有关HandlerSecretAttribute的源代码,我已整理放至github上https://github.com/yinboxie/BlogExampleDemo

前端Axios请求统一拦截处理

客户端http请求(以Axios为例)进行统一的拦截处理。前端用过诸多http插件,如ajax,fetch,vue-resoure,axios等,个人感觉axios的请求拦截是最好用的。

import axios from 'axios'
import { sign } from './sign'
let _ = require('lodash')
var service = axios.create({
baseURL:'http://xxx.com'
timeout:10000 // 请求超时时间
}) // request拦截器
service.interceptors.request.use(
config => {
let token = getToken()
if (token) {
config.headers['token'] = token // 让每个请求携带自定义token 请根据实际情况自行修改
}
// 如果接口需要签名, 则通过请求时,headers中传递sign参数true
if (config.headers['sign']) {
config = sign(config) // 核心签名逻辑,独立封装了处理函数
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)

sign函数核心源码

import md5 from 'js-md5'
let _ = require('lodash')
/**
* 接口参数签名
* @param {*} config 请求配置
*/
export const sign = config => {
// 获取到秒级的时间戳,与后端对应
let tmp = new Date()
.getTime()
.toString()
.substr(0, 10)
let header = {
appId:'pmes',
timeStamp: tmp,
signature: ''
}
let signStr = _.toString(header.timeStamp)
if (config.params) {
// url参数签名
let pArray = []
for (let p in config.params) {
pArray.push(p)
}
let sArray = pArray.sort()
for (let item of sArray) {
signStr += item + _.toString(config.params[item])
}
} else if (config.data) {
// request body参数的内容
signStr += JSON.stringify(config.data)
} // 签名核心逻辑
let newsignStr = _.sortBy(signStr, s => s.charCodeAt(0)).join('')
let s = md5(newsignStr).toUpperCase()
header.signature = s
config = Object.assign(config, { headers: header })
return config
}

实际的调用函数

// post请求, body传参
axios.post('/Login/CheckLoginTest1',
{ Account: 'xiaowang',Password: '123' },
{ headers: { sign: true }}
).then(d => {
console.log(d)
})
// post请求,url传参
axios.post('/Login/CheckLoginTest3',
null,
{
params: {t1: '2',t2: '3'},
headers: { sign: true }
}
).then(d => {
console.log(d)
})
// get请求
axios.get('/Login/CheckLoginTest2',
{
params: {t1: '2',t2: '3'},
headers: { sign: true }
}
).then(d => {
console.log(d)
})

总结

为了保证WebApi数据在通信时的安全性,需要采取多重安全防护: 参数签名校验,token验证,跨域权限,时间戳过期校验,允许请求的appId校验等。当然具体的规则我们都得依据项目实际情况去实现,这里就不再展开讨论其他方式的实现。

参考

WebApi安全性 使用TOKEN+签名验证

WebApi安全性 参数签名校验(结合Axios使用)的更多相关文章

  1. [置顶] webapi token、参数签名是如何生成的

    一个问题 在这里我想问大家一句,如果你向一个刚刚接触.net web后端程序开发的同学(别人刚刚也就学了webform的request,response,会提交表单的这种刚接触不久的同学),你怎么去解 ...

  2. webapi token、参数签名是如何生成的(转载)

    API接口保障安全性原则:1.有调用者身份2.请求的唯一性3.请求的参数不能被篡改4.请求的有效时间 在刚接触接口开发时,可能脑子里压根就没有这个接口调用安全性的原则,但常识性的经验告诉我们,每一个请 ...

  3. webAPI过滤器添加参数签名

    项目需求: 接口对安卓和IOS开发接口,需要房子用户窜改数据请求接口.添加sign签名校验参数. 代码如下:加上特性标签就可以控制部分接口验证 public class SignAuthorizeFi ...

  4. WebApi安全性 使用TOKEN+签名验证

    首先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候,会面临着许多的安全性问题, ...

  5. WebAPI 安全性 使用TOKEN+签名验证(上)

    首先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候,会面临着许多的安全性问题, ...

  6. WebApi安全性 使用TOKEN+签名验证 (秘钥是GUID的,私有的,不是雙方的,并不在网络连接上传输)

    转http://www.cnblogs.com/MR-YY/archive/2016/10/18/5972380.html WebApi安全性 使用TOKEN+签名验证   首先问大家一个问题,你在写 ...

  7. 接口鉴权之sign签名校验与JWT验证

    需求描述: 项目里的几个Webapi接口需要进行鉴权,同接口可被小程序或网页调用,小程序里没有用户登录的概念,网页里有用户登录的概念,对于调用方来源是小程序的情况下进行放权,其他情况下需要有身份验证. ...

  8. Apk去签名校验详解

    某些apk为了防止重打包,使用了签名校验.所以在破解的时候我们需要破解签名校验.在定位签名校验位置时常用的关键词有sign,signature,checkSign,signCheck,getPacka ...

  9. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

随机推荐

  1. `protected` vs `private`

    private 标识为 private 的属性为私有属性,不能在除自己外的地方进行访问. protected 标识为 protected 的属性为受保护的属性,与私有属性类似,但还可以在继承类中进行访 ...

  2. C#上手练习5(GOTO语句)

    C# goto 语句用于直接在一个程序中转到程序中的标签指定的位置,标签实际上由标识符加上冒号构成 语法形式如下. goto Labell;    语句块 1;Labell    语句块 2; 如果要 ...

  3. java基础(15):常用API(Object、String、StringBuffer)

    1. Java的API及Object类 在以前的学习过程中,我们都在学习对象基本特征.对象的使用以及对象的关系.接下来我们开始使用对象做事情,那么在使用对象做事情之前,我们要学习一些API中提供的常用 ...

  4. ASP.Net MVC 路由及路由调试工具RouteDebug

    一.路由规则 1.可以创建多条路由规则,每条路由的name属性不相同 2.路由规则有优先级,最上面的路由规则优先级越高 App_Start文件下的:RouteConfig.cs public stat ...

  5. Spring Boot 之异步执行方法

    前言: 最近的时候遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行.开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种 ...

  6. querySelectorAll和getElementsByClassName获取元素的区别

    querySelectorAll()方法是HTML5新增的方法,通过传入一个css选择符,返回所有匹配的元素而不仅仅是一个元素.这个方法返回的是一个NodeList的实例.那么它和通过getEleme ...

  7. 「SAP技术」 SAP MM MPN物料的采购初探

    「SAP技术」 SAP MM MPN物料的采购初探 1, MPN物料号与我方正常使用料号物料主数据之间的LINK关系维护 MPN料号 14000005 , 我方料号11000250 , 2,采购信息记 ...

  8. if语句,if...else语句的分析

    if语句的反汇编判断 if语句的反汇编判断基本是围绕JCC指令的,如果想要有深刻的理解,可以自行练习JCC指令 执行各类影响标志位的指令 jxx xxxx 1.案例一 mov eax,dword pt ...

  9. JAVA基础复习(重点)

    一. 初识Java编程 1.           Java开发环境 JDK Java开发工具 JVM Java虚拟机 JRE Java运行环境 2.实现第一个hello world public cl ...

  10. python session保持登录,新增地址,并删除,由观察可知,address_id决定删除的内容;

    import requests,reheaders={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) Ap ...