0

我正在通过编码慢慢学习和进步,所以我希望有人可以为我快速查看这个功能,并告诉我我是否走在正确的轨道上,我怎样才能做得更好或者我可以在哪里为失败做准备。我是 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 中的数据结构非常陌生。

4

2 回答 2

1

使用strncpy(target, source, strlen(source))保证字符串 intarget不是以空值结尾的。如果可能malloc()返回归零内存,那么它似乎可以工作,但是一旦malloc()返回非归零内存(先前分配的内存),事情就会出错。

的长度参数strncat()很奇怪。它是当前(以空结尾的)数据之后目标字符串中剩余的空间量。您的使用,除了没有可以处理的空终止字符串之外,并不能防止缓冲区溢出。

IMNSHO确实没有一个好的用例strncat(),而且很少有strncpy(). 如果您知道所有内容有多大,则可以使用memmove()(或memcpy()) 代替。如果您不知道所有内容有多大,那么您不知道在不截断的情况下进行复制是否安全。

您的malloc()调用也有点奇怪:它没有为尾随的 null 分配足够的空间,并且仅将三个项之一乘以sizeof(char),这是不一致的,但在其他方面是无害的。很多时候你会逃脱短期分配,因为malloc()四舍五入的大小,但是当你不逃脱时,所有的地狱都会崩溃。像这样的工具valgrind会报告分配内存的滥用情况。

于 2014-08-29T23:09:12.520 回答
0

乔纳森的回答解释了这部分代码的问题。

要修复它,您可以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正确大小的 'd 缓冲区的指针。当然,如果您不想依赖该函数的存在,也可以编写您自己的该函数版本。

这里还有一个严重的问题,即您的代码不能防止 SQL 注入(请参阅此处以获取解释)。关于如何防止这种情况的适当讨论可能超出了这个问题的范围!

于 2014-08-30T21:21:59.517 回答