Fortify 不信任 Java System 属性

问题描述

我正在尝试使用 #include <string.h> #include <stdio.h> void swap(char *x,char *y) { char temp; temp = *x; *x = *y; *y = temp; } void permute(char *a,int i,int n,int *count) { int j; if( i == n ){ printf("%s\n",a); *count += 1; } else { for( j = i; j <= n; j += 1 ){ swap(a + i,a + j); permute(a,i + 1,n,count); swap((a + i),(a + j)); } } } int main(int argc,char **argv) { char buf[1024]; char *str = argc > 1 ? argv[1] : buf; int len; int contador = 0; if( argc < 2 ){ printf("\nType a word: "); scanf("%1023s",buf); } len = strlen(str); permute(str,len - 1,&contador); printf("\nNumber of words: %d\n",contador); return 0; } 分叉一个进程:

ProcessBuilder

Fortify 报告了一个命令注入漏洞,因为 String classpath = System.getProperty("java.class.path"); String[] javaCmd = {"java","-cp",classpath,...}; ProcessBuilder builder = new ProcessBuilder(); // ... builder.command(javaCmd) // ... 是“从不受信任的数据构建的”。 Fortify 是正确的,因为系统属性是可变的:javaCmd 这使得在运行系统命令时使用它们很危险。

我找不到 System.setproperty() 的替代品,我想知道是否有人有想法?

谢谢

解决方法

整个命令是一个巨大的步行漏洞。或不。安全不是非黑即白。它是灰色的阴影。这段代码不是完全白色,而是浅灰色(即:它为攻击者提供了一些路由,但这些路由在正确配置的系统上通常不可用,并且“进入”的少数方法通常被视为更可怕和直接路由,这使得开放的攻击面大多没有实际意义)。

TL;DR:警告是愚蠢的,告诉 fortify 忽略这个,此外,您的安全流程可能需要更新。此外,这段代码很可能不会真正做你想做的事。不幸的是,没有简单的方法来编写可以做你想做的事情的代码。为成为坏消息的传播者而道歉。

再详细一点:

特别是,“我将通过不完全遵循一般分析来处理每一个强化警告,而只是通过写出我能想到的最接近的东西来摆脱它”是一种很好的思考方式编写了安全代码而没有实际这样做。

您必须了解 Fortify 的驱动力。然后,您必须弄清楚攻击面实际上是什么,或者不接受这个(因此更改/删除暴露它的所有代码),或者接受它,并记录此攻击面无关紧要。在这种情况下,第二个选项(接受、记录并继续)听起来几乎适用于所有可以想象的场景。

在这个特定实例中,您编写的代码有 2 个不同的攻击面:

磁盘访问导致被盗

您正在运行 java。就这样。相对路径。您不知道将运行什么 java,并且您绝对无法保证它与您当前的 JVM 来自同一个 java。它很容易成为恶意脚本。这将要求攻击者找到一种方法将该脚本放在路径上的文件夹中。对于非 root 用户,. 通常在路径上,并且首先在路径上,所以如果这是例如服务器和攻击者可以设法使服务器将文件保存在自己的目录中,boom。你去吧。您的服务器现已遭到入侵。

那个 fortify 没有警告这是错误的;一般来说,相对路径只是一个坏主意,如果不是出于安全原因,那么出于稳定性原因:这不会在很多很多服务器上工作。不幸的是,基本上不可能以独立于平台和部署的方式从第一个 JVM 可靠地调用第二个 JVM。这就是为什么真正的解决方案通常是直接避免它,或者设置明确的操作系统绑定脚本来处理这个问题(然后使用绝对路径运行脚本)。

危害系统属性

是的,如果 Sonme 攻击者设法诱使您的 JVM 运行 System.setProperty("java.class.path"),那么他们可以危及您的机器。 但这完全是荒谬的。您应该立即忘记这个攻击面,因为它的长度为零。

您运行 System.setProperty(untrustedUserInput,someOtherUntrustedUserInput); 的可能性有多大?继续,搜索您的代码库。它......不太可能在那里。某些攻击者可能会强迫您的服务器运行它想要的任何字节码(这将需要一个开放的安全漏洞,例如具有缓冲区溢出或其他内容的 PNG 解析器;这意味着它要么是攻击者0 天,或者您确保及时修补服务器的流程被破坏,在这种情况下,您会遇到更大的问题)。如果攻击者可以做到这一点,他们就可以设置该属性,是的。

他们也可以随心所欲地直接ProcessBuilder,因此,这一点完全没有实际意义。您将注意力集中在巨山旁边的岩石上,并将其定为陆地上的最高点。

因此,总结一下:在这种情况下,强化警告是愚蠢的,应该完全忽略。然而,这段代码IS肯定会打开一些攻击面;不过也不是特别大。特别是,如果没有人可以登录此框或写入运行此 JVM 进程的用户的目录(当然他们不应该这样做,或者编辑路径!) - 你很好。如果情况并非如此,您就会遇到更大的问题。

这就是安全性的工作原理:您将这些内容写下来,并在整个过程中不断审查(不仅仅是代码、文档、检查,每两年与系统管理员进行一次访谈以检查他们是否阅读了文档,并且遵循指令)。您无法关闭所有攻击面。您只需提高对它们的认识并确保它们不会被滥用。

我不认为有一种创造性的方法可以让 fortify 关闭(也许通过反射调用 processbuilder,fortify 可能不会弄清楚),但它所做的只是降低安全性.这里唯一正确的解决方案是完全放弃强化(这可能有点激烈),或者使用它应该如何使用它:将它发现的地方作为一个非详尽代码列表分析。不是“这是我需要修复的内容列表,然后我的代码是安全的”。这种分析应该足够了,因此,贴上适当的注释或评论或任何需要告诉 fortify 您已手动接受该分析并且它不应再告诉您有关它的信息。

真正的解决方案

不要这样做。在所有。尝试找到一种方法来做任何需要做的事情,而根本不需要调用新的 JVM。如果这不在桌面上,请重新定义它的工作方式:与其“使用与此 VM 相同的类路径克隆此 VM”,不如考虑“运行一个不一定是此 VM 的克隆的新 VM,因为我启动的实际 JVM 可能与该 VM 所驱动的可执行文件不同,并且类路径是显式配置的,或者至少在其他地方配置。换句话说,如果必须,请记录此服务器的正确设置需要在特定位置创建脚本,并适当配置访问权限,以使用特定类路径启动 JVM。