post 防篡改_WebAPI 用户认证防篡改实现HMAC(一)MD5签名获取

本文介绍了WebAPI中防止数据被篡改的HMAC机制,通过结合合作号、合作Key和MD5摘要来确保请求的安全。详细讲解了如何组织字符串进行MD5加密,并提供了C#代码示例,展示了签名生成过程以及如何处理GET和POST请求的签名。
摘要由CSDN通过智能技术生成

原文:http://blog.csdn.net/starfd/article/details/43487587

在开始前先说下HMAC防篡改机制的原理,如果已经接触过支付宝的可以跳过此部分

防篡改,顾名思义就是防止有人恶意篡改请求数据以达到恶意攻击的目的,那要怎么才能实现这样的目的呢?其实很简单,将要请求的数据加上合作号、合作Key按规则组织成一个字符串,获取对应的MD5摘要,然后将该摘要及合作号同时作为请求的一部分一起传递(合作Key禁止传递)

下面进行举例:

假定需要进行签名的参数如下(以json格式举例):

{‘partner’: ‘3122131212’,‘orderNo’:‘1234567’}

对数组里的每一个键按默认的字母正向排序,最后加上partner对应的key进行MD5加密,假定对应的key为bbb,则需要进行MD5摘要的字符串如下:

partner=3122131212&orderNo=1234567bbb

最终需要传递的请求数据格式如下(分别列举GET和POST方式,服务实际支持哪种方式以服务声明为准):

GET:partner=3122131212&orderNo=1234567&sign=EBFE84D02E8E40952899EE5CDFE5404C

POST:{‘partner’:‘3122131212’,‘orderNo’:‘1234567’ ,‘sign:‘EBFE84D02E8E40952899EE5CDFE5404C’}

上例中partner为平台提供的合作号,key为合作密码,sign为签名,然后此处例子是将Get和Post区分开来的,实际获取MD5的代码会支持QueryString及Form同时存在的情况,且当两者同时存在时,组织字符串顺序为先QueryString后Form

以下是签名摘要生成代码

using System;

using System.Collections.Generic;

using System.Collections.Specialized;

using System.Security.Cryptography;

using System.Text;

public static class SecuritySignHelper

{

public const string Partner = "partner";

public const string Sign = "sign";

/// 

/// 获取防篡改签名,组织原始字符串的方式为:先get后post,该签名要求partner在加密时为全小写,同时该方法隐含要求parnter和sign必须通过QueryString方式传递

/// 

/// 通过QueryString方式传递的键值集合,如果内部包含parnter或者sign,相关字段在组织原始字符串时将会被移除

/// 合作账号

/// 合作Key

/// 通过Form方式传递的键值集合,如果包含parnter或者sign,此部分不会被做特殊处理

/// 

public static string GetSecuritySign(this NameValueCollection getCollection, string partner, string partnerKey, NameValueCollection postCollection = null)

{

if (string.IsNullOrWhiteSpace(partner) || string.IsNullOrWhiteSpace(partnerKey))

{

throw new ArgumentNullException();

}

var dic = SecuritySignHelper.GetSortedDictionary(getCollection,

(k) =>

{//过滤partner及sign

return string.Equals(k, SecuritySignHelper.Partner, StringComparison.OrdinalIgnoreCase)

|| string.Equals(k, SecuritySignHelper.Sign, StringComparison.OrdinalIgnoreCase);

});

dic.Add(SecuritySignHelper.Partner, partner);

StringBuilder tmp = new StringBuilder();

SecuritySignHelper.FillStringBuilder(tmp, dic);//将QueryString填入StringBuilder

dic = SecuritySignHelper.GetSortedDictionary(postCollection);

SecuritySignHelper.FillStringBuilder(tmp, dic);//将Form填入StringBuilder

tmp.Append(partnerKey);//在尾部添加key

tmp.Remove(0, 1);//移除第一个&

return tmp.ToString().GetMD5_32();//获取32位长度的Md5摘要

}

private static SortedDictionary GetSortedDictionary(NameValueCollection collection, Func filter = null)

{//获取排序的键值对

SortedDictionary dic = new SortedDictionary();

if (collection != null && collection.Count > 0)

{

foreach (var k in collection.AllKeys)

{

if (filter == null || !filter(k))

{//如果没设置过滤条件或者无需过滤

dic.Add(k, collection[k]);

}

}

}

return dic;

}

private static void FillStringBuilder(StringBuilder builder, SortedDictionary dic)

{

foreach (var kv in dic)

{

builder.Append('&');

builder.Append(kv.Key);

builder.Append('=');

builder.Append(kv.Value);

}//按key顺序组织字符串

}

/// 

/// 获取32位长度的Md5摘要

/// 

/// 

/// 

/// 

public static string GetMD5_32(this string inputStr, Encoding encoding = null)

{

RefEncoding(ref encoding);

byte[] data = GetMD5(inputStr, encoding);

StringBuilder tmp = new StringBuilder();

for (int i = 0; i 

{

tmp.Append(data[i].ToString("x2"));

}

return tmp.ToString();

}

private static byte[] GetMD5(string inputStr, Encoding encoding)

{

using (MD5 md5Hash = MD5.Create())

{

return md5Hash.ComputeHash(encoding.GetBytes(inputStr));

}

}

private static void RefEncoding(ref Encoding encoding)

{

if (encoding == null)

{

encoding = Encoding.Default;

}

}

}

使用例子

string partner = "zhangsan";

string partnerKey = "bbb";

NameValueCollection getCollection = new NameValueCollection();

string md50 = getCollection.GetSecuritySign(partner, partnerKey);//不带任何参数的请求

getCollection.Add("test", "123");

string md51 = getCollection.GetSecuritySign(partner, partnerKey);//带一个参数的请求

NameValueCollection postCollection = new NameValueCollection();

postCollection.Add("Name", "张三");

postCollection.Add("Address", "上海");

string md52 = getCollection.GetSecuritySign(partner, partnerKey, postCollection);//同时存在QueryString及Form的请求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值