我有一个数字列表,并希望为我的用户提供输入printf样式格式字符串的选项,以指定数字的输出方式。
如何根据参数列表验证用户提供的格式字符串?格式错误的输入不应该使程序崩溃,我想避免任何格式字符串攻击。
我不关心验证是否仅处理POSIX或编译器特定超集中指定的格式选项。是否有任何图书馆电话要求,或者我必须自己写吗?
澄清: 我需要的是这样的事情:
float var1, var2, var3, var4;
// var1 .. var2 are given by the program
const char * userSupplied = getFormatStringFromUser();
if( isValidFormat( userSupplied, "float", "float", "float", "float" ) )
printf( userSupplied, var1, var2, var3, var4 );
else
printf( "The format you gave was invalid!\n" );
在这个例子中,我知道我有四个花车。 我想允许任何只引用0到4个浮点数的格式。
因此 isValidFormat()应允许以下格式字符串:
虽然应拒绝以下内容:
答案 0 :(得分:1)
不要将用户输入的字符串传递给printf
。 printf
的格式字符串接口是为代码而设计的,不是为人类输入而设计的。你会发现如果你只是制作自己的格式字符串规范,你就可以自由地为用户设计它。
您是否有理由对用户强制使用完全混淆的printf
格式字符串规范?
基本上,您正在请求帮助编写内容以将格式字符串规范转换为printf
格式字符串规范。我建议你从用户键入的构造 printf
格式字符串中编写代码。这样更安全,并为您提供更大的灵活性。即使它的代码更多,也不那么苛刻。
答案 1 :(得分:1)
为你编写代码太多了,但我会给你一个很好的方法。为您需要支持的每种类型设计有效格式说明符的正则表达式,然后使用它们为整个格式字符串构造一个更大的正则表达式,并查看它是否匹配。例如,浮点(double
)参数的正则表达式看起来像:
%[+- 0#]*[0-9]*([.][0-9]+)?[aefgAEFG]
可以出现在格式说明符之间的文字文本的正则表达式如下所示:
([^%]|%%)*
确保在匹配格式字符串时,您坚持整个字符串与正则表达式匹配(在末尾使用^
和$
锚点)而不仅仅是子字符串。
答案 2 :(得分:0)
没有标准(POSIX或C)方式,我知道没有提供此功能的库。因此,您必须自己编写或搜索比我更好的搜索。请注意,您只需要检查对您有用的那些。
答案 3 :(得分:0)
如果您有预定义的输入参数,请使用switch case。
switch ( <variable> ) {
case accetable-value_1:
Code to execute if <variable> == accetable-value_1
break;
case accetable-value_2:
Code to execute if <variable> == accetable-value_2
break;
...
default:
error: This is not a valid value, please enter a valid value
break;
}
答案 4 :(得分:0)
在RRDtool中,我使用这样的代码来检查各种格式模式。
#include <glib.h>
static int bad_format_check(const char *pattern, char *fmt) {
GError *gerr = NULL;
GRegex *re = g_regex_new(pattern, G_REGEX_EXTENDED, 0, &gerr);
GMatchInfo *mi;
if (gerr != NULL) {
// rrd_set_error("cannot compile regular expression: %s (%s)", gerr->message,pattern);
return 1;
}
int m = g_regex_match(re, fmt, 0, &mi);
g_match_info_free (mi);
g_regex_unref(re);
if (!m) {
// rrd_set_error("invalid format string '%s' (should match '%s')",fmt,pattern);
return 1;
}
return 0;
}
#define SAFE_STRING "(?:[^%]+|%%)*"
int bad_format_imginfo(char *fmt){
return bad_format_check("^" SAFE_STRING "%s" SAFE_STRING "%lu" SAFE_STRING "%lu" SAFE_STRING "$",fmt);
}
#define FLOAT_STRING "%[-+ 0#]?[0-9]*(?:[.][0-9]+)?l[eEfF]"
int bad_format_axis(char *fmt){
return bad_format_check("^" SAFE_STRING FLOAT_STRING SAFE_STRING "$",fmt);
}
int bad_format_print(char *fmt){
return bad_format_check("^" SAFE_STRING FLOAT_STRING SAFE_STRING "%s" SAFE_STRING "$",fmt);
}
答案 5 :(得分:-2)
最简单的方法是使用sprintf(而不是printf)来计算字符串中的结果,并测试sprintf返回的错误代码。