地址栏参数防篡改

1,236 阅读1分钟

需求

假如一个详情页的地址栏有一个商品id,但是又不想用户通过更改id来看其他商品详情。

方案设计

  1. 在商品列表页获取列表数据时提供活动id对应的签名,活动id和签名一一对应,生成签名使用md 如sign=MD5(id${id}sk${secretKey}),secretKey是密钥;
  2. 在跳转至详情页时将签名带上,如:details?id=123&sign=xxx;
  3. 在请求活动详情时带上id和sign(签名);
  4. node层通过id和密钥重新生成签名,重新生成的签名和请求接口时的签名对比,如果一致则表示活动id没有被篡改。

代码实现(部分)

// 判断id是否修改中间件
import { Context } from "koa";
import { KoaMiddlewareInterface, Middleware } from "routing-controllers";
import * as MD5 from 'md5'
import getApolloConfig from '@xxx/apollo'// 引入阿波罗配置

@Middleware({ type: "before" })
export default class IdCheckMiddleware implements KoaMiddlewareInterface {
  async use(context: Context, next: (err?: any) => Promise<any>,): Promise<any> {
    const config = getApolloConfig()
    // 是否严格模式下的id(是否需要校验id签名)  '0'不需要  '1'需要
    const strictId = config['strictId']
    // 这样可以通过阿波罗配置来即时控制是否需要校验签名
    if (strictId === '0') {
      return next()
    }
    // 生成md5签名的密钥
    const secretKey = config['idSecretKey']
    // id和sign通过header传过来(其他传参方法也一样)
    const id = context.request.header["id"] || ''
    // 再次生成签名
    const nodeSign = MD5(`id${id}sk${secretKey}`)
    // 客户端传来的签名
    const sign = context.request.header["sign"] || ''
    if (nodeSign !== sign) {
      context.body = {
        code: 3, 
        error: ['非法的id'],
      };
    } else {
      return next()
    }
  }
}