scanf("%s", buf);
で、bufの長さはどれくらいに取ればよいのでしょう。
sscanf(buf,"%s",buf2);
なら、sizeof(buf)以上に大きくならないでしょうが、scanf(), fscanf()で文字列を読み込むときは、Buffer Overflowの危険から逃れられないような気がしています。
私はそのため、文字列を扱うときには、この二つの関数を使わないでいるのですが、安全な使用方法はあるのでしょうか?
scanf("%10s",buf);
のような使い方は知っています。でもこれでは文字数が10文字だったのか、それ以上だったのか判別できません。知りたいのは最大文字数が未知の場合です。
こう使えば安全という使い方があればぜひご紹介ください。
No.12
- 回答日時:
> scanf()系の関数は、大変便利なのでつい使いたくなりますが、どういう仕様だったらもっと安全だったのでしょうねえ。
効率や利便性を犠牲にすれば、より安全にすることはできますが、外部I/Oを扱う関数を、単体で完全に安全にすることは不可能です。
Cの精神では、関数を安全に使うのは利用者の責任ですから、運用面も含めて安全になるように設計することが不可欠です。そういう意味では、#7のrinkunさんの指摘が一番的を射ているかと思います。
No.11
- 回答日時:
> mktemp(3)を使うのに対し、
> sprintf(dbname, "/tmp/randword%x", (int) getppid());
> とかくのは本質を外れますが、過剰品質とはいえないと思います。
もし質問の内容が「mktempの使い方を教えてください」であれば、過剰品質ではなく、単なる見当違いです。
また、一時ファイル名の生成方法に関する質問であれば、mktempに比べてご提案の方法は決して安全性が高いわけではありませんし、移植性も低下します。
さらに、質問者が環境非依存のプログラムを書いている場合や、質問中で環境を指定していない場合には、tmpnam以外の選択肢がないことも事実です。そんな場合に「環境非依存」という要件を無視して、特定環境における安全性を主張しても無意味です。
> > 作成依頼をしたいのであれば、相応の対価を支払った上で委託するのが筋です。
> 教えて!gooに出てくる質問だって、その多くは本来、対価を支払って学校などで教わるものではないでしょうか?
学校で教わることができるというだけで、ここで質問していけないわけではありません。それに対して、作成依頼目的の利用は利用規約で禁止されているので、ここでは行うべきではないのです。
No.10
- 回答日時:
せっかくですので、もう少し考察してみましょう。
scanf("%10ls", wcs);
のような場合には、どこまで読み込まれたのかを知るのは結構大変です。
特に、不正列によって走査が中断されると、検出するのはかなり難しくなります。少なくとも、MB_CUR_MAXバイトまでは先読みしないといけないわけですが、ungetcで戻せるのは1文字までしか保証されないのも厄介です。
やってやれないことはないでしょうが、かなりのボリュームになってしまいそうです。
scanf系の関数でどうしようもないのは、バッファオーバーフローよりむしろ数値のオーバーフローです。
入力された値が、実引数で指定したオブジェクトで表現できなかった場合の動作は未定義なので、数値がオーバーフローした時点で、一見動いているように見えても、安全性・信頼性の観点からは既に終わってしまっています。
というわけで、上記のような場合は、scanf系関数はsscanfも含めて、安全とはいえないでしょうね。
ありがとうございます。
sscanf(3)にも危険性はあるという指摘、大変興味深いです。
scanf()系の関数は、大変便利なのでつい使いたくなりますが、どういう仕様だったらもっと安全だったのでしょうねえ。
No.9
- 回答日時:
> 実例として、
> http://oshiete1.goo.ne.jp/kotaeru.php3?q=1719642
> からあえて取らせていただきました。文脈から悪い例と判断されるので、弊害はないかと思います。
はい。そこでの回答でも、移植性がないこと、どうすれば移植性を持たせられるかについても書いています。
> > if (scanf("%10[" CHARSET "]%c", buf, &c) < 2 || strchr(CHARSET, c) == NULL)
> この文は期待したようにはコンパイルされないと思います。
コンパイル&動作を確認済みですが、どの辺りが気になりましたか?
まあ、動作に関していえば、scanfが0やEOFを返した場合の対策を施していないので、安全性に問題があるといえばいえなくもありませんが...
> 安全性は過剰品質ですか?
説明のためのサンプルコードでは、一般的な安全対策も過剰品質でしかありません。説明の本質から外れたコードが増えると、要点がぼやけてしまいます。
たとえ、サンプルコードを丸写しして問題が発生しようと、それはその人の問題に過ぎません。ここはソースコードの作成依頼目的で利用すべき場所ではないのです。作成依頼をしたいのであれば、相応の対価を支払った上で委託するのが筋です。
たびたびありがとうございます。
> コンパイル&動作を確認済みですが、どの辺りが気になりましたか?
勘違いです。失礼しました。
> 説明のためのサンプルコードでは、一般的な安全対策も過剰品質でしかありません。
mktemp(3)を使うのに対し、
sprintf(dbname, "/tmp/randword%x", (int) getppid());
とかくのは本質を外れますが、過剰品質とはいえないと思います。
> 作成依頼をしたいのであれば、相応の対価を支払った上で委託するのが筋です。
教えて!gooに出てくる質問だって、その多くは本来、対価を支払って学校などで教わるものではないでしょうか?
No.8
- 回答日時:
さらに蛇足かもしれませんが…
> (コード略)
> この文は期待したようにはコンパイルされないと思います。
え?正しくコンパイルされますよ。プリプロセッサの動作と、文字列リテラルの連結についてよく考えてみましょうよ。
--サンプルプログラムここから
#include <stdio.h>
#include <string.h>
#define CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
int main()
{
char buf[16], c;
if (scanf("%10[" CHARSET "]%c", buf, &c) < 2 || strchr(CHARSET, c) == NULL)
{
puts("10文字以下だった");
}
else
{
ungetc(c, stdin);
puts("10文字を超えてちょん切られた。");
}
return 0;
}
--サンプルプログラムここまで
これでちゃんと動作します。"%10[A-Za-z]%c"と同等です。
> 安全性は過剰品質ですか?
商品なら安全性は品質です。
サンプルコードの場合は、本題以外の部分は安全性より簡単であることが重視されます。
でも、初心者向けのサンプルプログラムで、上記のようにやっちゃうと、当の初心者はついてこれません。だから、scanf("%10s", buf);で十分なのではないかと思うんです。ちなみに、私が文字列を取り出すサンプルを書く場合は、
--サンプルコード片ここから
char buf[16];
fgets(buf, 10, stdin);
buf[10]='\0';
--サンプルコード片ここまで
とかしますけどね。(これで十分なのかはまた別の問題)
ところで、これでわかるように、元の質問
> こう使えば安全という使い方があればぜひご紹介ください。
への回答は#5のjactaさんの回答で既になされているわけなんですけど、このまま続けます?
>> この文は期待したようにはコンパイルされないと思います。
失礼いたしました。勘違いです。
> 回答は#5のjactaさんの回答で既になされているわけなんですけど、このまま続けます?
「教えて!goo」の仕様で締め切ってしまうと、まだ続けたい人がいたり、回答が間違っていて補足をしたくてもできなくなってしまうのですね。
あまり早い締め切りも、いつまでも締め切らないでいるのもどっちも問題です。
しばらく新しい投稿がなくなったのを確認してから締め切らせてください。
No.7
- 回答日時:
> 安全なライブラリの使い方というより、危険なプログラムを安全に使う限定方法ですね。
危険のない環境では危険なプログラムではありませんよ。
仕様外の入力を考慮しなくて良いプログラムではfscanf()もscanf()も安全に使えます。
> お言葉ではございますが、質問した初心者は、安全性など考えずにいただいたコードをありがたく使いますよ。
たいていはそれで問題も起きないので良いのでは?
もしセキュリティを考慮しなければいけないようなプログラムでそんなことをするバカだったら早めに痛い目に遭って学習させる方が身のためだし。
# そんなバカにセキュリティを考慮すべきプログラムを書かせるバカも
No.6
- 回答日時:
他人の回答についた補足ですが…
> 質問した初心者は、安全性など考えずにいただいたコードを
> ありがたく使いますよ
なるほど、そういうことね、質問の意図がやっとわかりました。
初心者は確かにそのとおりだと思います。
でも、私たち職業プログラマはそうではいけないので、お客様に納品するべきプログラムではそのようなコードを使うことはありません。
というか、初心者は実際に痛い目にあわないと痛い目について理解できないので、サンプルプログラムが危険でもいいという考え方もあるのです。
--サンプルプログラムここから
int sub(char *x)
{
return scanf("%s", x);
}
int main()
{
char string[16];
return printf("%s\n",sub(string));
}
--サンプルプログラムここまで
というプログラムで、メモリを超えて入力したらおかしくなった、という経験をしないとscanfが怖いとは思わないということです。ちなみに、この例はもろにスタックを破壊しておかしくなります。
その時点で、fgetsとsscanfで代替できるということを覚えても遅くはないのでは?ということです。
ありがとうございます。
失敗に学べということどすね。
でも、IE,firefoxともBuffer overflowによるバグで、パッチを当てまくっているという現実があります。
No.5
- 回答日時:
> fscanf(stream, "%[A-Za-z]", str);
> 見たいな場合はどうしましょうかね?
まず、"%[A-Za-z]"という書き方には移植性がありません。これを見た初心者が真似をすると危険という観点からは、好ましくありませんね。
今回の場合も、同じようにやればそこそこの安全性は保たれるように思います。
#define CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
if (scanf("%10[" CHARSET "]%c", buf, &c) < 2 || strchr(CHARSET, c) == NULL)
{
puts("10文字以下だった");
}
else
{
ungetc(c, stdin);
puts("10文字を超えてちょん切られた。");
}
今回の場合に特化すれば、isalphaでも構いませんが、一般的にはstrchrまたはmemchrにする必要があるかと思います。
ところで、個人的には
> 説明のためのサンプルコードにセキュリティ上の安全性を求めるほうが間違ってる。
を指示します。
過剰品質は、時としてセキュリティホール以上に問題がありますから。
たびたびのご回答ありがとうございます。
> まず、"%[A-Za-z]"という書き方には移植性がありません。
実例として、
http://oshiete1.goo.ne.jp/kotaeru.php3?q=1719642
からあえて取らせていただきました。文脈から悪い例と判断されるので、弊害はないかと思います。
> if (scanf("%10[" CHARSET "]%c", buf, &c) < 2 || strchr(CHARSET, c) == NULL)
この文は期待したようにはコンパイルされないと思います。
> 過剰品質は、時としてセキュリティホール以上に問題がありますから。
過剰品質は要求していません。安全性は過剰品質ですか?
No.4
- 回答日時:
安全な使い方といえば、入力にオーバーフローするようなデータがないと分かっているときや、オーバーフローを起こしても対処できるような使い方しかしないとき。
あらかじめフォーマットが確認されているファイルをfscanfで読み込むとか、作った本人が使うプログラムでscanf入力を使うとか。
> このカテゴリの回答の中にも多数のscanf()を使った回答を見かけます。
説明のためのサンプルコードにセキュリティ上の安全性を求めるほうが間違ってる。
# 話題自体がセキュリティの場合は別だが
ありがとうございます。
安全なライブラリの使い方というより、危険なプログラムを安全に使う限定方法ですね。
> 説明のためのサンプルコードにセキュリティ上の安全性を求めるほうが間違ってる。
お言葉ではございますが、質問した初心者は、安全性など考えずにいただいたコードをありがたく使いますよ。サンプルコードにも安全性は求められると思います。汎用性までは求めなくとも。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- Excel(エクセル) エクセル関数の変わった使い方 3 2022/05/13 17:12
- C言語・C++・C# 略語の読み方について 2 2023/05/25 12:35
- Visual Basic(VBA) オブジェクトが見つかりません 1 2023/06/24 19:43
- Visual Basic(VBA) 複数csvを横に追加していくマクロについて 2 2023/04/25 09:19
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- C言語・C++・C# #include <stdio.h>int main(void) { int buf[100] = 6 2022/11/01 22:45
- Visual Basic(VBA) findメソッドの変数について 6 2023/06/23 08:01
- 政治 私の発明した「二階建て漢字」は使えるでしょうか? 3 2023/02/08 16:40
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・プリン+醤油=ウニみたいな組み合わせメニューを教えて!
- ・タイムマシーンがあったら、過去と未来どちらに行く?
- ・遅刻の「言い訳」選手権
- ・【大喜利】【投稿~11/12】 急に朝起こしてきた母親に言われた一言とは?
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・好きな「お肉」は?
- ・あなたは何にトキメキますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・ハマっている「お菓子」を教えて!
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
プロダクションコードとは?
-
指定したフォルダーを最前面表...
-
無限ループ中にある任意のキー...
-
Arduino nano(アルドゥイーノ ...
-
テキストの暗号化
-
2値化した画像の黒い部分のピク...
-
マイコンからプログラムを読み...
-
Java規則性のある再帰的手続き...
-
初級者の質問――time_tについて
-
任意ソフトのテキストボックス...
-
ドキメントの手直し
-
VBコンソールアプリ(.NET Frame...
-
COBOLのS9タイプからXタイプへ...
-
共分散行列を求めるプログラム
-
複素数の固有値の求めるプログ...
-
vba listviewにおけるtextのAli...
-
C言語primeについて
-
signalハンドラに引数を渡したい
-
ドロネー三角形分割のプログラ...
-
Macターミナルで実行中のプログ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プロダクションコードとは?
-
指定したフォルダーを最前面表...
-
Arduino nano(アルドゥイーノ ...
-
vba listviewにおけるtextのAli...
-
C言語primeについて
-
世界一美しいソースコード
-
COBOLのS9タイプからXタイプへ...
-
マイコンからプログラムを読み...
-
2値化した画像の黒い部分のピク...
-
無限ループ中にある任意のキー...
-
初級者の質問――time_tについて
-
c言語のサイコロを100回振って...
-
Excel VBA じゃんけん
-
VBAにてTIFFから画像を取込みた...
-
コンパイルエラーの意味
-
C言語で1000までの素数を求める...
-
arduino mpu6050 計測できない
-
VB6 画面サイズ変更について
-
Labviewって・・・
-
signalハンドラに引数を渡したい
おすすめ情報