WebAPi接口安全之公钥私钥加密

这篇具有很好参考价值的文章主要介绍了WebAPi接口安全之公钥私钥加密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

WebAPi使用公钥私钥加密介绍和使用

随着各种设备的兴起,WebApi作为服务也越来越流行。而在无任何保护措施的情况下接口完全暴露在外面,将导致被恶意请求。最近项目的项目中由于提供给APP的接口未对接口进行时间防范导致短信接口被怒对造成一定的损失,临时的措施导致PC和app的防止措施不一样导致后来前端调用相当痛苦,选型过oauth,https,当然都被上级未通过,那就只能自己写了,就很,,ԾㅂԾ,,。下面就此次的方式做一次记录。最终的效果:传输过程中都是密文,别人拿到请求串不能更改请求参数,通过接口过期时间防止同一请求串一直被调用。
 

   第一步重写MessageProcessingHandler中的ProcessRequest和ProcessResponse


无论是APi还是Mvc请求管道都提供了我们很好的去扩展,本次说的是api,其实mvc大概意思也是差不多的。我们现在主要写出大致流程

webapi接口加密,安全,servlet,java,web安全,网络安全

从图中可以看出我们需要在MessageProcessingHandlder上做处理。我们继承MessageProcessingHandlder重写ProcessRequest和ProcessResponse方法,从方法名可以看出一个是针对请求值处理,一个是针对返回值处理代码如下:

 1  public class CustomerMessageProcesssingHandler : MessageProcessingHandler
 2     {
 3         protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
 4         {
 5             var contentType = request.Content.Headers.ContentType;
 6 
 7             if (!request.Headers.Contains("platformtype"))
 8             {
 9                 return request;
10             }
11             //根据平台编号获得对应私钥
12             string privateKey = Encoding.UTF8.GetString(Convert.FromBase64String(ConfigurationManager.AppSettings["PlatformPrivateKey_" + request.Headers.GetValues("platformtype").FirstOrDefault()]));
13             if (request.Method == HttpMethod.Post)
14             {
15                 // 读取请求body中的数据
16                 string baseContent = request.Content.ReadAsStringAsync().Result;
17                 // 获取加密的信息
18                 // 兼容 body: 加密数据  和 body: sign=加密数据
19                 baseContent = Regex.Match(baseContent, "(sign=)*(?<sign>[\\S]+)").Groups[2].Value;
20                 // 用加密对象解密数据
21                 baseContent = CommonHelper.RSADecrypt(privateKey, baseContent);
22                 // 将解密后的BODY数据 重置
23                 request.Content = new StringContent(baseContent);
24                 //此contentType必须最后设置 否则会变成默认值
25                 request.Content.Headers.ContentType = contentType;
26             }
27             if (request.Method == HttpMethod.Get)
28             {
29                 string baseQuery = request.RequestUri.Query;
30                 // 读取请求 url query数据
31                 baseQuery = baseQuery.Substring(1);
32                 baseQuery = Regex.Match(baseQuery, "(sign=)*(?<sign>[\\S]+)").Groups[2].Value;
33                 baseQuery = CommonHelper.RSADecrypt(privateKey, baseQuery);
34                 // 将解密后的 URL 重置URL请求
35                 request.RequestUri = new Uri($"{request.RequestUri.AbsoluteUri.Split('?')[0]}?{baseQuery}");
36             }
37             return request;
38         }
39         protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
40         {
41             return response;
42         }
43     }

上面的代码大部分已经有注释了,但这里说明三点第一:platformtype用来针对不同的平台设置不同的公钥和私钥;第二:在post方法中ContentType一定要最后设置,否则会成为默认值,这个问题会导致webapi不能进行正确的参数绑定;第三:有人可能会问这里ProcessResponse是不是可以不用重写?答案是必须重写如果不想对结果操作直接返回就如上当然你也可以在此对返回值进行加密,但是个人认为意义不大,看具体情况因为大部分数据加密后前端还是需要解密然后展示所以此处不做任何处理。在这一步我们已经对前端请求的加密串在handler中处理成明文重新赋值给HttpRequestMessage。

  第二步重写AuthorizeAttribute中OnAuthorization和HandleUnauthorizedRequest


