これらの2つのオプションのどちらを使用するのがより安全かを知りたいです。
_#define MAXLEN 255
char buff[MAXLEN + 1]
_
sprintf(buff, "%.*s", MAXLEN, name)
snprintf(buff, MAXLEN, "%s", name)
私の理解では、両方とも同じです。提案してください。
指定した2つの式は、notと同等です。sprintf
は、書き込む最大バイト数を指定する引数を取りません。単に、宛先バッファ、フォーマット文字列、および一連の引数を取ります。したがって、バッファがスペースを持っているよりも多くのバイトを書き込む可能性があり、そのために任意のコードを書き込みます。 %.*s
は次の理由で満足のいく解決策ではありません。
strlen
に相当するものを参照しています。これは、メモリ内の長さではなく、文字列の文字数の尺度です(つまり、nullターミネータはカウントしません)。sprintf
バージョンの動作を変更します。 snprintf
を使用すると、フォーマット文字列または入力タイプの変更に関係なく、固定の明確な最大値が設定されます。質問の簡単な例では、2つの呼び出し間のセキュリティに大きな違いはないかもしれません。ただし、一般的な場合、snprintf()
はおそらくより安全です。複数の変換仕様を含むより複雑なフォーマット文字列を作成すると、特に以前の変換では必ずしも固定数が生成されないため、異なる変換全体でバッファ長を正確に考慮することは困難(またはほぼ不可能)になる可能性があります出力文字の。
したがって、snprintf()
を使い続けます。
snprintf()
のもう1つの小さな利点は(セキュリティ関連ではありませんが)、必要なバッファの大きさを教えてくれることです。
最後の注意-snprintf()
呼び出しで実際のバッファサイズを指定する必要があります-ヌルターミネータのアカウンティングを処理します。
snprintf(buff, sizeof(buff), "%s", name);
この節を読むまでは、snprintf()
の方がはるかに優れていると思います。
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html
簡単な要約:snprintf()
は移植性がありません。システムからシステムへの動作の変更。 snprintf()
の最も深刻な問題は、snprintf()
を呼び出すだけでsprintf()
が実装されている場合に発生する可能性があります。しかし、そうではないかもしれません。
そのため、今でもsnprintf()
はより安全であると言っていますが、使用する際には注意が必要です。
最適かつ最も柔軟な方法は、snprintf
!を使用することです。
size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */
char *str = malloc(nbytes);
snprintf(str, nbytes, "%s", name);
C99では、snprintf
は、'\0'
を除く文字列に書き込まれたバイト数を返します。必要なバイト数よりも少ない場合、snprintf
は、フォーマットを拡張するために必要なバイト数を返します('\0'
を除く)。 snprintf
に長さ0の文字列を渡すことにより、展開された文字列がどれくらいの長さであったかを事前に見つけ、それを使用して必要なメモリを割り当てることができます。
あなたのsprintfステートメントは正しいですが、安全目的のためにそれを使用するほど自信がありません(たとえば、1つの謎めいた文字がなく、あなたはシールドレスです) wait snprintfはANSI Cにありません。それは(だけ?)C99です。それが、もう1つを好む(弱い)理由かもしれません。
まあ。 strncpy
も使用できますか?
例えば.
char buffer[MAX_LENGTH+1];
buffer[MAX_LENGTH]=0; // just be safe in case name is too long
strncpy(buffer,MAX_LENGTH,name); // strncpy will never overwrite last byte
これら2つの間に重要な違いがあります-snprintf
呼び出しは、正しい戻り値を見つけるためにname
引数を最後までスキャンします(NULを終了します)。一方、sprintf
呼び出しは、name
からAT MOST 255文字)を読み取ります。
したがって、name
が少なくとも255文字の非NUL終了バッファへのポインタである場合、snprintf
呼び出しはバッファの最後から実行され、未定義の動作(クラッシュなど)を引き起こす可能性があります。 sprintf
バージョンはサポートしません。
どちらも必要な結果を返しますが、snprintf
はより一般的であり、指定された形式文字列に関係なく、文字列をオーバーランから保護します。
さらに、snprintf
(またはその場合はsprintf
)が最後の\0
、文字列バッファを1バイト大きくする必要があります、char buff[MAXLEN + 1]
。