scanf_s("%s", a, 10);
此代碼將保護我們的程序免受緩衝區溢出攻擊。scanf的寬度規範和scanf_s之間的差異
但沒有 scanf_s,我們可以這樣寫:
scanf("%9s", a);
我覺得這個代碼也將阻止緩衝區溢出。這是真的?
那麼兩種方式有什麼不同?
如果scanf的寬度規範阻止緩衝區溢出,爲什麼我們稱原始scanf「不安全」?
scanf_s("%s", a, 10);
此代碼將保護我們的程序免受緩衝區溢出攻擊。scanf的寬度規範和scanf_s之間的差異
但沒有 scanf_s,我們可以這樣寫:
scanf("%9s", a);
我覺得這個代碼也將阻止緩衝區溢出。這是真的?
那麼兩種方式有什麼不同?
如果scanf的寬度規範阻止緩衝區溢出,爲什麼我們稱原始scanf「不安全」?
scanf_s()
不是由C99標準(或以前的標準)描述的。
如果您想要使用以C99(或以前)爲目標的編譯器,請使用scanf()。 對於C11 Standard
,scanf_s()
比使用scanf()更難以使用,以提高針對buffer overflows
的安全性。
那麼兩種方式有什麼不同?
scanf_s()
是scanf()的更安全版本。在指定目的地的參數後,必須提供目的地的大小。該程序在複製之前檢查緩衝區是否具有指定的大小,以確保沒有覆蓋和惡意代碼未運行。該論點必須在scanf_s()
的情況下通過。
如果scanf的寬度規範阻止緩衝區溢出,爲什麼我們調用原始scanf「不安全」?
可與scanf
函數一起使用的格式說明符支持顯式字段寬度設置,該設置限制輸入的最大大小並防止緩衝區溢出。但scanf()
功能很難使用,因爲字段寬度必須爲embedded into format string
(無法通過可變參數傳遞它,因爲它可以在printf
中完成)。在這方面,scanf的設計確實相當糟糕。但是,任何關於scanf在字符串緩衝區溢出安全性方面無能爲力的主張都是完全虛假的,通常由懶惰的程序員做出。
與scanf()
真正的問題具有完全不同的性質,即使它也關於溢出。當scanf函數用於將數字的十進制表示轉換爲算術類型的值時,它不提供算術溢出保護。如果發生溢出,scanf會產生未定義的行爲。由於這個原因,在C標準庫中執行轉換的唯一正確方法是從strto
系列中的函數。
因此,總結一下上面的問題,scanf
的問題是很難正確和安全地使用字符串緩衝區。並且不可能安全地使用算術輸入。後者是真正的問題。前者只是一個不便。
scanf_s
通過使場寬度通過可變參數的參數,因爲它可以在printf
完成解決了緩衝區溢出的在字符數組的情況下,問題(在scanf()
字段寬度必須embedded into format string
)。此外,在scanf_s
中字段寬度是強制性的,但在scanf
中是可選的。
謝謝。但是還有一個問題,scanf_s對算術溢出是安全的嗎? scanf_s如何解決這個問題? – Gear
我編輯了我的答案。 – abhiarora
請注意,C標準中的'scanf_s()'函數家族不提供對數字輸入的算術溢出(下溢)的保護,至少在函數scanf()函數家族中是這樣 - 至少根據附錄C11標準的K.3.5.3.2。 –