2011-09-15 45 views
4

我使用String.format方法的Java API来记录东西。我的方法是这样的:Java安全String.format和转义%

public static void log(String message, Object... params){ 
    System.out.println(String.format(message, params)); 
} 

但问题是,如果用户发送带有%性格介于它的消息,它会抛出异常。这里有一个场景:

log("SELECT * FROM my WHERE name like '%six%'"); 

和Java寻找东西来取代%s(没关系)和%'(糟糕)。我想解决这个问题。因为那里没有params%s将会丢失,%'会导致异常。

一个解决方案可以是message.replace("%", "%%")但我不确定它是否是一个优雅的解决方案。

+1

我不明白为什么'%s'将是确定的,如果''%是没有的。如果他们给你破碎的输入,他们不能指望工作输出。只是抛出一个异常。 –

+0

@Christoffer我没有看到包含SQL'like'子句的消息字符串作为中断输入。 – adarshr

+1

如果字符串同时包含'%s'和'%',并且一个被认为是OK而另一个不是,那么输入被破坏。如果输入是'String.format()'的格式字符串,并且您不希望'like'语句中的'%s'被参数值替换,则除'%% s'和'% %'在输入中断。 –

回答

7

log不知道给定%是否意味着作为格式说明符或百分号。请看下面的例子:

log("%s%s", "test"); 

那是"test%s""%stest",或错误?

因此,这个问题将在调用点加以解决:

log(escape("SELECT * FROM my WHERE name like '%six%'")); 

其中escape()是你需要编写将与%%替换所有%功能。

或者,下面就可以在调用点使用:

log("%s", "SELECT * FROM my WHERE name like '%six%'"); 
+0

或者,可以从'log()'方法内调用'escape()'方法,使得操作无缝。 – adarshr

+1

@adarshr:那么使用'String.format()'有什么意义? –

+0

我使用了最后一种情况,现在我的SQL被记录为'log(“%s”,query);'。谢谢。 –

1

为最有可能的误用一个简单的解决方案(使用%s%某处String,但不提供参数)将除你原来的方法提供了一种无PARAMS超载你的方法

public static void log(String message) { 
    System.out.println(message); 
} 

另外,您可以动态地尝试检测无PARAMS情况,但是这是一个有点更多的工作:

public static void log(String message, Object... params) { 
    final String output; 
    if (params == null || params.length = 0) { 
    output = message; 
    } else { 
    output = String.format(message, params); 
    } 
    System.out.println(output); 
} 
+0

如果客户端利用格式化功能并执行诸如'%n'之类的操作,则不起作用。 – aioobe

+0

上述两种方法是不明确的,因为第一种方法(使用var args)也会采用长度为0的参数列表。 –

+0

@aioobe:true,它需要记录,但我没有看到真正的理由在这里使用'%n'而不是'\ n'。 –

0

一种选择w ^应该将字符串直接传递给println,如果params的长度为0. 另一种选择是有两个重载。

public static void log(String message); 
public static void log(String format, String param, String...params); 
+1

我不认为固定的'参数'是必要的。另外:格式参数可以是'Object',所以'log'也应该接受'Object'。 –

+0

但是您是否觉得它提供了更多的可读性,因为在无参数情况下调用哪个超载没有潜在的困惑? –

+2

这是真的,它更明显,但它有缺点。例如,如果由于某种原因,我已经有*数组(可能是因为调用方法本身就是一个变量arity方法):那么你必须复制数组来调用'log'方法。 –