如何使用scanf避免缓冲区溢出 [英] How to avoid buffer overflow using scanf

查看:113
本文介绍了如何使用scanf避免缓冲区溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include< stdio.h>#include< stdlib.h>int main(int argc,char ** argv){char first_name [20];char last_name [20];int student_num;炭债[1];printf(输入名称:");scanf(%s",first_name);printf(输入姓氏:");scanf(%s",last_name);printf(输入六位长度的学生ID:");scanf(%d",& student_num);printf(您对大学[Y/N]有欠款吗?");scanf(%s",债务);printf("\ n您的名字是%s%s.\ n",first_name,last_name);printf(您的学生ID为%d.\ n",student_num);printf(债务:%s.\ n",债务);返回(EXIT_SUCCESS);} 

如何避免此代码中的缓冲区溢出?我希望我的代码产生这样的输出:

 输入名称:Enescekilokoneyasharrontannamyantoniaaquin输入姓氏:Basenau输入六位长度的学生ID:456789您是否有大学[Y/N]欠款?是您的名字是** Enescekilokoneyashar **(名称输入仅20位)* Basenau *.您的学生证是** 393299 **.债务:** Y **.进程返回-1073741819(0xC0000005)执行时间:36.336 s按任意键继续. 

我尝试使用:

  scanf(%19s",first_name); 

但是它没有按我预期的那样工作.我需要找到另一种方法来验证输入参数,以防止缓冲区溢出攻击并将输入限制为缓冲区大小.

解决方案

您可以继续使用 scanf ,但需要将其占用的大小限制为目标缓冲区的大小,类似:

  scanf(%19 [^ \ n]",first_name);//最后一个目标缓冲区元素为空字节 

请注意,该说明符可以解析空格,因此您可以接受一个以上单词的输入.

但是,它将在 stdin 缓冲区中保留一个 \ n 字符,或者在您输入较大的字符串的情况下未解析的其余字符,因此您每次需要解析新输入时都需要清除它,可以创建一个方便的函数,在需要这种清除时可以调用该函数,从而使其成为一种模式:

  void clear_buffer(){int c;而((c = getchar())!='\ n'& c!= EOF){继续;}} 

您的 char债务[1] 缓冲区也有问题,它太小而无法存储字符串,它必须至少具有2个字符才能存储空终止符:

  char债务[2]; 

呼叫将是:

  clear_buffer();scanf(%1 [^ \ n]",债务); 

最后,如果您输入的是字母字符而不是输入的字符,则应该在 scanf(%d",& student_num)中验证 scanf 的返回.数字,该函数将无法解析并返回0,您也可以使其最多解析6个数字,类似于:

  clear_buffer();if(scanf(%6d",& student_num)== 0){//%6d将输入限制为6位数字//处理错误} 

实时演示

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    char first_name[20];
    char last_name[20];
    int student_num;
    char debts[1];

    printf("Enter name:");
    scanf("%s", first_name);
    printf("Enter lastname:");
    scanf("%s", last_name);
    printf("Enter six bits length student ID:");
    scanf("%d", &student_num);
    printf("Do you have debts for university [Y/N]?");
    scanf("%s", debts);

    printf("\nYour name is %s %s.\n", first_name, last_name);
    printf("Your Student ID is %d.\n", student_num);
    printf("Debts: %s.\n", debts);
    return (EXIT_SUCCESS);
}

How to avoid buffer overflow in this code? I want my code to produce such an output:

Enter name:Enescekilokoneyasharrontannamyantoniaaquin
Enter lastname:Basenau
Enter six bits length student ID:456789
Do you have debts for university [Y/N]?YES

Your name is **Enescekilokoneyashar** (only 20 bits from name input) *Basenau*.
Your Student ID is **393299**.
Debts: **Y**.

Process returned -1073741819 (0xC0000005)   execution time : 36.336 s
Press any key to continue.

I have tried to use:

scanf("%19s", first_name);

But it does not work as I expect. I need to find some another way to validate input parameters to prevent buffer overflow attack and limit input to buffers size.

解决方案

You can maintain the use of scanf but you need to limit the size of what it can take to the size of the destination buffer, something like:

scanf(" %19[^\n]", first_name); //last destination buffer element is for null byte

Note that this specifier can parse spaces so you can take an input with more than one word.

It will, however, leave a \n character in the stdin buffer, or the remaining characters that were not parsed in case you input a larger string, so you need to clear it every time you want to parse a new input, you can make a handy function that you can call when you need such clearence, making it a pattern:

void clear_buffer(){
    int c;
    while ((c = getchar()) != '\n' && c != EOF){
        continue;
    }
}

Your char debts[1] buffer is also problematic, it's too small to store a string, it needs to have at least 2 characters to be able to store the null terminator:

char debts[2];

And the call will be:

clear_buffer();
scanf(" %1[^\n]", debts);

Lastly you should verify the return of scanf, for instance, in scanf("%d", &student_num), if you input alphabetical characters instead of digits, the function will fail to parse and return 0, you can also make it parse at most 6 digits, something along the lines of:

clear_buffer();
if(scanf("%6d", &student_num) == 0){ // %6d limit the input to 6 digits
    //handle error
}

Live demo

这篇关于如何使用scanf避免缓冲区溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