当前位置:首页 > 2014世界杯

C CGI表单更新

admin 2025-07-03 01:48:32 9721

在可能的情况下尽早返回第一,很好地运用了先前审查的要点。您似乎不确定的一件事是提前返回--我将在这里对您的代码进行重构,以展示它是什么样子(我不会在实际的生产代码中包含额外的注释):

代码语言:javascript运行复制#include

#include

#include

int main(void)

{

char *stdInData;

char *requestMethod;

char *contentLenString;

int contentLength;

char *user;

char *pass;

char *stdInDataCpy;

requestMethod = getenv("REQUEST_METHOD");

if ( strcmp(requestMethod,"POST") != 0 ) {

printf("Status: 405 Method Not Allowed\n\n");

/* the program successfully detected the user error! */

return EXIT_SUCCESS;

}

/* If we got here, the request method is POST */

contentLenString = getenv("CONTENT_LENGTH");

contentLength = atoi(contentLenString);

if ( contentLength == 0 ) {

printf("Status: 400 Bad Request\n\n");

/* the program successfully detected the user error! */

return EXIT_SUCCESS;

}

/* If we got here, we have a content length */

stdInData = malloc(contentLength + 1);

if (!stdInData) {

printf("Status: 500 Server Error\n\n");

return EXIT_FAILURE;

}

/* If we got here, we have a buffer to read into */

fgets(stdInData, contentLength + 1, stdin);

stdInDataCpy = malloc(contentLength + 1);

if ( stdInDataCpy ){

strcpy(stdInDataCpy, stdInData);

pass = strtok(stdInDataCpy, "&");

pass = strtok(NULL, "&");

pass = strtok(pass, "=");

pass = strtok(NULL, "=");

}

user = strtok(stdInData, "&");

user = strtok(user, "=");

user = strtok(NULL, "=");

printf("Content-type: text/html\n\n");

printf("\n");

printf("\n");

printf("Takelogin\n");

printf("\n");

printf("\n");

printf("%s@%s", user, pass);

free(stdInData);

free(stdInDataCpy);

printf("\n");

printf("\n");

return EXIT_SUCCESS;

}您看到代码是如何不再深深缩进的吗?而且我们在条件代码中不再有if,所以我们一次只需要跟踪一个条件?

添加了更多的防御检查第一次重构帮助我们识别一些库调用,这些调用的失败我们还没有很好地处理:

如果环境变量未设置,getenv()可以返回空指针。如果出现错误,fgets()将返回一个空指针。如果第二个malloc()失败,我们将忽略它,并且pass未初始化。strtok()可以返回一个空指针。printf()也可能失败,在这种情况下,我们没有正确地执行我们的函数(我们可以在关闭流时发现失败)。下一个版本添加了这些检查(变量声明移到可以初始化的位置):

代码语言:javascript运行复制int main(void)

{

const char *const requestMethod = getenv("REQUEST_METHOD");

if (!requestMethod || strcmp(requestMethod,"POST") != 0) {

printf("Status: 405 Method Not Allowed\n\n");

return EXIT_SUCCESS;

}

const char *const contentLenString = getenv("CONTENT_LENGTH");

int contentLength = contentLenString ? atoi(contentLenString) : 0;

if (contentLength == 0) {

printf("Status: 400 Bad Request\n\n");

return EXIT_SUCCESS;

}

char *const stdInData = malloc(contentLength + 1);

char *const stdInDataCpy = malloc(contentLength + 1);

if (!stdInData || !stdInDataCpy || !fgets(stdInData, contentLength + 1, stdin)) {

printf("Status: 500 Server Error\n\n");

return EXIT_FAILURE;

}

strcpy(stdInDataCpy, stdInData);

const char *pass = strtok(stdInDataCpy, "&");

pass = strtok(NULL, "&");

pass = strtok(NULL, "=");

pass = strtok(NULL, "=");

const char *user = strtok(stdInData, "&");

user = strtok(NULL, "=");

user = strtok(NULL, "=");

if (!pass || !user) {

printf("Status: 400 Missing data\n\n");

free(stdInData);

free(stdInDataCpy);

return EXIT_SUCCESS;

}

printf("Content-type: text/html\n\n"

"\n"

"\n"

"Takelogin\n"

"\n"

"\n"

"%s@%s"

"\n"

"\n",

user, pass);

free(stdInData);

free(stdInDataCpy);

return fclose(stdout) ? EXIT_FAILURE : EXIT_SUCCESS;

}用户输入是敌对的外来的输入是有害的。例如,如果我们传递一个负的内容长度参数会发生什么?

即使不是积极敌对,善意的用户代理也可以按任何顺序传递表单变量user和pass,并且可能提供比我们预期的更多的变量,因此我们不能依赖所需参数的确切位置:我们需要更彻底地检查它们。

最后,变量可能包含我们不希望直接包含到文本中的文本(即跨站点脚本或XSS攻击)。

我们可以使用一些辅助函数来使代码更加健壮:

代码语言:javascript运行复制#include

#include

#include

/* return value (to right of = sign) if s begins with key=, else null */

static const char* val_if_param(const char *s, const char *key)

{

const size_t key_len = strlen(key);

if (!strncmp(s, key, key_len) && s[key_len] == '=') {

return s + key_len + 1;

}

return NULL;

}

static void html_print(const char *s)

{

for (; *s; ++s) {

switch (*s) {

case '&': printf("&"); break;

case '<': printf("<"); break;

default: putchar(*s); break;

}

}

}

int main(void)

{

const char *const requestMethod = getenv("REQUEST_METHOD");

if (!requestMethod || strcmp(requestMethod,"POST") != 0) {

printf("Status: 405 Method Not Allowed\n\n");

return EXIT_SUCCESS;

}

const char *const contentLenString = getenv("CONTENT_LENGTH");

int contentLength = contentLenString ? atoi(contentLenString) : 0;

if (contentLength <= 0) {

printf("Status: 400 Bad Request\n\n");

return EXIT_SUCCESS;

}

++contentLength; /* allow for null terminator */

char *const stdInData = malloc((size_t)contentLength);

if (!stdInData || !fgets(stdInData, contentLength, stdin)) {

printf("Status: 500 Server Error\n\n");

return EXIT_FAILURE;

}

const char *user = NULL;

const char *pass = NULL;

for (char *s = strtok(stdInData, "&"); s; s = strtok(NULL, "&")) {

if (!pass) { pass = val_if_param(s, "pass"); }

if (!user) { user = val_if_param(s, "user"); }

}

if (!pass || !user) {

printf("Status: 400 Missing data\n\n");

free(stdInData);

return EXIT_SUCCESS;

}

puts("Content-type: text/html\n\n"

"\n"

"\n"

"Takelogin\n"

"\n"

"");

html_print(user);

putchar('@');

html_print(pass);

puts("\n\n"

"\n");

free(stdInData);

return fclose(stdout) ? EXIT_FAILURE : EXIT_SUCCESS;

}