一个简单的前后端传输加密方案

释放双眼,带上耳机,听听看~!

背景

其实前段时间迭代业务开发的不亦乐乎(包括摸鱼), 突然收到来自公司安全部门提出的一个问题, 说我们的项目数据会被篡改.

例如查询detail的一个接口, 如果用户A 只有在列表查询张三这条数据的数据权限, 且在列表页只能看见张三这条数据, 对于普通用户而言直接调用detail接口, 虽然在列表看不到李四的数据, 但是只要把入参的id字段稍稍修改一下, 就会查到自己数据权限之外的数据, 以点带面, 通过篡改数据, 还会做一些其他的事情.

因此, 项目组要通过技术方案, 解决此类问题————前后端加密.

什么是前后端加密

其实加密呢, 就是对前后端传输的数据进行通过前后端约定的规则和算法进行加密传输, 服务器每次接受请求的时候, 都会对这次请求的加密结果进行比对, 或者用私钥其解密;

先说说风险, 其实前后端传输数据的时候都是明文传输, 也就是说传输的数据用抓包工具就清晰可见, 例如你登陆的账号密码;

再例如, 如果每次提交一个表单的时候, 数据被劫持篡改, 提交了你不想要的数据, 如果你填写了你的店铺地址, 结果请求的店铺地址被篡改到钓鱼网站, 或者其他竞争者的店铺, 就会给你带来经济上的损失;

所以说, 前后端加密对如今http这种明文传输协议是势在必行的.

前端如何进行加密

其实我做的加密的大体方式很简单, 就是通过md5进行了对称加密; 并没有采用非对称加密, 主要是为了防止篡改数据, 所以足够了.

二话不说先上代码:

// 这是个请求拦截器
requestInterceptors: [
    ...
      return {
        ...
        options: {
          ...
          headers: {
            // 加密的结果放在请求头的sign字段中传输给后端(前后端约定的字段)
            sign: requestSign(url, options), // 传输加密字段, payload为空传 (null) .
          },
        },
      };
    },
  ],

如代码所示, 我们要在请求头中把我们加密的东东塞进去, 传输给后端;

下面再来看看这个requestSign方法是如何实现的:

type requestSignType = (url: string, options?: RequestOptionsInit) => string | null;

// 传输加密
export const requestSign: requestSignType = (url, options) => {
  // PUBLIC_KEY 前后端通用加密key.
  const PUBLIC_KEY = '假装这是一个约定好的key';

  /*
   * 由于get请求有的query参数卸载url上, 有的放在请求 方法的params字段里,
   * 所以针对不同编码方式采取通过 url | options.params 的取值方式获取参数.
   * */

  if (
    options.method.toLocaleLowerCase() === 'get' &&
    (Object.keys(parseQuery(url.split('?')[1])).length !== 0 ||
      Object.keys(options.params).length !== 0)
  ) {
    const tmpData: Record<string, any> =
      Object.keys(parseQuery(url.split('?')[1])).length !== 0
        ? { ...parseQuery(url.split('?')[1]) }
        : { ...options.params };
    let result: string = '';
    
    for (const item of Object.keys(tmpData).sort()) result += `${item}=${tmpData[item]}&`;
    
    return md5(`${result.substring(0, result?.length - 1)}${PUBLIC_KEY}`);
  }

  if (options.method.toLocaleLowerCase() === 'post') {
    return md5(`${JSON.stringify(options?.data)}${PUBLIC_KEY}`);
  }

  return null;
};

代码可见, 根据不同的方法, 采取不同的加密方式:

  1. GET: parseQuery方法是解析query参数的, 由于我们后端在将query参数parseJSON的时候, 字段顺序可能不一样, 所以前后端约定将字段名称通过sort方法按照英文字母的ASSIC的顺序进行排序后, 再咱找顺序组成约定的字符格式, 最后转成JSON字符串进行加密.
  2. PSOT: 如果是post方法, 就对整个body进行转换加密.

全部都用转化后的字符串拼接上约定好的PUBLIC_KEY进行MD5加密.

解决了什么问题?

这么做防止了数据的篡改, 如果hacker通过篡改数据做一些不为人知的勾当, 后台会拿到本次请求的数据进行加密比对, 如果被篡改, 获得的hash值就会完全不同, 就会判断数据被篡改, 从而拒绝请求.

为TA充电
共{{data.count}}人
人已赞赏
前端

写给前端的跨平台方案、跨端引擎的本质

2021-5-28 23:41:21

前端

鼠标一键点击实现页面文本全选和复制

2021-5-29 17:49:51

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索