2016-11-04 54 views
1
scanf_s("%s", a, 10); 

此代碼將保護我們的程序免受緩衝區溢出攻擊。scanf的寬度規範和scanf_s之間的差異

沒有 scanf_s,我們可以這樣寫:

scanf("%9s", a); 

我覺得這個代碼也將阻止緩衝區溢出。這是真的?

那麼兩種方式有什麼不同?

如果scanf的寬度規範阻止緩衝區溢出,爲什麼我們稱原始scanf「不安全」?

回答

3

scanf_s()不是由C99標準(或以前的標準)描述的。

如果您想要使用以C99(或以前)爲目標的編譯器,請使用scanf()。 對於C11 Standardscanf_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中是可選的。

+0

謝謝。但是還有一個問題,scanf_s對算術溢出是安全的嗎? scanf_s如何解決這個問題? – Gear

+1

我編輯了我的答案。 – abhiarora

+0

請注意,C標準中的'scanf_s()'函數家族不提供對數字輸入的算術溢出(下溢)的保護,至少在函數scanf()函數家族中是這樣 - 至少根據附錄C11標準的K.3.5.3.2。 –

相關問題