webapi接口加密,安全,servlet,java,web安全,网络安全

上图是Api中Filter的请求顺序,我们在第一个Filter上处理,代码如下:

 1    public class CustomRequestAuthorizeAttribute : AuthorizeAttribute
 2     {
 3 
 4         public override void OnAuthorization(HttpActionContext actionContext)
 5         {
 6             //action具有[AllowAnonymous]特性不参与验证
 7             if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>().Any(x => x is AllowAnonymousAttribute))
 8             {
 9                 base.OnAuthorization(actionContext);
10                 return;
11             }
12             var request = actionContext.Request;
13             string method = request.Method.Method, timeStamp = string.Empty, expireyTime = ConfigurationManager.AppSettings["UrlExpireTime"], timeSign = string.Empty, platformType = string.Empty;
14             if (!request.Headers.Contains("timesign") || !request.Headers.Contains("platformtype") || !request.Headers.Contains("timestamp") || !request.Headers.Contains("expiretime"))
15             {
16                 HandleUnauthorizedRequest(actionContext);
17                 return;
18             }
19             platformType = request.Headers.GetValues("platformtype").FirstOrDefault();
20             timeSign = request.Headers.GetValues("timesign").FirstOrDefault();
21             timeStamp = request.Headers.GetValues("timestamp").FirstOrDefault();
22             var tempExpireyTime = request.Headers.GetValues("expiretime").FirstOrDefault();
23             string privateKey = Encoding.UTF8.GetString(Convert.FromBase64String(ConfigurationManager.AppSettings[$"PlatformPrivateKey_{platformType}"]));
24             if (!SignValidate(tempExpireyTime, privateKey, timeStamp, timeSign))
25             {
26                 HandleUnauthorizedRequest(actionContext);
27                 return;
28             }
29             if (tempExpireyTime != "0")
30             {
31                 expireyTime = tempExpireyTime;
32             }
33             //判断timespan是否有效
34             double ts2 = ConvertHelper.ToDouble((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds, 2), ts = ts2 - ConvertHelper.ToDouble(timeStamp);
35             bool falg = ts > int.Parse(expireyTime) * 1000;
36             if (falg)
37             {
38                 HandleUnauthorizedRequest(actionContext);
39                 return;
40             }
41             base.IsAuthorized(actionContext);
42         }
43         protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
44         {
45             base.HandleUnauthorizedRequest(filterContext);
46 
47             var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage();
48             response.StatusCode = HttpStatusCode.Forbidden;
49             var content = new
50             {
51                 BusinessStatus = -10403,
52                 StatusMessage = "服务端拒绝访问"
53             };
54             response.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
55         }
56         private bool SignValidate(string expiryTime, string privateKey, string timestamp, string sign)
57         {
58             bool isValidate = false;
59             var tempSign = CommonHelper.RSADecrypt(privateKey, sign);
60             if (CommonHelper.EncryptSHA256($"expiretime{expiryTime}" + $"timestamp{timestamp}") == tempSign)
61             {
62                 isValidate = true;
63             }
64             return isValidate;
65         }
66     }

请求头部增加参数expiretime使用此参数作为本次接口的过期时间如果没有则表示使用平台默认的接口时间,是我们可以针对不同的接口设置不同的过期时间;timestamp请求时间戳来防止别人拿到接口后一直调用timesign是过期时间和时间戳通过hash然后在通过公钥加密的串来防止别人修改前两个参数。重写HandleUnauthorizedRequest来设置返回内容。


至此整个验证过程就结束了,我们在使用过程中可以建立BaseApi将特性标记上让其他APi继承,当然我们的接口中可能有的action不需要验证看OnAuthorization第一行代码 增加相应的特性跳过此验证。在整个过程中其实我们已经使用了两种加密方式。一是本文中的CustomerMessageProcesssingHandler;另外一种就是timestamp+QueryString然后hash 在公钥加密 这样就不需要CustomerMessageProcesssingHandler其实就是本文中的头部加密方式。

