我正在通过编码慢慢学习和进步,所以我希望有人可以快速浏览一下这个功能并告诉我是否看起来我在正确的轨道上,我怎么能做得更好,或者我可能会让自己失败。我是C世界的新手,所以请放轻松我 - 但要坦率和诚实。
void test(char *username, char *password) {
printf("Checking password for %s - pw: %s\n",username,password);
char *query1 = "SELECT password FROM logins WHERE email = '";
char *query2 = "' LIMIT 1";
char *querystring = malloc(strlen(query1) + strlen(username) + strlen(query2) * sizeof(char));
strncpy(querystring,query1,strlen(query1));
strncat(querystring,username,strlen(username));
strncat(querystring,query2,strlen(query2));
printf("Query string: %s\n",querystring);
mysql_query(mysql_con,querystring);
MYSQL_RES *result = mysql_store_result(mysql_con);
int num_fields = mysql_num_fields(result);
int num_rows = mysql_num_rows(result);
if (num_rows != 0) {
MYSQL_ROW row;
printf("Query returned %i results with %i fields\n",num_rows,num_fields);
row = mysql_fetch_row(result);
printf("Password returned: %s\n",row[0]);
int comparison = strncmp(password, row[0], strlen(password));
if (comparison == 0) {
printf("Passwords match!\n");
} else {
printf("Passwords do NOT match!\n");
}
} else {
printf("No such user... Password is invalid");
}
free(querystring);
}
目前,它正在运作......输出:
Checking password for jhall@futuresouth.us - pw: 5f4dcc3b5aa765d61d8327deb882cf99
Query string: SELECT password FROM logins WHERE email = 'test@blah.com' LIMIT 1
Query returned 1 results with 1 fields
Password returned: 5f4dcc3b5aa765d61d8327deb882cf99
Passwords match!
呼叫:
test("test@blah.com","5f4dcc3b5aa765d61d8327deb882cf99");
我正在寻找关于如何更好地使用字符串的输入,或者如果我如何做到这一点有任何不可预见的问题。我在使用C语言中的数据结构方面非常陌生。
答案 0 :(得分:1)
使用strncpy(target, source, strlen(source))
可以保证target
中的字符串不会以空值终止。如果perchance malloc()
返回归零内存,那么它似乎可以正常工作,但是一旦malloc()
返回非归零内存(先前分配的内存),事情就会出错。
strncat()
的长度参数非常奇怪;它是当前(以null结尾)数据之后目标字符串中剩余的空间量。除了不使用以空字符结尾的字符串之外,您的用法不能防止缓冲区溢出。
strncat()
IMNSHO确实没有一个好的用例,strncpy()
很少有好的理由。如果你知道一切都有多大,你可以使用memmove()
(或memcpy()
)。如果您不知道一切都有多大,那么您不知道在没有截断的情况下进行复制是否安全。
你的malloc()
调用也有点奇怪:它没有为尾随空分配足够的空间,它只将三个项中的一个乘以sizeof(char)
,这是不一致的但是无害的。很多时候你会因为malloc()
的大小而缩短分配,但是当你没有逃脱时,所有的地狱都会破裂。像valgrind
这样的工具会报告滥用已分配的内存。
答案 1 :(得分:0)
Jonathan的回答解释了这部分代码的问题。
要解决此问题,您可以改为使用snprintf
:
size_t space_needed = strlen(query1) + strlen(username) + strlen(query2) + 1;
char *querystring = malloc(space_needed + 1);
if ( !query_string )
exit(EXIT_FAILURE);
snprintf(query_string, space_needed, "%s%s%s", query1, username, query2);
然后,即使你计算错误的长度,至少你没有得到缓冲区溢出。
为了避免代码重复,有一个非标准函数asprintf,你传递参数,它产生一个指向正确大小的malloc
'缓冲区的指针。当然,如果您不想依赖该函数的存在,则可以编写自己的此函数版本。
这里还有一个严重的问题,即你的代码不能防止SQL注入(see here的解释)。正确讨论如何防范这种情况可能超出了这个问题的范围!