Otimização de segurança
De Benpian começou a falar sobre o sistema de otimização de segurança espiga. Dividido em três campos:
- endereço de interface de pico escondido
- código de verificação fórmula matemática
- Anti-limitante escova interface
endereço de interface de pico escondido
botão de Spike-per-click irá gerar um endereço de pico, antes do pico não sabe o endereço. Não escreva os mortos, é obtido a partir do servidor, endereço mosaico dinâmico. (Protocolo HTTP é transmitida em claro, transparente, e não pode controlar a extremidade dianteira de um usuário mal-intencionado ataque) ou para verificar a segurança no lado do serviço, proibir off estes serviços maliciosos.
Esta operação: Para evitar que o caso pode ser, depois de um login de usuário malicioso, Token adquirido através de pico contínua chamando endereço da interface, para alcançar escalpelamento solicitações maliciosas.
Url não é o mesmo de cada vez, apenas a do pico verdadeiro clicando no botão irá gerar um endereço de interface de pico id correspondente, de acordo com a mercadoria e os usuários.
No entanto, isso ainda não resolve o botão Wizard ou usando o robô Clique no botão com frequênciaOperação, a fim de reduzir o número de cliques no botão, e sob alta concorrência, impedir que vários usuários ao mesmo tempo, um grande número de solicitações e questões, alta concorrência acrescentando anti fórmula matemática otimizados códigos gráficos e afins.
Idéias: Antes de começar pico, vá buscar endereço pico interface do pedido.
processo:
- Pedido para / miaosah / path primeiro até o final frente do caminho quando o usuário clicar no "pico";
- Adicione o endereço geração de interface (/ miaosah / path) e UUID fundo ao gerar um valor aleatório, e os endereços reais pico MD5 criptografado e armazenado na chave de usuário id id / item e Redis pico endereços em pares (para verificação após usar, Redis conjunto válido de 60 anos, porque o salto página a espiga muito rapidamente);
- transformação do_miaosha da interface, trazer parâmetros PathVariable, interfaces de pico recepção do pedido, verificar se PathVariable e memória cache consistente, se tal for acordado antes de entrar no link pico.
MiaoshaController relacionados com alterações no código da seguinte forma:
//第四版,秒杀接口地址隐藏
@RequestMapping(value = "/{path}/do_miaosha", method = RequestMethod.POST)
@ResponseBody
public Result<Integer> miaosha(Model model, @RequestParam("goodsId") long goodsId, HttpServletResponse response,
@CookieValue(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String cookieToken,
@RequestParam(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String paramToken,
@PathVariable("path") String path) {
if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return Result.error(CodeMsg.SESSION_ERROR);//token不存在或失效
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
MiaoshaUser user = userService.getByToken(response, token);//从token中读用户信息
//验证path
boolean check = miaoshaService.checkPath(user, goodsId, path);
if (!check) {
return Result.error(CodeMsg.REQUEST_ILLEGAL);
}
//内存标记,减少redis访问
boolean over = localOverMap.get(goodsId);
if (over) {//库存减去10后不必要访问redis,访问map即可
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//预减库存
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
if (stock < 0) {
localOverMap.put(goodsId, true);
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
return Result.error(CodeMsg.REPEATE_MIAOSHA);
}
//入队
MiaoshaMessage mm = new MiaoshaMessage();
mm.setUser(user);
mm.setGoodsId(goodsId);
sender.sendMiaoshaMessage(mm);
return Result.success(0);//排队中
}
@RequestMapping(value = "/path", method = RequestMethod.GET)
@ResponseBody
public Result<String> getMiaoshaPath(HttpServletResponse response, @RequestParam("goodsId") long goodsId,
@CookieValue(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String cookieToken,
@RequestParam(value = MiaoshaUserService.COOKI_NAME_TOKEN,required = false) String paramToken) {
if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return Result.error(CodeMsg.SESSION_ERROR);//token不存在或失效
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
MiaoshaUser user = userService.getByToken(response, token);//从token中读用户信息
String path = miaoshaService.createMiaoshaPath(user, goodsId);
return Result.success(path);
}
Gerando um código de endereço pico códigos de endereço pico e verificação dos procedimentos a seguir:
public boolean checkPath(MiaoshaUser user, long goodsId, String path) {
if (user == null || path == null) {
return false;
}
String pathOld = redisService.get(MiaoshaKey.getMiaoshaPath, "" + user.getId() + "_" + goodsId, String.class);
return path.equals(pathOld);
}
public String createMiaoshaPath(MiaoshaUser user, long goodsId) {
if (user == null || goodsId <= 0) {
return null;
}
String str = MD5Util.md5(UUIDUtil.uuid() + "123456");
redisService.set(MiaoshaKey.getMiaoshaPath, "" + user.getId() + "_" + goodsId, str);
return str;
}