补充:园友建议增加请求端实例,确实是昨天有所遗漏。趁不忙补充上:

本次以HttpClient调用方式为例,展示Get,Post请求加密到执行的相应的action的过程;首先看一下Get请求如下:

webapi接口加密,安全,servlet,java,web安全,网络安全

可以看到我们的请求串url已经是密文,头部时间sign也是密文,除非别人拿到我们的私钥不然是不能修改其参数的。然后请求到达我们的CustomerMessageProcesssingHandler中我们看下Get中得到的参数是:

webapi接口加密,安全,servlet,java,web安全,网络安全

这是我们得到的前端传过来的querystring的参数他的值就是我们前端加密后传过来的下一步我们解密应该要得到未加密之前的参数也就是客户端中id=1同时重新给requesturi赋值;

webapi接口加密,安全,servlet,java,web安全,网络安全

结果中我们可以看到id=1已被正确解密得到。接下来进入我们的CustomRequestAuthorizeAttribute

webapi接口加密,安全,servlet,java,web安全,网络安全

在这一步我们进行对timeSign的解密对请求只进行hash对比然后验证时间戳是否在过期时间内最终我们到达相应的action:

webapi接口加密,安全,servlet,java,web安全,网络安全

这样整个请求也就完成了Post跟Get区别不大重要的在于拿到传递参数的地方不一样这里我只贴一下调用的代码过程同上:

 1   public static void PostTestByModel() {
 2 
 3             HttpClient http = new HttpClient();
 4             var timestamp = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds;
 5             var expiretime = "600";
 6             var timesign = RSAEncrypt(publicKey, EncryptSHA256($"expiretime{expiretime}timestamp{timestamp}"));
 7             var codeValue = RSAEncrypt(publicKey, JsonConvert.SerializeObject(new Tenmp { Id = 1, Name = "cl" }));
 8             http.DefaultRequestHeaders.Add("platformtype", "Web");
 9             http.DefaultRequestHeaders.Add("timesign", $"{timesign}");
10             http.DefaultRequestHeaders.Add("timestamp", $"{string.Format("{0:N2}", timestamp.ToString()) }");
11             http.DefaultRequestHeaders.Add("expiretime", expiretime);
12             var url1 = string.Format($"{host}api/Values/PostTestByModel");
13             HttpContent content = new StringContent(codeValue);
14             MediaTypeHeaderValue typeHeader = new MediaTypeHeaderValue("application/json");
15             typeHeader.CharSet = "UTF-8";
16             content.Headers.ContentType = typeHeader;
17             var response1 = http.PostAsync(url1, content).Result;
18         }

最后当验证不通过得到的返回值:

webapi接口加密,安全,servlet,java,web安全,网络安全

这也就是重写HandleUnauthorizedRequest的目的 当然你也可以不重写此方法那么返回的就是401 英文的未通过验证。文章来源地址https://www.toymoban.com/news/detail-756269.html

