在Groovy / Grails中不安全地使用用户提供的GString:s

时间:2009-03-22 19:39:25

标签: security grails groovy gstring

Groovy中的GString概念非常强大(参见http://groovy.codehaus.org/Strings+and+GString)。

GStrings让你做的事情如下:

world = "World"
println "Hello ${world}"
# Output: Hello World
println "1+2 = ${1+2}"
# Output: 1+2 = 3
println "${System.exit(-1)}"
# Program terminated

我正在试图弄清楚是否使用Groovy GString:s会在您的代码中引入类似于SQL注入攻击的安全问题。

在上面的示例中,代码是由程序的作者编写的,因此System.exit(-1)命令的执行不能被视为安全漏洞,因为它是作者声明的意图。

假设我正在编写一个Grails网络应用程序,其中用户输入来自表单字段(读取POST / GET参数)和数据库表(使用GORM)。让我们假设一个攻击者控制发送给服务器的POST / GET请求和数据库中的内容。

我的应用中的代码如下所示:

def str1 = params.someParameterControlledByTheAttacker
def str2 = SomeGORMPersistedObject.get(1).somePropertyFieldControlledByTheAttacker
render "Hello! Here is some text: ${str1} and ${str2}"

攻击者有没有办法在上面的场景中执行代码?为什么?为什么不?我最初的假设是GString的使用总是安全的。请随意证明我的错。请尽量具体。

更新#1:为了保持讨论重点,请忽略代码中的任何HTML-XSS问题,因为这个问题是关于服务器端的代码执行,而不是客户端的代码执行

更新#2:有些人指出“过滤掉不需要的字符串通常是个好主意”。虽然过滤掉“可能不好的字符”可能会让您免于某些类别的安全问题,但编写即使没有过滤也安全的代码会更好。您可以将它与Java JDBC API中PreparedStatements的使用进行比较 - 正确使用PreparedStatements 保证可以避免某些类型的注入攻击。过滤SQL输入可能会给你相同的结果,但使用PreparedStatements严格控制过滤方法恕我直言。

5 个答案:

答案 0 :(得分:3)

不,你不会有GString机制引入的任何 new 问题,因为GStrings的形成是一个“编译时”现象。虽然可以在运行时确定(和更改)它们的值,但表单不是。

另一种看待它的方式:你可以用GStrings做的任何事情都可以通过闭包和字符串连接来完成,语义完全相同; GStrings只是语法糖。除非你担心闭包(或者,天堂禁止,字符串连接)你不应该担心GStrings。

答案 1 :(得分:0)

使用给定的代码示例,没有安全问题。 str1和str2只调用了它们的toString方法,并且在GStrings上没有带有默认toString方法的安全漏洞。

除非您(程序作者)已经为“somePropertyFieldControlledByTheAttacker”定义了getter,以实际对值的内容进行评估,否则它是安全的。

安全漏洞发生的唯一方法是程序作者添加一个。

答案 2 :(得分:0)

第二个想法,看起来你的使用很好,因为你只是将你定义的局部变量作为一个变量,但字符串仍然需要擦除特殊字符,但不是像“System.exit(-1)之类的东西)“因为除非$ {}在字符串中,否则它将整个过程视为一个字符串。

最好的做法是从字符串中删除所有特殊字符,例如“$ {}”,因为您不必在代码中使用它们容易受到影响。 < / p>

但是,如果它永远不会以嵌套的方式篡改字符串,那你就没事了,所以我不是百分百肯定。

答案 3 :(得分:0)

我很确定以params(在Controller中)传入的对象是纯字符串,因此它们不会在运行时得到评估(如GStrings那样)。此外,我做了一些实验,似乎要把它们变成GStrings,你需要做一些非常粗糙的工作。这是可行的,但需要大量的杂耍。

简而言之,它可能不是一个安全漏洞。

剥离特殊字符仍然是一个真正的,非常好的主意,至少在不需要它们的字符串中......尽管确定这是“留给读者的练习”。但只要您意识到所有用户生成的数据(从网络或数据库中提取的数据)都是可疑的,您就会更加安全。

答案 4 :(得分:0)

您可能在上面的代码中有一个跨站点脚本漏洞 - 确保您调用.encodeAsHTML(),或者坏人可能会惹麻烦。