赞
踩
说明: 保证数据唯一性 不允许有重复的
为什么需要实现幂等性:
在接口调用时一般情况下都能正常返回信息不会重复提交,不过在遇见以下情况时可以就会出现问题,如:
使用幂等性最大的优势在于使接口保证任何幂等性操作,免去因重试等造成系统产生的未知的问题。
实现方式:
说明: API参数篡改就是恶意人通过抓包的方式获取到请求的接口的参数,通过修改相关的参数,达到欺骗服务器的目的,常用的防止篡改的方式是用签名以及加密的方式。
防御方式:
说明: 就是把之前窃听到的数据原封不动的被重放或多次重放。
防御方式:
防止重放攻击必须要保证请求仅一次有效
需要通过在请求体中携带当前请求的唯一标识,并且进行签名防止被篡改。
所以防止重放攻击需要建立在防止签名被串改的基础之上
微信支付的接口就是这样做的
timestamp的作用
每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数一起进行数字签名。HTTP请求从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间相比较,是否超过了60s,如果超过了则认为是非法的请求。一般情况下,从抓包重放请求耗时远远超过了60s,所以此时请求中的timestamp参数已经失效了,如果修改timestamp参数为当前的时间戳,则signature参数对应的数字签名就会失效,因为不知道签名秘钥,没有办法生成新的数字签名。
但这种方式的漏洞也是显而易见的,如果在60s之后进行重放攻击,那就没办法了,所以这种方式不能保证请求仅一次有效
nonce的作用
nonce的意思是仅一次有效的随机字符串,要求每次请求时,该参数要保证不同。我们将每次请求的nonce参数存储到一个“集合”中,每次处理HTTP请求时,首先判断该请求的nonce参数是否在该“集合”中,如果存在则认为是非法请求。nonce参数在首次请求时,已经被存储到了服务器上的“集合”中,再次发送请求会被识别并拒绝。
nonce参数作为数字签名的一部分,是无法篡改的,因为不知道签名秘钥,没有办法生成新的数字签名。
这种方式也有很大的问题,那就是存储nonce参数的“集合”会越来越大。
nonce的一次性可以解决timestamp参数60s(防止重放攻击)的问题,timestamp可以解决nonce参数“集合”越来越大的问题。
说明: 案例:截获用户登录请求,截获到账号、密码等
防御方式: 参数进行加密传输
如果为了保证更加的安全,可以加上RSA,RSA2,AES等等加密方式,保证了数据的更加的安全,但是唯一的缺点是加密与解密比较耗费CPU的资源.
说明: SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库。
比如
public interface UserMapper {
@Select(" SELECT * FROM user_info where userName=#{userName} and password=${password}")
public UserEntity login(UserEntity userEntity);
}
假设password=“1; drop table user_info”,那就会删掉表了。
防御方式:
说明: JS脚本注入 获取用户信息(token等等)
防御方式: 使用特殊字符转换的方式 +过滤器拦截处理
说明: 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
简单的说,就是利用浏览器对用户的信任,比如,用户已经登录了ww.aaa.com,自然aaa这个网站就会将用户的登录状态session存在cookie中; 然后,aaa.com这个网页有一个对作品点赞的功能,点赞提交地址为 aaa.com/api.like?id=777; 这时,另外一个叫www.bbb.com的网站,放了这样一个元素 <imgsrc=“aaa.com/api.like?id=888”>,我们知道,请求静态资源用的是get方法,这样的话,一旦用户进入这个bbb.com页面,就会请求aaa.com这个网站的点赞接口,而且点赞的用户对象是888; 最后因为用户的登录信息尚未过期,那就等于给id为888这个作品点赞了,然而,用户并不知情。
防御方式:
说明: 比如A网站有一张图片,被B网站直接通过img标签属性引入,直接盗用A网站图片展示。
如果别人的项目频繁引用我的图片的话 别人请求放访问的是我的 服务器 也会浪费我的宽带。
防御方式: 判断http请求头Referer域中的记录来源的值,如果和当前访问的域名不一致的情况下,说明该图片可能被其他服务器盗用。 Referer字段中记录了访问的来源(浏览器访问链接地址),相当于限制资源(图片、文字) 只能在某个域名(限制某个服务器)来源进行访问。
说明: 例如 上传木马文件 删除某个文件 (jsp exe bat)
上传文件漏洞原理: jsp里面有操作文件的代码 我上传后 然后访问这个jsp 在tomcat环境下 执行这个文件 执行了 就完蛋了。 用第三方工具类去判断流
防御方式:
方式一: 在上传文件时候 一定要使用判断文件流的方式 确定是图片 不要判断后缀方式获取图片
方式二: 静态资源与动态资源分开服务器 Nginx+Tomcat实现 动静分离 Nginx存放静态资源 没有tomcat环境
方式三: 服务器硬盘上不能做删除操作
方式四: 权限设置 对于目录的操作权限没有
方式五: 前端做后缀限制
方式六:服务器上不要有热部署功能。如果我上传class文件。 Java程序就能获取到了。限制 jsp exe 等可执行程序。
说明: DoS是Denial of Service的简称,即拒绝服务,造成DoS的攻击行为被称为DoS攻击,其目的是使计算机或网络无法提供正常的服务。最常见的DoS攻击有计算机网络带宽攻击和连通性攻击。
DoS攻击是指故意的攻击网络协议实现的缺陷或直接通过野蛮手段残忍地耗尽被攻击对象的资源,目的是让目标计算机或网络无法提供正常的服务或资源访问,使目标系统服务系统停止响应甚至崩溃,而在此攻击中并不包括侵入目标服务器或目标网络设备。这些服务资源包括网络带宽,文件系统空间容量,开放的进程或者允许的连接。这种攻击会导致资源的匮乏,无论计算机的处理速度多快、内存容量多大、网络带宽的速度多快都无法避免这种攻击带来的后果
防御方式: 解决这个问题就要用到高防服务器,如果租用高防服务器的话,它的防御能力、访问速度、稳定与否都是首要考虑因素
直接异常信息,会给攻击者以提示。 可以使用mvc中的工具,把错误码异常等进行封装
HTML注释, 会暴露功能,方便攻击。 上线时去除注释
文件上传, 如果本身功能就是上传文件去执行,那么就有可能执行非常危险的命令。 解决方式是,设置文件白名单,限制文件类型,另外还可以重新命名文件,改名为不可执行的
路径遍历, 使用相对路径来遍历未开放的目录。 方式是将JS,CSS部署在独立的服务器,使用独立域名。 其他文件不使用静态URL访问,动态参数不包含文件路径信息。
注意:所有的安全措施都用上的话有时候难免太过复杂,在实际项目中需要根据自身情况作出裁剪,比如可以只使用签名机制就可以保证信息不会被篡改,或者定向提供服务的时候只用Token机制就可以了。如何裁剪,全看项目实际情况和对接口安全性的要求。
攻击与防御一直是对立存在的两面,有新的攻击方式就会有更好的防护方法!在计算机网络方面两者更是通过长期竞争实现共同的进步;任何系统都不是完美的,既然我们不能开发出绝对安全的系统,那我们就要时刻防范各种可能的攻击。出现漏洞及时修复,这样才能保证我们系统的安全与稳定!
主要防御措施可以归纳为两点:
public class SignAuthInterceptor implements HandlerInterceptor { private RedisTemplate<String, String> redisTemplate; private String key; public SignAuthInterceptor(RedisTemplate<String, String> redisTemplate, String key) { this.redisTemplate = redisTemplate; this.key = key; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取时间戳 String timestamp = request.getHeader("timestamp"); // 获取随机字符串 String nonceStr = request.getHeader("nonceStr"); // 获取签名 String signature = request.getHeader("signature"); // 判断时间是否大于xx秒(防止重放攻击) long NONCE_STR_TIMEOUT_SECONDS = 60L; if (StrUtil.isEmpty(timestamp) || DateUtil.between(DateUtil.date(Long.parseLong(timestamp) * 1000), DateUtil.date(), DateUnit.SECOND) > NONCE_STR_TIMEOUT_SECONDS) { throw new BusinessException("invalid timestamp"); } // 判断该用户的nonceStr参数是否已经在redis中(防止短时间内的重放攻击) Boolean haveNonceStr = redisTemplate.hasKey(nonceStr); if (StrUtil.isEmpty(nonceStr) || Objects.isNull(haveNonceStr) || haveNonceStr) { throw new BusinessException("invalid nonceStr"); } // 对请求头参数进行签名 if (StrUtil.isEmpty(signature) || !Objects.equals(signature, this.signature(timestamp, nonceStr, request))) { throw new BusinessException("invalid signature"); } // 将本次用户请求的nonceStr参数存到redis中设置xx秒后自动删除 redisTemplate.opsForValue().set(nonceStr, nonceStr, NONCE_STR_TIMEOUT_SECONDS, TimeUnit.SECONDS); return true; } private String signature(String timestamp, String nonceStr, HttpServletRequest request) throws UnsupportedEncodingException { Map<String, Object> params = new HashMap<>(16); Enumeration<String> enumeration = request.getParameterNames(); if (enumeration.hasMoreElements()) { String name = enumeration.nextElement(); String value = request.getParameter(name); params.put(name, URLEncoder.encode(value, CommonConstants.UTF_8)); } String qs = String.format("%s×tamp=%s&nonceStr=%s&key=%s", this.sortQueryParamString(params), timestamp, nonceStr, key); log.info("qs:{}", qs); String sign = SecureUtil.md5(qs).toLowerCase(); log.info("sign:{}", sign); return sign; } /** * 按照字母顺序进行升序排序 * * @param params 请求参数 。注意请求参数中不能包含key * @return 排序后结果 */ private String sortQueryParamString(Map<String, Object> params) { List<String> listKeys = Lists.newArrayList(params.keySet()); Collections.sort(listKeys); StrBuilder content = StrBuilder.create(); for (String param : listKeys) { content.append(param).append("=").append(params.get(param).toString()).append("&"); } if (content.length() > 0) { return content.subString(0, content.length() - 1); } return content.toString(); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。