雨翔河
首页
列表
关于
代码漏洞和风险
2020-03-19 12:31
> 这几天在检查各个老项目的代码情况,本来是准备CodeReview用的,没想到越看越多的问题,一发不可收拾。。。 #### 1. 随机数问题 可以参考: https://stackoverflow.com/questions/11051205/difference-between-java-util-random-and-java-security-securerandom `Random` 和 `SecureRandom` 的区别,这个知道的应该比较多,重要的情况下,随机函数的使用要尽量使用 `SecureRandom` #### 2. 填充式加密 ``` Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv = new IvParameterSpec("********".getBytes()); ``` 我们系统的这种加密的填充方式居然是存在漏洞的。 使用pkcs5填充的CBC的这种特定模式很容易受到填充oracle攻击,虽然我也不是很懂填充oracle攻击,但是看百度的描述是可以根据有效填充和无效填充的明文差异来进行解密. 可以参考: https://www.freebuf.com/articles/database/151167.html ``` Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); c.init(Cipher.ENCRYPT_MODE, k, iv); byte[] cipherText = c.doFinal(plainText); ``` #### 3.加密方式 密文的加密: 应该使用GCM,而不应该使用 ECB ,因为ECB的输入和输出是一样的值,这很容易被重放破解 ``` Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); c.init(Cipher.ENCRYPT_MODE, k, iv); byte[] cipherText = c.doFinal(plainText); ``` 解决: ``` Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); c.init(Cipher.ENCRYPT_MODE, k, iv); byte[] cipherText = c.doFinal(plainText); ``` 另外: 产生的密文很容易被敌手篡改。这意味着密码无法检测数据是否被篡改。如果密文可以被攻击者控制,它可以在不被发现的情况下被改变。 解决方案是使用包含基于哈希的消息验证码(HMAC)的密码对数据进行签名。将HMAC函数与现有密码组合在一起很容易出现错误。具体来说,先验证HMAC,并且只有在数据未被修改的情况下,才能对数据执行任何密码函数。 以下模式是脆弱的,因为他们不提供一个HMAC: - CBC - OFB - CTR - ECB GCM模式将HMAC放进加密结果数据里面去,从而提供结果的完整性。 #### 4.散列值对比漏洞 由于比较时间的暴露,攻击者可能能够检测到秘密散列的值。当调用array .equals()或String.equals()函数时,如果匹配的字节较少,它们将提前退出,这就意味着执行时间更短,返回更快,同样,匹配位数多的话返回时间更长。 ``` String secretMd5 = request.getSecretMd5(); String boxSecretMd5 = MD5.MD5Encode(boxSecret + ""); if (!boxSecretMd5.equals(secretMd5)) { logger.info("{}上报私钥不正确:{}", xxx, secretMd5); builder.setResultCode(xxxEnum.PARAMETER_ILLEGAL.getCode()); builder.setResultMsg(xxxEnum.PARAMETER_ILLEGAL.getMsg()); return builder.build(); } ``` 这种情况虽然要做到攻击成功很麻烦,因为受影响的因素很多,但是在数据量大的情况下,一步步的距离真实密码会越来越近,直到最后使用暴力模式来破解攻破你的系统。 解决方案: ``` if(MessageDigest.isEqual(userInput.getBytes(),actualHash.getBytes())) { ... } ``` #### 5. 可能的XSS攻击 ``` response.getWriter().write(outJson); ``` 这里为什么要列出来是因为用户的输入的时候返回回去,很容易出现在没有过滤用户输入的数据的时候,直接输出给用户,如果内容里面携带恶意脚本,那就很容易出现问题。 #### 6.可能的CSRF ``` loger.error("公共请求头处理 error:" + request.getRequestURI(), e); ``` 在日志打印的时候我们经常把用户的一些行为信息直接放入到日志里,当这种日志被收集起来或者在shell里不小心点到了的时候,就很容易引发问题,因为如果内容本身是个删除链接或者什么针对系统的恶意链接什么的。 #### 7. 用户文件随意读取写入漏洞 ``` @GET @Path("/images/{image}") @Produces("images/*") public Response getImage(@javax.ws.rs.PathParam("image") String image) { File file = new File("resources/images/", image); //Weak point if (!file.exists()) { return Response.status(Status.NOT_FOUND).build(); } return Response.ok().entity(new FileInputStream(file)).build(); } ``` 打开一个文件来读取它的内容。文件名来自输入参数。如果将未经过滤的参数传递到此文件API,则可以读取来自任意文件系统位置的文件。 解决: ``` File file = new File("resources/images/", FilenameUtils.getName(image)); ``` #### 8. 正则表达式的redos攻击,这个很严重。 ``` ^(-?)[0-9]+(.[0-9]+)?$ ``` 如果构造一个数据,数据为 ``` -12312312312312321123123123211212312312312312312312312312....12312312321 ``` 在这个构造数据的末尾加上一个英文字母,能直接让正则表达式的执行引擎在匹配的时候CPU飙升,原理就不做多解释了,百度下redos就明白了,如果多线程一起发起请求的话,可以很容易直接让服务器宕机,不信邪的话可以试试。 项目内类似代码的: ``` public static boolean isStrictNumber(String numberStr) { if (null == numberStr || "".equals(numberStr)) { return false; } return numberStr.matches("^(-?)[0-9]+(.[0-9]+)?$"); } ``` #### 9. xxe攻击 XML External Entity (XXE) ``` DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); doc = (Document) builder.parse(is); ``` 比如通过在xml里面加入包含引用文件,恶意的让服务器在处理这个xml的时候去读取该包含文件。 解决方案: ``` DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(input); ``` 注:如果我记得没错的话,微信支付曾经吃过这个的大亏。 #### 10. 密方法的初始化向量数组问题 ``` public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes); ``` 加密方法的初始化向量数组应该是高度随机的,而不应该是0 解决: ``` byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); ``` #### 11. session的设置要使用经过验证处理的值,不要信任用户的输入值。 ``` public void doSomething(HttpServletRequest req, String activateProperty) { //.. req.getSession().setAttribute(activateProperty,"true"); } ``` #### 12. sql注入,老生常谈 ``` PreparedStatement countStmt = null; ResultSet rs = null; try { countStmt = connection.prepareStatement(count_sql); } ``` 解决: ``` onnection conn = [...]; conn.prepareStatement("update XXXX set SALES = ? where COF_NAME = ?"); updateSales.setInt(1, nbSales); updateSales.setString(2, coffeeName); ``` #### 13. 利用公司的网站链接来做钓鱼 某恶意用户发了一个链接: ` http://website.com/login?redirect=http://xxxx.xxx.com/xxxx/login ` A用户看到了这个链接点击访问以为是website的链接,实际上因为他没有鉴权,被服务器重定向到了 `http://xxxx.xxx.com/xxxx/login ` A用户访问了之后输入各种卡等信息被骗。 导致website公司连带责任。 代码: ``` protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.sendRedirect(req.getParameter("redirectUrl")); } ``` ModelView等重定向的写法也类似容易犯这种问题。 #### 14. HTTP Response Splitting 攻击 依然是这种完全信任用户传来的值导致的。 ``` String redUrl = url + "?appid=" + appId + "&redirect_uri=" + redirectClientGetUrl + "_" + timestamp + "&response_type=" + responseType + "&scope=" + scope + "&state=" + platFrom + "#wechat_redirect"; response.sendRedirect(redUrl); ``` ##### 代码就先查看到这里吧,下班下班,明天下午的CR补充材料就这个了。
类型:工作
标签:sql,漏洞,安全
Copyright © 雨翔河
我与我周旋久
独孤影
开源实验室