到了这里,关于WebAPi接口安全之公钥私钥加密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 私钥和公钥到底是谁来加密、谁来解密?

    1.  应用场景 场景1(第一种用法):用于信息加解密,此时使用公钥加密,私钥解密。 场景2(第二种用法):用于数字签名,此时使用私钥签名,公钥验签。 有点混乱,不要去硬记,你只要这样想即可: - 既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解

    2023年04月15日
    浏览(79)
  • C#.NET Framework RSA 公钥加密 私钥解密 ver:20230609

    C#.NET Framework RSA 公钥加密 私钥解密 ver:20230609   环境说明: .NET Framework 4.6 的控制台程序 。   .NET Framework 对于RSA的支持: 1. .NET Framework 内置只支持XML格式的私钥/公钥。如果要用PKCS1,PKCS8格式的,要用到三方库BouncyCastle。 2. .NET 中默认加密算法为“RSA/ECB/PKCS1Padding” ,要和

    2024年02月08日
    浏览(72)
  • C# .NET CORE .NET6 RSA 公钥加密 私钥解密

    环境说明: .NET CORE 版本:.NET 6 。   .NET CORE 对于RSA的支持: 1. .NET 6 中内置了对 PKCS1,PKCS8 2种私钥格式的支持。 2. 如果你要部署在Linux,docker ,k8s 中;一定要用 “RSA”这个类,不能是 .NET FRAMEWORK 的 RSACryptoServiceProvider。 3. .NET 中默认加密算法为“RSA/ECB/PKCS1Padding” ,要和JAVA互通

    2024年02月08日
    浏览(94)
  • RSA加密,公钥、私钥的生成,前端使用公钥加密,JSEncrypt返回值为false的原因以及解决方法,XML转换Pkcs1、8

    非对称加密算法,两个且不同的Key,一个公开,一个私密,公开加密,私密解密。 特点: 原文短,加密后密文长 生成相对较慢 安全性超强 我们使用.net进行生成公钥、私钥。 使用RSA.ToXmlString(Boolean) 方法生成公钥以及私钥,方法中接收一个参数, true  表示同时包含 RSA 公钥

    2024年01月21日
    浏览(65)
  • C# webapi接口调用实例

    书接上回C# WebServiceWebApi接口项目创建,在demo的基础上进行webapi接口调用实例开发。 WebApi接口项目public分支https://gitee.com/xiuhuang/webapi_demo 进行接口调用的类库项目public分支https://gitee.com/xiuhuang/dll_demo 下文中提到的所有修改都可以在gitee上看到与demo的修改处直观对比,并且复制

    2024年02月07日
    浏览(48)
  • C# WebService&WebApi接口项目创建

    注意勾选红框项,默认是不勾选的,否则创建新项目时会找不到ASP.NET Web应用程序(.NET Framework)的模板。 0.demo源码获取:https://gitee.com/xiuhuang/webservice_demo 1.创建新项目,选择ASP.NET Web应用程序(.NET Framework)。 2.点击下一步,到这个页面时选择空。 3.选中项目右键,添加-新建项,

    2024年02月05日
    浏览(59)
  • RSA加解密工具类(PKCS8公钥加密,PKCS1私钥解密)

    场景 :如果项目上生成的秘钥,公钥是PKCS8格式,私钥却是PKCS1格式。需要在这种场景加解密的话可以直接使用下面工具类。 特殊说明:私钥解密的时候必须把私钥源文件内容整个传入,不能删除私钥的文件头和文件尾,并且不能删除换行。

    2024年02月11日
    浏览(67)
  • 使用EF Core创建webapi接口(二)

    有错误欢迎大家给我指正 说明:netcore webapi+net6+EF Core版本,codefirst模式(代码创建数据库) 1.netcore webapi+net6+EF Core版本,dbfirst模式(代码生成数据库)见:使用EF Core创建webapi接口(一)-CSDN博客 2.netcore webapi+net6+EF Core+vue前后端联动版本,见netcore webapi+net6+EF Core+vue3前后端联动-CSD

    2024年02月21日
    浏览(44)
  • 搭建一个简易框架 3秒创建一个WebApi接口

    前端ajax请求数据,传递的参数都是一个json字符串,经过多次解析发现其实都是一个DataSet {\\\"selectA1\\\":[{\\\"Name\\\":\\\"156324\\\"}]} {\\\"selectA1\\\":[{\\\"Name\\\":\\\"156324\\\"}],\\\"selectA2\\\":[{\\\"IdA\\\":\\\"11\\\",\\\"IdB\\\":\\\"12\\\"},{\\\"IdA\\\":\\\"13\\\",\\\"IdB\\\":\\\"14\\\"}]} 既然如此那么数据库设计一张表 . . 前端请求数据时传递一个字符串JsonParm,里面放json格式

    2024年02月03日
    浏览(36)
  • Winform窗体利用WebApi接口实现ModbusTCP数据服务

    在上位机开发过程中,有时候会遇到需要提供数据接口给MES或者其他系统,今天跟大家分享一下,如何在Winform等桌面应用程序中,开发WebApi接口,提供对外modbus设备的数据服务。通讯模型是: 为了更好地演示应用场景,本案例以读取ModbusTCP设备为例,开发好WeiApi接口后,第

    2024年02月05日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包