『你的API接口安全么』之给NetCore请求参数加解密!

2023-11-13 20:41:01 浏览数 (1)

(忽如一夜春风来 _ _ _ _ _ _ _)

大家好,天气骤降,你那里下雪了么。

1、故事背景

最近一直在接触安全相关的东西,无论是看书,看新闻,还是写项目——网络安全,接口安全,数据安全,资源安全等等已经被纷纷讨论和津津乐道了,平时在上班的路上经常会思考一些架构设计相关的内容,或者看些书,那正好也考虑了一个接口安全的内容给大家分享一下,一共两篇,这是接口请求篇,另一个是接口返回响应内容篇:

2、整体设计思路

首先,我们需要定义一种加密方式,当前需要和前端商量好,肯定是需要前端也能加解密的,其实有很多种,这里用Base64来演示,大家下载BlogCore最新代码就能看到两个中间件,自己根据公司情况进行修改即可。

其次,我们用一个接口做例子:

http://localhost:9291/api/Login/GetJwtTokenSecret?name=blogadmin&pass=blogadmin

这是一个很简单的接口,有两个参数,分别是用户名和密码。

然后模拟登录,请求会返回token:

这样其实是不安全的,当然你可能会说用https会安全,这也不尽然,毕竟再加密一下肯定会更安全的嘛。前端小伙伴可以对这个参数进行base64加密,比如这样:

所以最终接口是这样的:

http://localhost:9291/api/Login/GetJwtTokenSecret?param=bmFtZT1ibG9nYWRtaW4mcGFzcz1ibG9nYWRtaW4=

第三,就是我们的重中之重,请求参数解密中间件。

我们需要统一的对接口入参进行解密,然后将解密的参数,再塞到接口中,往下请求,所以聪明的你肯定知道如何处理,而且也要放到中间件管道外层,代码是这样,当然后期会微调,大家还是看BlogCore最新更新就行了。

代码语言:javascript复制
 public async Task InvokeAsync(HttpContext context)
 {
     // 配置开关,过滤接口
     if (AppSettings.app("Middleware", "EncryptionRequest", "Enabled").ObjToBool())
     {
         var isAllApis = AppSettings.app("Middleware", "EncryptionRequest", "AllApis").ObjToBool();
         var needEnApis = AppSettings.app<string>("Middleware", "EncryptionRequest", "LimitApis");
         var path = context.Request.Path.Value.ToLower();
         if (isAllApis || (path.Length > 5 && needEnApis.Any(d => d.ToLower().Contains(path))))
         {
             Console.WriteLine($"{isAllApis} -- {path}");

             if (context.Request.Method.ToLower() == "post")
             {
                 // 读取请求主体
                 using StreamReader reader = new(context.Request.Body, Encoding.UTF8);
                 string requestBody = await reader.ReadToEndAsync();

                 // 检查是否有要解密的数据
                 if (!string.IsNullOrEmpty(requestBody) && context.Request.Headers.ContainsKey("Content-Type") &&
                     context.Request.Headers["Content-Type"].ToString().ToLower().Contains("application/json"))
                 {
                     // 解密数据
                     string decryptedString = DecryptData(requestBody);

                     // 更新请求主体中的数据
                     context.Request.Body = GenerateStreamFromString(decryptedString);
                 }
             }
             else if (context.Request.Method.ToLower() == "get")
             {
                 // 获取url参数
                 string param = context.Request.Query["param"];

                 // 检查是否有要解密的数据
                 if (!string.IsNullOrEmpty(param))
                 {
                     // 解密数据
                     string decryptedString = DecryptData(param);

                     // 更新url参数值
                     context.Request.QueryString = new QueryString($"?{decryptedString}");
                 }
             }

             await _next(context);
         }
         else
         {
             await _next(context);
         }
     }
     else
     {
         await _next(context);
     }
 }

核心的地方就是在信息解密那个节点,然后回填。

最后呢,就是运行下项目,就可以看到能正常的请求到接口了,而且参数也没问题:

到这里,我们就很简单的,完美的实现了这个需求,而且不用修改之前的任意代码,只需要一个中间件,就能实现,还可以手动进行控制,比如指定某几个接口等,也可以控制get请求和post请求等等。

不知道你是否有更好的建议呢,欢迎评论留言哟。

下篇文章,我们来讨论下,如何实现接口返回的时候,如何对返回内容进行加密。

0 人点赞