Secure Programming for Linux HOWTO <author>David A. Wheeler, <tt>dwheeler@dwheeler.com</tt> <date>version 1.30, 9 February 2000</date> <trans>高橋 聡 <tt>hisai@din.or.jp</tt> <tdate> 2000/09/22 <abstract> <!-- This paper provides a set of design and implementation guidelines for writing secure programs for Linux systems. Such programs include application programs used as viewers of remote data, CGI scripts, network servers, and setuid/setgid programs. --> このドキュメントは Linux で安全性が求められるプログラムを書く場合に 必要になる設計と実装のしかたについて、そのガイドラインを示します。安全性が 求められるプログラムとは、接続先に存在するデータのビューアー、 CGI スクリプト、 ネットワーク関連のサーバー、setuid/setgid されているプログラムなどです。 </abstract> <toc> <!-- Begin the document --> <!-- <sect>Introduction --> <sect>序論 <p> <!-- This paper describes a set of design and implementation guidelines for writing secure programs on Linux systems. For purposes of this paper, a ``secure program'' is a program that sits on a security boundary, taking input from a source that does not have the same access rights as the program. Such programs include application programs used as viewers of remote data, CGI scripts, network servers, and setuid/setgid programs. This paper does not address modifying the Linux kernel itself, although many of the principles discussed here do apply. These guidelines were developed as a survey of ``lessons learned'' from various sources on how to create such programs (along with additional observations by the author), reorganized into a set of larger principles. --> このドキュメントは Linux で安全性が求められるプログラムを書く場合に 必要になる設計と実装のしかたについて、そのガイドラインを示します。 このドキュメントの目的は、「安全なプログラム」です。安全なプログラムとは セキュリティの防護壁となっており、プログラム自身と同じアクセス権限を持って いない入力先からの入力を受け取るプログラムのことです。 そのようなプログラムとして、接続先に存在するデータを見るためのアプリケー ション、CGI スクリプト、ネットワーク関連のサーバー、setuid/setgid されて いるプログラムなどがあげられます。 このドキュメントでは、Linux のカーネル自体の修正は取扱いませんが、ここで 議論される手法の多くはカーネルの修正にも有効です。 これらのガイドラインは、安全なプログラムを書くための様々な情報(著者自身の 考えも含まれています)から「教訓として学んできたこと」を整理して、原則の 集大成としてまとめ直したものです。 <p> <!-- This paper does not cover assurance measures, software engineering processes, and quality assurance approaches, which are important but widely discussed elsewhere. Such measures include testing, peer review, configuration management, and formal methods. Documents specifically identifying sets of development assurance measures for security issues include the Common Criteria [CC 1999] and the System Security Engineering Capability Maturity Model [SSE-CMM 1999]. More general sets of software engineering methods or processes are defined in documents such as the Software Engineering Institute's Capability Maturity Model for Software (SE-CMM), ISO 9000 (along with ISO 9001 and ISO 9001-3), and ISO 12207. --> <!-- ??? Ideally have references for these. --> このドキュメントでは、安全についての保証基準やソフトウエア工学の手法、 品質保証の手法は扱いません。それらは大切なことですが、すでに他のところ で広く論じられています。 これらの手法には、テスト、ピア・レビュー、コンフィギュレーション管理、 フォーマルメソッドがあります。セキュリティについての開発時の保証基準 については、the Common Criteria [CC 1999] や the System Security Engineering Capability Maturity Model [SSE-CMM 1999] などがあります。 ソフトウエア工学の手法については、Software Engineering Institute's Capability Maturity Model for Software (SE-CMM) や ISO 9000 (ISO 9001 と ISO 9001-3 と合わせて参照のこと)、ISO 12207 などに詳しく書かれています。 <p> <bf>訳註:</bf> <itemize> <item>ピア・レビューとは、同じ分野の専門家たちと意見交換を行なうこと <item>フォーマルメソッドとは、設計を行なうに当たって、数学的(統計的)な 手法を用いる方法論 <item>[CC 1999] という表記は、参考文献を表す </itemize> <!-- This paper does not discuss how to configure a system (or network) to be secure in a given environment. This is clearly necessary for secure use of a given program, but a great many other documents discuss secure configurations. Information on configuring a Linux system to be secure is available in a wide variety of documents including Fenzi [1999], Seifried [1999], and Wreski [1998]. --> このドキュメントは、ある特定の環境で動いているシステム(もしくはネット ワーク)を安全に設定する方法を議論していません。設定方法はプログラムを 安全に利用する上では必須の事項ですが、これ以外に安全な設定方法について 論じている文献が多数存在します。安全に Linux システムを稼働させる 方法については、Fenzi [1999]、Seifried [1999]、Wreski [1998] をはじめ として、すでに広く論じられています。 <p> <!-- This paper assumes that the reader understands computer security issues in general, the general security model of Unix-like systems, and the C programming language. This paper does include some information about the Linux programming model for security. --> このドキュメントは、読者のみなさんがコンピュータの安全性について おおよそ理解しており、UNIX ライクなシステムのセキュリティ・モデルや C に ついても理解していることを前提としています。 また、セキュリティに関連する Linux のプログラミング・モデルについても若干 ですが解説しています。 <p> <!-- You can find the master copy of this document at <url url="http://www.dwheeler.com">. This document is also part of the Linux Documentation Project (LDP) at <url url="http://www.linuxdoc.org"> (the LDP version may be older than the master copy). --> このドキュメントの原本は<url url="http://www.dwheeler.com">にあります。 また Linux Documentation Project (LDP) <url url="http://www.linuxdoc.org"> にも含まれています(LDP 版は、原本よりも古い可能性があります)。 <p> <!-- This document is (C) 1999-2000 David A. Wheeler and is covered by the GNU General Public License (GPL); see the last section for more information. --> このドキュメントは David A. Wheeler が著作権((C) 1999-2000 David A. Wheeler) を保持しています。また GNU General Public License (GPL) によってその権利は 保護されています。詳しいことはこのドキュメントの最後のセクションを参照して ください。 <p> <!-- This paper first discusses the background of Linux and security. The next section describes the general Linux security model, giving an overview of the security attributes and operations of processes, filesystem objects, and so on. This is followed by the meat of this paper, a set of design and implementation guidelines for developing applications on Linux systems. This is broken into validating all input, avoiding buffer overflows, structuring program internals and approach, carefully calling out to other resources, judiciously sending information back, and finally information on special topics (such as how to acquire random numbers). The paper ends with conclusions and references. --> このドキュメントはまず Linux の背景とそのセキュリティについて論じます。 次のセクションでは、一般的な Linux のセキュリティ・モデルについて、 プロセスやファイルシステム等を対象に、その属性と取扱い方を一通り見ていき ます。 その次にこのドキュメントの中心となる Linux 上でのアプリケーション開発の設計 と実装についてのガイドラインを説明します。この中では下記の項目を取り上げて います。 <itemize> <item>入力されるものすべてを検証すること <item>バッファオーバフローを回避すること <item>プログラムのインタフェースと内部構成をきちんとすること <item>他のリソースを利用する場合は慎重に行うこと <item>セキュリティに気を配って情報をやりとりすること <item>その他関連事項(乱数の取得方法など) </itemize> 最後に結論と参考文献でしめくくります。 </sect> <!-- <sect>Background <sect1>Linux and Open Source Software --> <sect>背景 <sect1>Linux とオープン・ソース・ソフトウエア <p> <!-- In 1984 Richard Stallman's Free Software Foundation (FSF) began the GNU project, a project to create a free version of the Unix operating system. By free, Stallman meant software that could be freely used, read, modified, and redistributed. The FSF successfully built many useful components but was having trouble developing the operating system kernel [FSF 1998]. In 1991 Linus Torvalds began developing an operating system kernel, which he named ``Linux'' [Torvalds 1999]. This kernel could be combined with the FSF material and other components producing a freely-modifiable and very useful operating system. This paper will term the kernel itself the ``Linux kernel'' and an entire combination as ``Linux'' (many use the term GNU/Linux instead for this combination). --> 1984 年に Richard Stallman 氏は Free Software Foundation (FSF)にて、GNU プロジェクトという、フリーな UNIX オペレーティングシステムを作り上げる プロジェクトを立ち上げました。フリーという言葉で、Stallman 氏は利用する こと、内容(ソース)を読むこと、修正を加えること、再配布することが自由に できるソフトウエアを表現しました。 FSF は数多くの便利なツール群を作成することができましたが、独自のオペレー ティングシステムのカーネルを思うように開発できずにいました [FSF 1998]。 1991 年に Linus Torvalds 氏が「Linux」というオペレーティングシステムの カーネルを開発しはじめました [Torvalds 1999]。 このカーネルは FSF や他のツールと相まって、自由に改変できる、たいへん実用的 なオペレーティングシステムとなりました。 このドキュメントではカーネルを指す言葉として「Linux カーネル」を、システム 全体を示す言葉として「Linux」を使用します(同様な意味で GNU/Linux という表現 を使う場合が多々あります)。 <p> <!-- Different organizations have combined the available components differently. Each combination is called a ``distribution,'' and the organizations that develop distributions are called ``distributors.'' Common distributions include Red Hat, Mandrake, SuSE, Caldera, Corel, and Debian. This paper is not specific to any distribution; it does presume Linux kernel version 2.2 or greater and the C library glibc 2.1 or greater, which are valid assumptions for essentially all current major Linux distributions. --> 様々な団体がそれぞれに、便利なツール群をこのカーネルと組み合わせています。 この組合せを「ディストリビューション」と呼び、団体を「ディストリビュータ」 と呼んでいます。 よく知られたディストリビュータには Red Hat、Mandrake、SuSE、Caldera、Corel、 Debian があります。 このドキュメントは特定のディストリビューションにターゲットを当てていません が、カーネルのバージョンが 2.2 以上で C ライブラリが glibc 2.1 以上である ことを前提にしています。現在の主要なディストリビューションはすべて、この 前提を満たしています。 <p> <!-- Increased interest in such ``free software'' has made it increasingly necessary to define and explain it. A widely used term is ``open source software,'' which further defined in [OSI 1999]. Eric Raymond [1997, 1998] wrote several seminal articles examining its development process. --> 「フリーソフトウエア」への関心が増すにつれ、その定義と説明を行う必要性が でてきました。 世間で広く使用されている言葉は「オープン・ソース・ソフトウエア」であり、 [OSI 1999] で詳細に定義されています。 Eric Raymond [1997, 1998] の中で、フリーソフトウエアの開発過程について、 独創性に富んだ論文をいくつか発表しています。 <p> <!-- Linux is not derived from Unix source code, but its interfaces are intentionally Unix-like. Therefore, Unix lessons learned apply to Linux, including information on security. Much of the information in this paper actually applies to any Unix-like system, but Linux-specific information has been intentionally added to enable those using Linux to take advantage of its capabilities. This paper intentionally focuses on Linux systems to narrow its scope; including all Unix-like systems would require an analysis of porting issues and other systems' capabilities, which would have greatly increased the size of this document. --> Linux はいわゆる UNIX と呼ばれるものからソースコードを流用していません。 しかしそのインターフェースは非常に UNIX ライクです。 そのため UNIX で学んだ教訓はそのまま Linux にも当てはまります。もちろん セキュリティについても同様です。 このドキュメントで述べられている情報の大部分は、実際のところ他の UNIX ライクなシステムでも役に立ちます。しかし Linux 固有の情報も意図的に加え られています。それは Linux の持つ優れた能力を引き出すためです。 このドキュメントではあえて Linux システムに焦点を当てて、対象となるシステム を狭めています。すべての UNIX ライクなシステムを対象にしてしまうと、ポーティ ングや他のシステムの機能についての詳細な検討が必要になってしまい、結果として このドキュメントの量が増えてしまうためです。 <p> <!-- Since Linux is intentionally Unix-like, it has Unix security mechanisms. These include user and group ids (uids and gids) for each process, a filesystem with read, write, and execute permissions (for user, group, and other), System V inter-process communication (IPC), socket-based IPC (including network communication), and so on. See Thompson [1974] and Bach [1986] for general information on Unix systems, including their basic security mechanisms. Section 3 summarizes key Linux security mechanisms. --> Linux は非常に UNIX ライクで、UNIX の持つセキュリティ関連のしくみを持って います。 そのしくみとは、プロセスに対するユーザやグループの ID(uid と gid)、読み/ 書き/実行それぞれのパーミッションを持ったファイルシステム、System V 由来 のプロセス間通信(IPC)、ソケットベースの IPC(ネットワークを利用した通信も 含む)等です。 UNIX システム一般の基本的なセキュリティについての情報は、 Thompson [1974] と Bach [1986] を見てください。 セクション 3 では Linux のセキュリティ機構のキーポイントを概説します。 <!-- ???: This is cheating; switch eventually to a real cross-reference --> <!-- <sect1>Security Principles --> <sect1>セキュリティの原則 <p> <!-- There are many general security principles which you should be familiar with; consult a general text on computer security such as [Pfleeger 1997]. --> セキュリティの原則については、少なからず知っておく必要があります。 ぜひ [Pfleeger 1997] のような、コンピュータに関わるセキュリティ全般について 書かれた書籍を読んでください。 <p> <!-- Saltzer [1974] and Saltzer and Schroeder [1975] list the following principles of the design of secure protection systems, which are still valid: --> Saltzer [1974] と Saltzer and Schroeder [1975] において、安全を保護する ためのシステム設計を行うに当たって、その原則について下記のようにまとめて います。これは現在でもなお有効です。 <itemize> <!-- <item><it>Least privilege</it>. Each user and program should operate using the fewest privileges possible. That way, damage from attack is minimized. <item><it>Economy of mechanism</it>. The protection system's design should be small, simple, and straightforward. <item><it>Open design</it>. The protection mechanism must not depend on the attacker ignorance. Instead, the mechanism should be public, depending on the secrecy of relatively few (and easily changeable) items like passwords. This makes extensive public scrutiny possible. Bruce Schneier argues that smart engineers should ``demand open source code for anything related to security,'' as well as ensuring that it receives widespread review and that any identified problems are fixed [Schneier 1999]. <item><it>Complete mediation</it>. Every access attempt must be checked; position the mechanism so it cannot be subverted. For example, in a client-server model, generally the server must do all access checking because users can build or modify their own clients. <item><it>Permission-based</it>. The default should be denial of service. <item><it>Separation of privilege</it>. Ideally, access to objects should depend on more than one condition, so that defeating one protection system won't enable complete access. <item><it>Least common mechanism</it>. Shared objects provide potentially dangerous channels for information flow, so physically or logically separate them. <item><it>Easy to use</it>. If a mechanism is easy to use it is unlikely to be avoided. --> <item><it>特権をできるだけ持たせない</it>。 ユーザやプログラムには、できるだけ権限を持たせないようにすること。 そうすれば、攻撃者によるダメージが最小限に抑えられる <item><it>しくみを単純に</it>。 防御システムは小さく単純明快な設計にすること <item><it>オープンな設計</it>。 防御するしくみは、攻撃者がそのしくみの知識を持ってないことに依存して はならない。 逆に、そのしくみは公開されたもので、パスワードのように比較的少ない項目 (そして簡単に変えられる)で秘密を守れること。 そうしておけば、広く第三者からチェックを受けられる。 Bruce Schneier 氏は、頭の切れるエンジニアならば、「セキュリティに関する すべてのコードはオープン・ソースであることを強く主張する」に違いないと している。 またそうすることで、広く第三者からレビューを受けられ、そこで問題となった 部分も修正されることを証明している。[Schneier 1999] <item><it>完全に仲介を行うこと</it>。 すべてのアクセスをチェックしなければならない。チェックするしくみは、 それが破られないところに置くこと。 たとえば、クライアント-サーバー・モデルであれば、サーバー側ですべての アクセスをチェックする必要がある。それはユーザが、クライアント側を新しく 作成したり、既存のものを修正することが可能なためである <item><it>パーミッションを活用すること</it>。 デフォルトではサービスを拒否すること <item><it>権限を集中させない</it>。 対象へのアクセスに当たって、理想的には複数の条件をつける必要がある。そう すれば、もしある防御システムが破られても、無制限なアクセスを許すような ことにはならない <item><it>共通したしくみはできるだけ用いない</it>。 しくみを共通化すると、そこが一連の情報の流れの中で危険性をはらんだ経路 になってしまう恐れがある。したがって物理的にも論理的にも独立させること <item><it>簡単に使える</it>。 ユーザが利用を敬遠しないように、簡単に使えるようにすること </itemize> <!-- <sect1>Types of Secure Programs --> <sect1>安全性が求められるプログラムの種類 <p> <!-- Many different types of programs may need to be secure programs (as the term is defined in this paper). Some common types are: --> 安全性は多岐に渡るプログラム(このドキュメントで定義されている)に求めら れています。 代表的なものをあげてみます。 <itemize> <!-- <item>Application programs used as viewers of remote data. Programs used as viewers (such as word processors or file format viewers) are often asked to view data sent remotely by an untrusted user (this request may be automatically invoked by a web browser). Clearly, the untrusted user's input should not be allowed to cause the application to run arbitrary programs. It's usually unwise to support initialization macros (run when the data is displayed); if you must, then you must create a secure sandbox (a complex and error-prone task). Be careful of issues such as buffer overflow, discussed later, which might allow an untrusted user to force the viewer to run an arbitrary program. <item>Application programs used by the administrator (root). Such programs shouldn't trust information that can be controlled by non-administrators. <item>Local servers (also called daemons). <item>Network-accessible servers (sometimes called network daemons). <item>CGI scripts. These are a special case of network-accessible servers, but they're so common they deserve their own category. Such programs are invoked indirectly via a web server, which filters out some attacks but nevertheless leaves many attacks that must be withstood. <item>setuid/setgid programs. These programs are invoked by a local user and, when executed, are immediately granted the privileges of the program's owner and/or owner's group. In many ways these are the hardest programs to secure, because so many of their inputs are under the control of the untrusted user and some of those inputs are not obvious. --> <item>リモートにあるデータを見るためのアプリケーション。 ビューアー(ワードプロセッサやファイルフォーマットを見るためのビューアー など)として使われるプログラムでは、離れたところにいる信頼できないユーザ がデータを送るように要求するケースが多い(このような要求は Web ブラウザ が自動的に行っている場合がある)。 信頼できないユーザからの入力によって、任意のプログラムを動かすような アプリケーションは決して許可すべきではない。 初期化マクロ(データを表示する時に動く)をサポートすることも、一般的に よいとはいえない。仮にサポートしなければならない場合でも、安全なサンド ボックス(複雑で間違いが起きがち)を用意する必要がある。 後程触れるバッファオーバーフローのような問題は、十分に注意が必要である。 バッファオーバーフローが起きると、信頼できないユーザがビューアー経由で 任意のプログラムを動かすことを許してしまう恐れがある <p> <bf>訳註:</bf>サンドボックス(sandbox)とは、制限付きで保護されたメモリー 領域。この領域で動くアプリケーションは、システムにダメージを与えない ように設計、動作します。 <p> <item>システム管理者(root)が使用するアプリケーション・プログラム。 そのようなプログラムでは、システム管理者以外が変更できる情報を信頼しては いけない <item>ローカルのサーバー(デーモンと呼ばれてる) <item>ネットワークサービスを行うサーバー(ネットワーク・デーモンと呼ばれること もある) <item>CGI スクリプト。 CGI スクリプトは、ネットワークサービスを行うサーバーとしては特殊な例に 当たる。しかしよく使用されているので、独立した分野として扱うことにする。 Web サーバーが CGI スクリプトを動かす。攻撃の内いくつかのものは Web サーバーがフィルタリングするが、CGI スクリプト側で対処しなければならない 攻撃も数多くある <item>setuid/setgid されたプログラム。 これらのプログラムは、そのマシンを使っているユーザが実行する。実行される とそのプログラムのオーナーやオーナーの所属するグループの権限が与えられる。 様々な理由で、安全面からするとこれらは非常にやっかいなプログラムである。 というのも、入力の大部分は信頼できないユーザが操っており、中には誰が入力 したのかわからないものもある </itemize> <p> <!-- This paper merges the issues of these different types of program into a single set. The disadvantage of this approach is that some of the issues identified here don't apply to all types of program. In particular, setuid/setgid programs have many surprising inputs and several of the guidelines here only apply to them. However, things are not so clear-cut, because a particular program may cut across these boundaries (e.g., a CGI script may be setuid or setgid, or be configured in a way that has the same effect). The advantage of considering all of these program types together is that we can consider all issues without trying to apply an inappropriate category to a program. As will be seen, many of the principles apply to all programs that need to be secured. --> このドキュメントでは、上記の異なった種類のプログラムの問題点を一切合財まと めてしまいます。 このやり方の欠点は、指摘された問題の中にはすべての種類のプログラムに当て はまるとは限らないものも含まれているということです。 特に setuid/setgid されたプログラムは、予想できないような入力を受け取るため、 ガイドラインのいくつかは setuid/setgid されたプログラムにしか当てはまりま せん。 しかし実際はそんなに割り切れるものではありません。というのも、ある種のプロ グラムはいくつかの範疇にまたがっているからです(たとえば、 CGI スクリプトは setuid/setgid されているかもしれないし、setuid/setgid と同様な効果が出るよう に設定されているかもしれません)。 プログラムの種類すべてをまとめて考えることの長所は、プログラムの分類を間違え たりすることなくすべての問題を検討できる点にあります。 これから見ていくことになりますが、原則の多くは安全性が必要となるプログラム すべてに当てはまります。 <p> <!-- There is a slight bias in much of this paper towards programs written in C, with some notes on other languages such as C++, Perl, Python, Ada95, and Java. This is because C is the most common language for implementing secure programs on Linux (other than CGI scripts, which tend to use Perl), and most other languages' implementations call the C library. This is not to imply that C is somehow the ``best'' language for this purpose, and most of the principles described here apply regardless of the programming language used. --> このドキュメントは、C で書かれたプログラムに多少かたよる傾向にありますが、 C++ や、Perl、Python、Ada95、Java などについても多少は触れています。 これは C が 安全なプログラムを Linux で実装するのに最もポピュラーな言語 だからです(CGI スクリプトは例外です。Perl がよく使われています)。他の言語 であっても、その実装は C で行っている場合がほとんどです。 だからといって、C が安全なプログラムを書くための「最良の」言語である わけではありません。ここで述べられている原則の多くは、使用されているプログラ ミング言語によらず適用できます。 <!-- <sect1>Paranoia is a Virtue --> <sect1>疑い深く、こだわりが強いことは美徳です <p> <!-- The primary difficulty in writing secure programs is that writing them requires a different mindset, in short, a paranoid mindset. The reason is that the impact of errors (also called defects or bugs) can be profoundly different. --> まず安全性が求められるプログラムを書くに当たってやっかいな点は、その着眼点 が普通のプログラムと違うところです。簡単にいうと、疑い深く、こだわりを強く 持つ必要があるということです。 というのも、エラー(欠陥とかバグとも呼ばれています)が生じた時に、システム に与える影響が普通のプログラムとはまったく違うからです。 <p> <!-- Normal non-secure programs have many errors. While these errors are undesirable, these errors usually involve rare or unlikely situations, and if a user should stumble upon one they will try to avoid using the tool that way in the future. --> 安全性が求められない普通のプログラムは、エラーをたくさん抱えています。 もちろんこれらのエラーは好ましくないものですが、たいていはほとんど起こら ないものだったり、起こったとしても非常にまれなケースだったりします。仮に 起こったとしても、ユーザは偶然に出くわしてしまったはずで、そのバグを何とか 避けながら利用し続けようとすると思います。 <p> <!-- In secure programs, the situation is reversed. Certain users will intentionally search out and cause rare or unlikely situations, in the hope that such attacks will give them unwarranted privileges. As a result, when writing secure programs, paranoia is a virtue. --> 安全性が求められるプログラムでは、この状況が一変します。 とあるユーザは、意図的にバグを捜し出して、本当にまれにしか起こらない状況を つくり出します。そして攻撃することによって不当な権限を得ようとします。 つまり、安全なプログラムを書くのに当たっては、疑い深く、こだわりを強く持つ ことが美徳になるのです。 </sect1> <!-- <sect1>Sources of Design and Implementation Guidelines --> <sect1>設計と実装を行うに当たってのガイドラインとなる情報源について <p> <!-- Several documents help describe how to write secure programs (or, alternatively, how to find security problems in existing programs), and were the basis for the guidelines highlighted in the rest of this paper. --> 安全性が求められるプログラムを書くため(もしくは既存のプログラムのセキュ リティ上の問題点を見つけるため)に、様々なドキュメントが書かれています。 これらのドキュメントは、これからこのドキュメントで明らかにしていくガイド ラインの根拠になっています。 <p> <#unless output=html> <!-- For general-purpose servers and setuid/setgid programs, there are a number of valuable documents (though some are difficult to find without having a reference to them). AUSCERT has released a programming checklist [AUSCERT 1996], based in part on chapter 22 of Garfinkel and Spafford's book discussing how to write secure SUID and network programs [Garfinkel 1996]. Matt Bishop [1996, 1997] has developed several extremely valuable papers and presentations on the topic. Galvin [1998a] described a simple process and checklist for developing secure programs; he later updated the checklist in Galvin [1998b]. Sitaker [1999] presents a list of issues for the ``Linux security audit'' team to search for. Shostack [1999] defines another checklist for reviewing security-sensitive code. The <it>Secure Unix Programming FAQ</it> also has some useful suggestions [Al-Herbish 1999]. Some useful information is also available from Ranum [1998]. Some recommendations must be taken with caution, for example, Anonymous [unknown] recommends the use of access(3) without noting the dangerous race conditions that usually accompany it. Wood [1985] has some useful but dated advice in its ``Security for Programmers'' chapter. Bellovin [1994] and FreeBSD [1999] also include useful guidelines. --> 汎用的なサーバーや setuid/setgid されたプログラムを対象に、数多くの役に立つ ドキュメントがあります(しかし中には参考文献がないと見つけることが困難な ものもあります)。 AUSCERT(オーストラリアのコンピュータ緊急対策チーム)はプログラミングに当たっ てのチェックリスト [AUSCERT 1996] を公開しています。このチェックリストは suid されたプログラムやネットワーク関連のプログラムをいかに安全にするかに ついて論じた [Garfinkel 1996] の 22 章の部分をベースにしています。 Matt Bishop [1996, 1997] でこのトピックに関連して、非常に有益なドキュメント を発表しています。 Galvin [1998a] では、安全が必要とされているプログラムの開発のためのシンプル な開発プロセスとチェックリストについて記述しています。後に Galvin [1998b] でチェックリストのアップデートを行っています。 Sitaker [1999] では「Linux security audit」(Linux セキュリティ監査)チーム が調査する問題に関してのリストを提示しています。 Shostack [1999] ではセキュリティを重要視するコードをレビューする場合の チェックリストを上記とは別に提示しています。 The <it>Secure Unix Programming FAQ</it> も役に立つ内容です [Al-Herbish 1999]。 Ranum [1998] からも有益な情報がいくつか得られます。 推奨されていることの中には、注意が必要なものもあります。たとえば Anonymous [unknown] では、通常でも起こりうる危険な競合状態を起こり得ないもの として、access(3)の使用を推奨しています。 Wood [1985] の中の「Security for Programmers」の章は役に立ちますが、少々 古い内容になってしまいました。 Bellovin [1994] と FreeBSD [1999] にも役に立つガイドラインがあります。 <p> <!-- There are many documents giving security guidelines for programs using the Common Gateway Interface (CGI) to interface with the web. These include Gundavaram [unknown], Kim [1996], Phillips [1995], Stein [1999], and Webber [1999]. --> Web とのインターフェースとなる CGI(Common Gateway Interface)については、 プログラミングをする際に必要になるセキュリティのガイドラインを示した ドキュメントが多数あります。Gundavaram [unknown]、Kim [1996]、Phillips [1995]、 Stein [1999]、Webber [1999] などがあげられます。 </#unless> <#if output=html> <!-- AUSCERT has released a programming checklist --> AUSCERT はプログラムに当たってのチェックリストを公開しています。 <htmlurl url="ftp://ftp.auscert.org.au/pub/auscert/papers/secure_programming_checklist" name="[AUSCERT 1996]">, <!-- based in part on chapter 22 of Garfinkel and Spafford's book discussing how to write secure SUID and network programs --> このチェックリストは suid されたプログラムやネットワーク関連のプログラムを いかに安全にするかについて論じた Garfinkel、Spafford 各氏の 22 章の部分を ベースにしています。 <htmlurl url="http://www.oreilly.com/catalog/puis" name="[Garfinkel 1996]">. <!-- Matt --> Matt 氏は、 <htmlurl url="http://olympus.cs.ucdavis.edu/~bishop/secprog.html" name="Bishop [1996, 1997]"> <!-- has developed several extremely valuable papers and presentations on the topic. --> でこのトピックに関連して、非常に役に立つドキュメントを発表しています。 <!-- <htmlurl url="http://www.sunworld.com/swol-04-1998/swol-04-security.html" name="Galvin [1998a]"> described a simple process and checklist for developing secure programs; he later updated the checklist in --> <htmlurl url="http://www.sunworld.com/swol-04-1998/swol-04-security.html" name="Galvin [1998a]"> は、安全なプログラムの開発のためのシンプル な開発プロセスとチェックリストについて記述しています。 <htmlurl url="http://www.sunworld.com/sunworldonline/swol-08-1998/swol-08-security.html" name="Galvin [1998b]">. <htmlurl url="http://www.pobox.com/~kragen/security-holes.html" name="Sitaker [1999]"> <!-- presents a list of issues for the ``Linux security audit'' team to search for. --> は、「Linux セキュリティ監査」チームが調査する問題に関してのリストを提示 しています。 <htmlurl url="http://www.homeport.org/~adam/review.html" name="Shostack [1999]"> <!-- defines another checklist for reviewing security-sensitive code. The <it>Secure Unix Programming FAQ</it> also has some useful suggestions --> では、セキュリティを重要視するコードをレビューする場合のチェックリストを 上記とは別に提示しています。 The <it>Secure Unix Programming FAQ</it> も役に立つ内容です <htmlurl url="http://www.whitefang.com/sup/" name="[Al-Herbish 1999]">. <!-- Some useful information is also available from --> <htmlurl url="http://www.clark.net/pub/mjr/pubs/pdf/" name="Ranum [1998]">. <!-- Some recommendations must be taken with caution, for example, --> からも有益な情報がいくつか得られます。 <htmlurl url="http://www.homeport.org/~adam/setuid.7.html" name="Anonymous [unknown]"> <!-- recommends the use of access(3) without noting the dangerous race conditions that usually accompany it. Wood [1985] has some useful but dated advice in its ``Security for Programmers'' chapter. --> は、通常でも起こりうる危険な競合状態を起こり得ないものとして、access(3)の 使用を推奨しています。 Wood [1985] の中の「Security for Programmers」の章は役に立ちますが、少々 古い内容になってしまいました。 <htmlurl url="http://www.research.att.com/~smb/talks" name="Bellovin [1994]"> <!-- and --> と <htmlurl url="http://www.freebsd.org/security/security.html" name="FreeBSD [1999]"> <!-- also include useful guidelines. --> にも役に立つガイドラインがあります。 <p> <!-- There are many documents giving security guidelines for programs using the Common Gateway Interface (CGI) to interface with the web. These include --> Web とのインターフェースとなる CGI(Common Gateway Interface)については、 プログラミングをする際に必要になるセキュリティのガイドラインを示した ドキュメントが多数あります。 <htmlurl url="http://language.perl.com/CPAN/doc/FAQs/cgi/perl-cgi-faq.html" name="Gundavaram [unknown]">, <htmlurl url="http://www.eekim.com/pubs/cgibook" name="Kim [1996]">, <htmlurl url="http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txt" name="Phillips [1995]">, <htmlurl url="http://www.w3.org/Security/Faq/www-security-faq.html" name="Stein [1999]">, <!-- and --> <htmlurl url="http://www.webbertech.com/tips/web-security.html" name="Webber [1999]">. </#if> <p> <!-- There are also many documents describing the issue from the other direction (i.e., ``how to crack a system''). One example is McClure [1999], and there's countless amounts of material from that vantage point on the Internet. --> 別の観点(つまり「システムをクラックするには」等)からこの問題を扱った ドキュメントもたくさんあります。 たとえば McClure [1999] がそれにあたります。インターネットの利点を生かして、 他にも数え切れないほどの資料があふれています。 <p> <!-- This paper is a summary of what I believe are the most useful guidelines; it is not a complete list of all possible guidelines. The organization presented here is my own (every list has its own, different structure), and the Linux-unique guidelines (e.g., on capabilities and the fsuid value) are also my own. Reading all of the referenced documents listed above as well is highly recommended. --> このドキュメントは、有益に違いないと私が判断したガイドラインをまとめました。 そのため、考えられるすべてを網羅したものではありません。 私自身が編集したもの(おまけにリストそれぞれが独自の構成を持っています) ですし、 Linux 固有のガイドライン(たとえばケイパビリティについてや fsuid の値等)についても同様です。 上記すべてのドキュメントを是非参照してください。 <p> <bf>訳註:</bf>ケイパビリティとは、オペレーティングシステムやハードウェア (CPU)が持つ、セキュリティやアクセス・コントロールを実現するしくみ。 fsuid とは、ファイルシステムをチェックする場合に使用するユーザー識別機能。 <p> <!-- One question that could be asked is ``why did you write your own document instead of just referring to other documents?'' There are several answers: --> 「他人のドキュメントを引用するだけでなく、自分でドキュメントを書いたのはなぜ ですか?」 という疑問をお持ちになったかもしれません。理由はいくつかあります。 <itemize> <!-- <item>Much of this information was scattered about; placing the critical information in one organized document makes it easier to use. <item>Some of this information is not written for the programmer, but is written for an administrator or user. <item>Some information isn't relevant to Linux. For example, many checklists warn against setuid shell scripts; since Linux doesn't permit them in the normal case, there's no need to warn against them. <item>Much of the available information emphasizes portable constructs (constructs that work on all Unix-like systems). It's often best to avoid Linux-unique abilities for portability's sake, but somethimes the Linux-unique abilities can really aid security. Even if non-Linux portability is desired, you may want to support Linux-unique abilities on Linux. <item>This approach isn't unique. Other operating systems, such as FreeBSD, have a security programming guide specific to their operating system. --> <item>情報の多くがあちこちに分散してしまっている。重要な情報は、整理 して 1 つのドキュメントとしてまとめておくと便利 <item>中には、プログラマのためではなく、システム管理者や一般ユーザ向け に書かれたドキュメントがある <item>Linux に関係ないドキュメントがある。たとえば setuid されたシェル スクリプトに対しての注意点をあげてあるチェックリストが多い。しかし Linux では普通そのようなスクリプトを実行できないので、注意をうながす必要がない <item>どのシステム(UNIX ライクなシステムすべて)でも適用できる項目が強調 されている場合が多い。 ポータビリティを重視するならば、Linux 固有の機能を使用しないことが一番。 しかし固有の機能を使うことで、セキュリティが確保できるのもまた事実である。 Linux 以外のオペレーティングシステムとのポータビリティが必要であっても、 Linux 固有の機能を使うことも選択肢として残されている <item>このアプローチのしかたは、何も Linux だけが行っているわけではない。 他のオペレーティングシステム、たとえば FreeBSD でもセキュリティを守る ための独自のプログラミング・ガイドが用意されている </itemize> </sect1> <!-- <sect1>Document Conventions --> <sect1>このドキュメントでの表記 <p> <!-- System manual pages are referenced in the format <it>name(number)</it>, where <it>number</it> is the section number of the manual. C and C++ treat the character '\0' (ASCII 0) specially, and this value is referred to as NIL in this paper. The pointer value that means ``does not point anywhere'' is called NULL; C compilers will convert the integer 0 to the value NULL in most circumstances, but note that nothing in the C standard requires that NULL actually be implemented by a series of all-zero bits. --> システムにあるマニュアル(man)のページは<it>名称(番号)</it>の形式で参照します。 <it>番号</it>は、マニュアルのセクション番号を表しています。 C と C++ は「\0」(ASCII の 0)を特別扱いするので、このドキュメントでは「NIL」 と表記します。 「どこも指していない」ポインタ値は、「NULL」と表記します。C コンパイラは 通常、整数の 0 を NULL として扱いますが、NULL をすべてのビットが 0 という 実装にするようにと C の規格が規定しているわけではありません。 </sect1> </sect> <!-- <sect>Summary of Linux Security Features --> <sect>Linux のセキュリティ機能についての概要 <p> <!-- Before discussing guidelines on how to use Linux security features, it's useful to know what those features are from a programmer's viewpoint. This section briefly describes those features; if you already know what those features are, please feel free to skip this section. --> Linux のセキュリティ機能についてのガイドラインを検討する前に、プログラマ の観点でそれらの機能を理解しておきましょう。 このセクションではそれらの機能について概観します。すでに理解されている場合 は読み飛ばしてください。 <p> <!-- Many programming guides skim briefly over the security-relevant portions of Linux and skip important information. In particular, they often discuss ``how to use'' something in general terms but gloss over the security attributes that affect their use. Conversely, there's a great deal of detailed information in the manual pages about individual functions, but the manual pages sometimes obscure the forest with the trees. This section tries to bridge that gap; it gives an overview of the security mechanisms in Linux that are likely to be used by a programmer. This section has more depth than the typical programming guides, focusing specifically on security-related matters, and points to references where you can get more details. Unix programmers will be in familiar territory, but there are several Linux extensions and specifics that may surprise them. This section will try to point out those differences. --> プログラミング・ガイドの多くは、Linux のセキュリティ関連の項目を軽く 済ましてしまい、大切な情報を省いてしまっています。 特に「どうやって使用するのか」をかいつまんで説明する場合が多く、 その機能を使用することによって生じるセキュリティ上の問題については、 うわべの説明にしか行っていません。 逆に個々の機能については、マニュアルの該当するページに詳細な情報がたくさん 書かれています。しかし、マニュアルページの記述は詳細すぎて全体像の把握を 困難にしがちです。 このセクションでは、そのギャップを埋めようと思います。プログラマが使いそう な Linux におけるセキュリティのしくみを概観します。 一般的なプログラミング・ガイドよりもう少し深くセキュリティに関する事項に 焦点を当て、さらに詳細な情報が得られるよう、参考文献をあげたいと思います。 UNIX でプログラミングをされた方々にとっては、すでにおなじみのことですが、 Linux で拡張された機能や固有の機能もいくつかあります。その機能にびっくり するかもしれません。 このセクションではそれらの相違点を明らかにしていきます。 <p> <!-- First, the basics. Linux is fundamentally divided into two parts: the Linux kernel (along with its kernel modules) and ``user space'' in which various programs execute on top of the kernel. When users log in, their usernames are mapped to integers marking their ``UID'' (for ``user id'') and the ``GID''s (for ``group id'') that they are a member of. UID 0 is a special privileged user (role) traditionally called ``root,'' who can overrule most security checks and is used to administrate the system. Processes are the only ``subjects'' in terms of security (that is, only processes are active objects). Processes can access various data objects, in particular filesystem objects (FSOs), System V Interprocess Communication (IPC) objects, and network ports. The next few sections detail this. --> まずは基本的なところから。 本来 Linux とは 2 つの部分から成り立っていて、それぞれ Linux カーネル (及びカーネル・モジュール)と「ユーザー空間」と呼ばれています。ユーザ空間は カーネル上にあり、そこで様々なプログラムが動いています。 ユーザがログインすると、ユーザ名はそのユーザが属している uid(ユーザ ID)と gid(グループ ID)を表す整数値に割り当てられます。 uid が 0 のユーザは特別な権限(役割)を持っていて、「root」と言われています。 root はセキュリティ・チェックをほとんど受けることがなく、システム管理を 行う場合に使用されるユーザです。 セキュリティから見て唯一「対象」となるもの、それがプロセスです(つまり、 いろいろなことを実行している正体は、プロセスそのものなのです)。 プロセスは様々なデータにアクセスします。それはファイルシステム(FSO)で あったり、System V のプロセス間通信(IPC)であったり、ネットワーク・ポート であったりします。 もう少しこの点について、詳しく見ていくことにしましょう。 <!-- <sect1>Processes --> <sect1>プロセスとは <p> <!-- In Linux, user-level activities are implemented by running processes. Many systems support separate ``threads''; in Linux, different threads may be implemented by using multiple processes (the Linux kernel then performs optimizations to get thread-level speeds). --> Linux ではユーザ・レベルでの動作をプロセスを動かすことで実現しています。 独立した「スレッド」をサポートするシステムが多いのですが、Linux では スレッドそれぞれを複数のプロセスとして走らせて実現しているようです(Linux カーネルは最適化をはかることによって、スレッド並の実行速度を稼いでいます)。 <p> <bf>訳註:</bf>Linux のスレッドはユーザ・レベルではなく、カーネル・レベル のスレッドで、カーネルがスレッドの制御を行っています。fork() と同じく 子プロセスを起こしますが、コンテキストの何を親プロセスと共有できるかを 指定できます。 <!-- <sect2>Process Attributes --> <sect2>プロセスが持っている属性 <p> <!-- Every process has a set of security-relevant attributes, including the following: --> それぞれのプロセスは、次のようなセキュリティ関連の属性を持っています。 <itemize> <!-- <item>RUID, RGID - real UID and GID of the user on whose behalf the process is running <item>EUID, EGID - effective UID and GID used for privilege checks (except for the filesystem) <item>FSUID, FSGID - UID and GID used for filesystem access checks; this is usually equal to the EUID and EGID respectively. This is a Linux-unique attribute. <item>SUID, SGID - Saved UID and GID; used to support switching permissions ``on and off'' as discussed below. <item>groups - a list of groups (GIDs) in which this user has membership. <item>umask - a set of bits determining the default access control settings when a new filesystem object is created; see umask(2). <item>scheduling parameters - each process has a scheduling policy, and those with the default policy SCHED_OTHER have the additional parameters nice, priority, and counter. See sched_setscheduler(2) for more information. <item>capabilities - POSIX capability information; there are actually three sets of capabilities on a process: the effective, inheritable, and permitted capabilities. See below for more information on POSIX capabilities. <item>limits - per-process resource limits (see below). <item>filesystem root - the process' idea of where the root filesystem begins; see chroot(2). --> <item>ruid、rgid - 実ユーザ ID と 実グループ IDのことで、プロセス を実際に走らせているユーザを表す <item>euid、egid - 実効ユーザ ID と 実効グループ IDのことで、権限のチェック のために用いる(ファイルシステムは除く) <item>fsuid、fsgid - ファイルシステムへのアクセス権限をチェックするために 用いる。通常 euid、egid と等しい。 この属性は Linux 独自である <item>suid、sgid - 保存ユーザ ID と 保存グループ ID。パーミッションを「オン」 もしくは「オフ」にする場合に使用する。詳しくは後述する <item>groups - ユーザが属しているグループ(GID)のリスト <item>umask - 新しくファイルやディレクトリを作る場合に、そのデフォルトのアク セス制限を設定するのに使用されるビット値。umask(2)を参照のこと <item>スケジューリングを設定するパラメタ - プロセスはそれぞれのスケジュー リング方針にもとづいて動いており、デフォルトの方針は SCHED_OTHER である。 SCHED_OTHER はパラメタとして nice 値、優先度(priority)とカウンタを 持っている。詳細は sched_setscheduler(2)を参照のこと <p> <bf>訳註:</bf>ここで述べられている「カウンタ」とは、プロセスの実行履歴 を計測するために用いられるカウンタを意味します。 <p> <item>ケイパビリティ - POSIX で定義されているケイパビリティ情報。セキュリ ティ関連の機能として、実効、継承、許可の 3 種類の機能がある。詳しくは 下記参照のこと <item>limit - プロセス単位にそのプロセスが使用できるリソースを制限する (下記参照) <item>ファイルシステムのルートの位置 - プロセスから見たルート・ファイルシス テムの位置。chroot(2)参照のこと <item> </itemize> <p> <!-- If you really need to know exactly what attributes are associated with each process, examine the Linux source code, in particular include/linux/sched.h's definition of task_struct. --> 属性とプロセスが実際どのように関連しているのかを知りたければ、Linux の ソース・コードを参照してください。include/linux/sched.h で定義されている 構造体の task_struct がキーポイントです。 </sect2> <!-- <sect2>POSIX Capabilities --> <sect2>POSIX ケイパビリティ <p> <!-- Linux version 2.2 added internal support for ``POSIX Capabilities.'' POSIX capabilities supports some splitting of the privileges typically held by root into a larger set of more specific privileges. POSIX capabilities are defined by a draft IEEE standard; they're not unique to Linux but they're not universally supported by other Unix-like systems either. When Linux documentation (including this one) says ``requires root privilege'', in nearly all cases it really means ``requires a capability'' as documented in the capability documentation. If you need to know the specific capability required, look it up in the capability documentation. --> Linux カーネル 2.2 の機能として「POSIX ケイパビリティ」がサポートされて います。 POSIX のケイパビリティは、通常 root が持っている権限をいくつかに分割して、 独自に権限の体系を再構成しています。 POSIX ケイパビリティは、IEEE(米国電気電子通信学会)標準のドラフトで定義されて います。したがって Linux 固有の機能ではありませんが、他の UNIX ライクなシス テムで広く採用されているわけではありません。 Linux のドキュメント(このドキュメントも含め)の中で、「root の権限が必要で ある」と書いてあった場合、「ケイパビリティが必要である」とほぼ同じ意味に なる、とケイパビリティについてのドキュメントに述べられています。 個々のケイパビリティについて知りたい場合は、下記のケイパビリティに関する ドキュメントを読んでください。 <p> <!-- The eventual intent is to permit capabilities to be attached to files in the filesystem; as of this writing, however, this is not yet supported. There is support for transferring capabilities, but this is disabled by default. Linux version 2.2.11 added a feature that makes capabilities more directly useful, called the ``capability bounding set.'' The capability bounding set is a list of capabilities that are allowed to be held by any process on the system (otherwise, only the special init process can hold it). If a capability does not appear in the bounding set, it may not be exercised by any process, no matter how privileged. This feature can be used to, for example, disable kernel module loading. A sample tool that takes advantage of this is LCAP at <url url="http://pweb.netcom.com/~spoon/lcap/">. --> ファイルシステム上にある各ファイル毎にケイパビリティが適用されることが 最終的な目標なのですが、このドキュメントを書いている時点ではまだサポート されていません。 転送機能に対するケイパビリティはサポートされていますが、デフォルトでは無効 になっています。 カーネル 2.2.11 ではケイパビリティを更に身近に使いやすくするしくみである 「ケイパビリティ・バウンディング・セット(capability bounding set)」が取り 入れられました。 このしくみは、システム上で稼動しているすべてのプロセスが利用できるケイパ ビリティのリストを用意します(特別な init プロセスだけが利用できるケイパ ビリティもあります)。 あるケイパビリティがリストにない場合、権限がどうであれ、どのプロセスもその ケイパビリティを利用できません。 この機能を使っている例として、カーネルモジュールの読み込みを無効にする場合 があげられます。 またうまくこの機能を活用しているツールとして、 <url url="http://pweb.netcom.com/~spoon/lcap/"> にある LCAP があげられます。 <p> <bf>訳註:</bf>LCAP は、カーネルがサポートしているケイパビリティを無効にする ことによって、システムをより安全にするしくみです。 <p> <!-- More information about POSIX capabilities is available at <url url="ftp://linux.kernel.org/pub/linux/libs/security/linux-privs">. --> POSIX ケイパビリティの詳細については、 <url url="ftp://linux.kernel.org/pub/linux/libs/security/linux-privs"> を参照してください。 <p> <bf>訳註:</bf>上記 ftp サーバーは anonymous ユーザの利用を認めていません。 <url url="ftp://ftp.kernel.org/pub/linux/libs/security/linux-privs"> を利用してください。 </sect2> <!-- <sect2>Process Creation and Manipulation --> <sect2>プロセスの作成とその操作 <p> <!-- Processes may be created using fork(2), the non-recommended vfork(2), or the Linux-unique clone(2); all of these system calls duplicate the existing process, creating two processes out of it. A process can execute a different program by calling execve(2), or various front-ends to it (for example, see exec(3), system(3), and popen(3)). --> プロセスは fork(2)もしくは vfork(2)(使用しない方がよい)、clone(2)(Linux 独自) を使って作成します。これらのシステムコールすべては、既存のプロセスを コピーして、2 つのプロセスを生成します。 プロセスは execve(2)やそのフロントエンドをコールして、別々のプログラムを実行 できます(フロントエンドとして、exec(3)、system(3)、popen(3)を参照してくだ さい)。 <p> <!-- When a program is executed, and its file has its setuid or setgid bit set, the process' EUID or EGID (respectively) is set to the file's. Note that under Linux this does not occur with ordinary scripts such as shell scripts, because there are a number of security dangers when trying to do this with scripts (some other Unix-like systems do support setuid shell scripts). As a special case, Perl includes a special setup to support setuid Perl scripts. --> あるプログラムを実行する時にファイルに setuid ビットが立っていると、 そのプロセスの euid にはファイルの uid が設定されます。 setgid が立っていると egid にファイルの gid が設定されます。 Linux 上では、シェルスクリプトのようなスクリプト全般に対して、このような ビットの設定はされないことを忘れないでください。 このようなことがスクリプトで設定できてしまうと、セキュリティ上非常に危険な ことになるからです(UNIX ライクなシステムの中には setuid されているスクリプト が動くものもあります)。 例外として、 Perl は特別な設定をほどこすと、setuid されている Perl スクリプト が実行できるようになります。 <p> <!-- In some cases a process can affect the various UID and GID values; see setuid(2), seteuid(2), setreuid(2), setfsuid(2). In particular the SUID attribute is there to permit trusted programs to temporarily switch UIDs. If the RUID is changed, or the EUID is set to a value not equal to the RUID, the SUID is set to the new EUID. Unprivileged users can set their EUID from their SUID, the RUID to the EUID, and the EUID to the RUID. --> 場合によって、プロセスはいくつかある uid や gid の値を変更できます。 setuid(2)、seteuid(2)、setreuid(2)、setfsuid(2)を参照してください。 特に suid の場合は、信頼できるプログラムが一時的にその uid 値を変更できます。 ruid の変更もしくは euid が ruid と異なる値にした場合は suid には新しい euid の値が設定されます。 特権をもたないユーザは、自分の suid から自分の euid を、ruid から euid を、 euid から ruid を設定できます。 <p> <!-- The FSUID process attribute is intended to permit programs like the NFS server to limit themselves to only the filesystem rights of some given UID without giving that UID permission to send signals to the process. Whenever the EUID is changed, the FSUID is changed to the new EUID value; the FSUID value can be set separately using setfsuid(2), a Linux-unique call. Note that non-root callers can only set FSUID to the current RUID, EUID, SEUID, or current FSUID values. --> fsuid プロセス属性は、NFS サーバのようなプログラムの権限を、指定された いくつかの UID のファイルシステム権限に制限できるようにするためのものです。 この際、その UID にはプロセスへシグナルを送れる許可は与えません。 euid が変更されると fsuid は新しい euid の値に変更されます。fsuid は setfsuid(2)という Linux 固有のシステムコールを使って設定することもできます。 root 以外から呼び出された場合は、fsuid には現在の ruid 値、euid 値、seuid 値、 あるいは現在の fsuid 値しか設定できません。 </sect2> </sect1> <!-- <sect1>Filesystem --> <sect1>ファイルシステム <p> <!-- Filesystem objects (FSOs) may be ordinary files, directories, symbolic links, named pipes (FIFOs), sockets, character special (device) files, or block special (device) files (this list is shown in the find(1) command). Filesystem objects are collected on filesystems, which can be mounted and unmounted on directories in the filesystem; filesystems may have slightly different sets of access control attributes and access controls can be affected by options selected at mount time. --> ファイルシステムの構成要素(FSO)は、通常のファイル、ディレクトリ、シンボリック リンク、名前付きパイプ(FIFO)、ソケット、キャラクタスペシャル(デバイス) ファイル、ブロックスペシャル(デバイス)ファイルがあります(find(1)コマンドに その一覧があります)。 これらはファイルシステムによって制御され、ファイルシステムを構成するディレ クトリ上でマウント/アンマウントして利用します。 ファイルシステム自身は、これら構成要素とは多少異なるアクセス制限の属性を 持っていて、マウント時にオプションを設定することによって、アクセス制限を かけることが可能です。 <!-- <sect2>Filesystem Object Attributes --> <sect2>ファイルシステムの構成要素の属性 <p> <!-- Currently ext2 is the most popular filesystem on Linux systems; it supports the following attributes on each filesystem object: --> 今のところ Linux では ext2 が最も一般的なファイルシステムです。ファイルシス テムの構成要素が持っている属性は下記の通りです。 <itemize> <!-- <item>owning UID and GID - identifies the ``owner'' of the filesystem object. Only the owner or root can change the access control attributes unless otherwise noted. <item>read, write, execute bits for each of user (owner), group, and other. For ordinary files, read, write, and execute have their typical meanings. In directories, the ``read'' permission is necessary to display a directory's contents, while the ``execute'' permission is sometimes called ``search'' permission and is necessary to actually enter the directory to use its contents. In a directory ``write'' permission on a directory permits adding, removing, and renaming files in that directory; if you only want to permit adding, set the sticky bit noted below. Note that the permission values of symbolic links are never used; it's only the values of their containing directories and the linked-to file that matter. <item>``sticky'' bit - when set on a directory, unlinks (removes) are limited to root, the file owner, or the directory owner. This is a very common Unix extension, though not quite universal. The sticky bit has no affect on ordinary files and ordinary users can turn on this bit. Old versions of Unix called this the ``save program text'' bit and used this to indicate executable files that should stay in memory; Linux's virtual memory management makes this use irrelevant. <item>setuid, setgid - when set on an executable file, executing the file will set the process' effective UID or effective GID to the value of the file's owning UID or GID (respectively). All Unix-like systems support this. When setgid is set on a directory, files created in the directory will have their GID automatically reset to that of the directory's GID. When setgid is set on a file that does not have any execute privileges, this indicates a file that is subject to mandatory locking during access (if the filesystem is mounted to support mandatory locking); this overload of meaning surprises many and not universal across Unix-like systems. <item>timestamps - access and modification times are stored for each filesystem object. However, the owner is allowed to set these values arbitrarily (see touch(1)), so be careful about trusting this information. All Unix-like systems support this. <item>immutable bit - no changes to the filesystem object are allowed; only root can set or clear this bit. This is only supported by ext2 and is not portable across all Unix systems (or even all Linux filesystems). <item>append-only bit - only appending to the filesystem object are allowed; only root can set or clear this bit. This is only supported by ext2 and is not portable across all Unix systems (or even all Linux filesystems). --> <item>所有 uid と gid - これを使って、構成要素の「所有者」を識別できる。 特別な設定をしなければ、普通所有者もしくは root だけがアクセス制限に 関する属性を変更できる <item>ユーザ(所有者)、グループそれ以外毎に、読み込み/書き込み/実行の権限 を表すビットがある。 通常のファイルの場合は、読み/書き/実行という文字通りの意味を持つ。 ディレクトリの場合は、「読み込み」パーミッションはそのディレクトリの中を 見られること意味し、「実行」パーミッションは、別名「検索」パーミッション とも言われ、実際にそのディレクトリに入って、そこにあるものを使用すること ができる。 「書き込み」パーミッションはそのディレクトリでファイルの追加、削除、変更 ができる。追加だけを許可させたい場合は、下記に説明する sticky ビットを 立てること。 シンボリックリンクのパーミッションは意味を持たないことに注意すること。 意味を持つのは、シンボリックリンクを含むディレクトリとリンク先のファイル の値だけである <item>「sticky ビット」 - ディレクトリに設定されると、削除や移動は root、 ファイルの所有者、もしくはディレクトリの所有者しか行えなくなる。 これは UNIX 一般で利用されている拡張機能だが、その他のオペレーティング システムでは一般的ではない。 sticky ビットは、通常のファイルに対しては何の影響も与えない。また一般 ユーザでも設定ができる。 古いバージョンの UNIX では「save program text」ビットと呼ばれ、メモリ に常駐する(スワップアウトしない)実行形式ファイルであることを示していたが、 Linux が仮想メモリ管理を実装するにいたって、すたれてしまった <item>setuid、setgid - 実行形式ファイルに設定されると、実効 uid と gid に そのファイルの所有者 ID と gid が設定される(各々独立に)。 この機能はすべての UNIX ライクなシステムがサポートしている。 setgid がディレクトリに設定されると、そのディレクトリに作成されるファイル は自動的にそのディレクトリの gid 値に設定し直される。 setgid が実行権をまったく持たないファイルに設定されると、そのファイルが アクセスされている時に、強制ロック(mandatory locking)がそのファイルに かかることを示す(ただし、マウントしているファイルシステムが強制ロックを サポートしていれば)。このしくみは負荷が非常に重く、UNIX ライクなシステムで 広く採用されてはいない <p> <bf>訳註:</bf>ファイルのロック機能には、強制ロック(mandatory locking)と アドバイザリ・ロック(advisory locking)があります。違いは、前者が カーネルがプロセスを監視しロック操作を行うので、プロセス間の依存 関係を越えてロックが可能です。 これに対して後者は、プロセス自身がロック操作を行うので、その プロセスの制御外のものに対してはロックが無効となります。 詳しくは、カーネル付属のドキュメントの <url url="file:///usr/src/linux/Documentation/mandatory.txt" name="mandatory.txt"> を参照してください。 <p> <item>タイムスタンプ - ファイルシステムの構成要素には、アクセスした時間 もしくは修正をかけた時間が保存されている。しかし所有者は自由にこれら の値を変更できるので(touch(1)を参照)、この情報を安易に信頼しないこと。 このしくみは、すべての UNIX ライクのシステムでサポートされている <item>変更不可(immutable)ビット - ファイルシステムの構成要素に対していかなる 変更も認めない。 これは、root だけが設定と解除ができる。 このしくみは、ext2 ファイルシステムだけがサポートしており、すべての UNIX システム(場合によっては Linux システムでも)で利用できるわけではない <item>追加限定(append-only bit)ビット - ファイルシステムへの追加だけが許可 される。 これは、root だけが設定と解除ができる。 このしくみは、ext2 ファイルシステムだけがサポートしており、すべての UNIX システム(場合によっては Linux システムでも)で利用できるわけではない </itemize> <p> <!-- Many of these values can be influenced at mount time, so that, for example, certain bits can be treated as though they had a certain value (regardless of their values on the media). See mount(1) for more information about this. Some filesystems don't support some of these access control values; again, see mount(1) for how these filesystems are handled. --> 上記の値の多くは、マウント時に適用されます。したがって、あるビット値がすでに 値(媒体上の値が何であれ)を持っていたかのように扱われる場合もあります。 詳しいことは mount(1)を参照してください。 ファイルシステムも中にはこれらのアクセス制御値のいくつかをサポートしていない 場合がありますので、くどいようですが mount(1)を見て、ファイルシステムが何を サポートしているのかを確認してください。 <p> <!-- There is ongoing work to add access control lists (ACLs) and POSIX capability values to the filesystem, but these do not exist in stock Linux 2.2. --> アクセス制御リスト(ACL、access control list)と POSIX ケイパビリティの値を ファイルシステムへ実装する作業が続けられていますが、標準の Linux 2.2 には まだ入っていません。 <p> <bf>訳註:</bf>ACL は従来の所有者、グループ等によるファイルへのアクセス 制御方法にかわって更に細かな制御を可能とするしくみです。ネットワーク上 のサーバーに対するアクセス制限についてもこの用語が使用されています (RFC 1983)。 </sect2> <!-- <sect2>Creation Time Initial Values --> <sect2>作成時の初期値 <p> <!-- At creation time, the following rules apply. When a filesystem object (FSO) is created (e.g. via creat(2)), the FSO's UID is set to the process' FSUID. The FSO GID is usually set to the process' FSGID, though if the containing directory's setgid bit is set or the filesystem's ``GRPID'' flag is set, the FSO GID is set to the GID of the containing directory. This special case supports ``project'' directories: to make a ``project'' directory, create a special group for the project, create a directory for the project owned by that group, then make the directory setgid: files placed there are automatically owned by the project. Similarly, if a new subdirectory is created inside a directory with the setgid bit set (and the filesystem GRPID isn't set), the new subdirectory will also have its setgid bit set (so that project subdirectories will ``do the right thing.''); in all other cases the setgid is clear for a new file. FSO basic access control values (read, write, execute) are computed from (requested values & ˜ umask of process). New files always start with a clear sticky bit and clear setuid bit. --> 作成する時には次のルールが適用されます。 あるファイルシステムの構成要素(FSO)が作られると(たとえば creat(2)を使って)、 FSO の uid はプロセスの fsuid に設定されます。普通、FSO の gid はプロセスの fsuid が設定されますが、ディレクトリに setgid ビットが立っていたり、ファイル システムの「grpid」が設定してあったりすると FSO の gid には、ディレクトリの gid が設定されます。 この特殊なケースを利用することによって、いわゆる「プロジェクト」のための ディレクトリを作ることができます。「プロジェクト用」のディレクトリを作る には次のようにします。まずプロジェクト用に専用のグループを作ります。それから そのグループが所有者であるプロジェクト用のディレクトリを作成し、setgid します。こうすると、何かファイルをそこのディレクトリに置くと、自動的にその プロジェクトが所有者となります。 同様に、新しいサブディレクトリを setgid ビットを立てたディレクトリの配下に 作成すると(ファイルシステムの grpid も設定されていない)、新しいディレクトリ も setgid ビットが立てられます(したがってプロジェクトのサブディレクトリは、 「期待通りの正しい動作」をします。その他のケースは、新しいファイルに setgid はかけられていません。基本となる FSO のアクセス制限(読み込み、 書き込み、実行)は、(要求された値に umask 値を &(ビット反転) ˜(論理積))して求められます。 ファイルが新規に作成された状態では、常に sticky ビットも setuid ビットも クリアされています。 </sect2> <!-- <sect2>Changing Access Control Attributes --> <sect2>アクセス制御の属性を変更する <p> <!-- You can set most of these values with chmod(2) or chmod(1), but see also chown(1), chgrp(1), and chattr(1). --> アクセス制御の属性の大部分は、chmod(2)か chmod(1)で設定できますが、chown(1)、 chgrp(1)、chattr(1)も参照してください。 <p> <!-- Note that in Linux, only root can change the owner of a given file. Some Unix-like systems allow ordinary users to change ownership, but this causes complications. For example, if you're trying to limit disk usage, allowing such operations would allow users to claim that large files actually belonged to some other ``victim.'' --> 注意して欲しいことがあります。それは Linux では root だけがファイルの所有者 を変更することができるということです。 UNIX ライクなシステムの中には、一般ユーザも所有者の変更が行えるものがあり ますが、これは厄介事を引き起こします。たとえばディスク使用量を制限しようと したとします。その時、一般ユーザに所有者の変更を許していると、ユーザの誰かが 自分の大きなファイルを他人の所有に変更して、その人を「被害者」にしたててしま えます。 </sect2> <!-- <sect2>Using Access Control Attributes --> <sect2>アクセス制御の属性を使うには <p> <!-- Under Linux and most Unix-like systems, reading and writing attribute values are only checked when the file is opened; they are not re-checked on every read or write. A large number of calls use these attributes, since the filesystem is so central to Linux. This includes open(2), creat(2), link(2), unlink(2), rename(2), mknod(2), symlink(2), and socket(2). --> Linux と UNIX ライクなシステムのほとんどで、読み込みや書き込みの属性 の値はファイルがオープンされた時にだけチェックされます。読み書きする度 にチェックされるわけではありません。システム・コールの大多数が、これらの 属性を利用しています。というのも、ファイルシステムというものが Linux の中枢をなしているからです。 これらのシステム・コールには、open(2)、creat(2)、link(2)、unlink(2)、 rename(2)、 mknod(2)、symlink(2)、socket(2)等があります。 </sect2> <!-- <sect2>Filesystem Hierarchy --> <sect2>ファイルシステムの階層 <p> <!-- Over the years conventions have been built on ``what files to place where''; please follow them and use them when placing information in the hierarchy. A summary of this information is in hier(5). More information is available on the Filesystem Hierarchy Standard (FHS), which is an update to the previous Linux Filesystem Structure standard (FSSTND); see <url url="http://www.pathname.com/fhs"> --> 長年の慣例で、「何のファイルはどこに置く」という約束事ができています。 きまりを守って、ディレクトリ階層の中に情報を格納してください。 概略については、hier(5)を参照してください。 さらに詳しく知りたければ、Filesystem Hierarchy Standard (FHS) <url url="http://www.pathname.com/fhs"> を見てください。FHS は従来の Filesystem Structure standard (FSSTND)を新たに書き換えたものです。 </sect2> </sect1> <sect1>System V IPC <p> <!-- Linux supports System V IPC objects, that is, System V message queues, semaphore sets, and shared memory segments. Each such object has the following attributes: --> Linux は System V 由来の IPC である、メッセージ・キュー、セマフォ、共有メモリ をサポートしています。 それぞれのサービスは、下記の属性を持っています。 <itemize> <!-- <item>read and write permissions for each of creator, creator group, and others. <item>creator UID and GID - UID and GID of the creator of the object. <item>owning UID and GID - UID and GID of the owner of the object (initially equal to the creator UID). --> <item>作成者や作成者が属するグループ、それ以外の者の読み書きのパーミッション <item>作成者 uid と gid - IPC オブジェクト作成者の uid と gid <item>所有者 uid と gid - IPC オブジェクト所有者の uid と gid(初期状態では IPC オブジェクト作成者の uid と同じ) </itemize> <p> <!-- When accessing such objects, the rules are as follows: --> 下記のルールにもとづいて IPC オブジェクトアクセスします。 <itemize> <!-- <item>if the process has root privileges, the access is granted. <item>if the process' EUID is the owner or creator UID of the object, then the appropriate creator permission bit is checked to see if access is granted. <item>if the process' EGID is the owner or creator GID of the object, or one of the process' groups is the owning or creating GID of the object, then the appropriate creator group permission bit is checked for access. <item>otherwise, the appropriate ``other'' permission bit is checked for access. --> <item>プロセスが root の権限を持っていれば、アクセスが許可される <item>プロセスの euid が所有者もしくは作成者の uid と同じならば、作成者の パーミッションを見て、問題なければアクセスが許可される <item>プロセスの euid が所有者もしくは作成者の gid と同じ、もしくはプロセス の属するグループの中に所有者もしくは作成者の gid と同じものがあれば、作成者 のパーミッションを見て、問題なければアクセスが許可される <item>その他の場合は「その他のユーザ」のパーミッションをチェックする </itemize> <p> <!-- Note that root, or a process with the EUID of either the owner or creator, can set the owning UID and owning GID and/or remove the object. More information is available in ipc(5). --> root もしくは 所有者や作成者の euid を持つプロセスは、所有者の uid や gid を 設定でき、また削除も可能であることを忘れないでください。詳しくは ipc(5)を 参照してください。 </sect1> <!-- <sect1>Sockets and Network Connections --> <sect1>ソケットとネットワーク接続 <p> <!-- Sockets are used for communication, particularly over a network. Socket(2) creates an endpoint for communication and returns a descriptor; see socket(2) for more information and cross-references to other relevant information. Note that binding to TCP and UDP local port numbers less than 1024 requires root privilege in Linux (binding to a remote port number less than 1024 requires no special privilege). --> ソケットは、情報を伝える手段として特にネットワーク越しの通信に使用されて います。 socket(2)は情報を伝えるための接続ポイントを作成し、それを表わすディスクリプタ を返します。さらに詳しいことは、socket(2)やそこから相互に参照できる関連情報を 見てください。 Linux の場合、TCP や UDP で 1024 以下のローカルなポートに接続するには、root の権限が必要であることを覚えておいてください。 (リモートにある 1024 以下のポートへの接続については、特別な権限は必要ありま せん)。 </sect1> <!-- <sect1>Quotas and Limits --> <sect1>quota とリソースの制限 <p> <!-- Linux has mechanisms to support filesystem quotas and process resource limits. Be careful with terminology here, because they both have ``hard'' and ``soft'' limits but the terms mean slightly different things. --> Linux には、ファイルシステムの割り当て制限(quota)とプロセスのリソース制限 を行なう機能があります。 この機能には、「ハードな制限」(hard limit)と「ソフトな制限」(soft limit)両方 の意味があり、多少意味が異なるので、注意が必要です。 <p> <!-- You can define storage (filesystem) quota limits on each mountpoint for the number of blocks of storage and/or the number of unique files (inodes) that can be used by a given user or a given group. A ``hard'' quota limit is a never-to-exceed limit, while a ``soft'' quota can be temporarily exceeded. See quota(1), quotactl(2), and quotaon(8). --> 記憶装置(ファイルシステム)の割り当て制限は、マウントポイント毎に設定が可能で、 特定のユーザやグループがそこで使用できるブロック数やファイル数(inode数)に 制限をかけられます。 「ハードな」ものが制限を越えることができないのに対して、「ソフトな」ものは 一時的に制限を越えることが許されています。 quota(1)、quotactl(2)、quotaon(8)を参照してください。 <p> <!-- The rlimit mechanism supports a large number of process quotas, such as file size, number of child processes, number of open files, and so on. There is a ``soft'' limit (also called the current limit) and a ``hard limit'' (also called the upper limit). The soft limit cannot be exceeded at any time, but through calls it can be raised up to the value of the hard limit. See getrlimit(), setrlimit(), and getrusage(). --> rlimit は、プロセスに対する数々の割り当て制限を実現するしくみで、ファイル サイズ、子プロセス数、オープンできるファイル数などを扱えます。「ソフトな」 制限(現状の制限(current limit)とも言う)と「ハードな制限」 (上限(upper limit)とも言う)があります。 ソフトな制限を超えることは決してできませんが、システムコールによってハード な制限の上限まであげることができます。 getrlimit()、setrlimit()、getrusage()を参照してください。 </sect1> <!-- <sect1>Audit --> <sect1>Audit(監査) <p> <!-- Currently the most common ``audit'' mechanism is syslogd(8). You might also want to look at wtmp(5), utmp(5), lastlog(8), and acct(2). Some server programs (such as the Apache web server) also have their own audit trail mechanisms. --> 現在もっとも一般的な「監査」のしくみは、syslogd(8)です。 wtmp(5)、utmp(5)、lastlog(8)、acct(2)も参照することをお勧めします。 サーバー・プログラム(Apache Web サーバーのようなもの)の中には、独自に痕跡を監査 するしくみを持っているものもあります。 </sect1> <sect1>PAM <p> <!-- When authenticating, most Linux systems use Pluggable Authentication Modules (PAM). This permits configuration of authentication (e.g., use of passwords, smart cards, etc.). PAM will be discussed more fully later in this document. --> 認証が必要な時に Linux システムの大部分は Pluggable Authentication Modules (PAM: 差し替え可能な認証モジュール)を使用します。このしくみを使うと、認証 方法の構成を変更できるようになります(たとえばパスワードやスマートカード等 の使用)。 PAM については、後でさらに論じます。 <p> <bf>訳註:</bf>スマートカード(smart card)とは、プラスティックのカード上に IC やメモリなどのチップを載せたカードを指します。日本では IC カードと 呼ぶケースが多いようです。 従来の磁気カードと比べると、より多くの情報を格納できるだけではなく、 プログラムをインストールして実行することが可能である点が大きく異なり ます。 </sect1> </sect> <!-- <sect>Validate All Input --> <sect>入力されるものすべてを検証すること <p> <!-- Some inputs are from untrustable users, so those inputs must be validated (filtered) before being used. You should determine what is legal and reject anything that does not match that definition. Do not do the reverse (identify what is illegal and reject those cases), because you are likely to forget to handle an important case. Limit the maximum character length (and minimum length if appropriate), and be sure to not lose control when such lengths are exceeded (see the buffer overflow section below for more about this). --> 入力には、信頼できないユーザからのものもあります。そこで、使用する前にそれら を検査(選別)する必要があります。 まず何が正しいかを定義して、その定義にマッチしないものすべてを拒否するように しなければいけません。 その逆の定義のしかたをしてはいけません(何が不正かを定義し、それらを拒否する)。 なぜなら、重要なケースの定義をうっかり忘れてしまうかもしれないから です。 文字列長の最大値を制限してください(必要があるなら最小値も)。そして、長さを 超えてしまった場合でもシステムが暴走しないことを確かめてください (下記のバッファオーバーフローのセクションでもう少し詳しく述べますので、 見てください)。 <p> <!-- For strings, identify the legal characters or legal patterns (e.g., as a regular expression) and reject anything not matching that form. There are special problems when strings contain control characters (especially linefeed or NIL) or shell metacharacters; it is often best to ``escape'' such metacharacters immediately when the input is received so that such characters are not accidentally sent. CERT goes further and recommends escaping all characters that aren't in a list of characters not needing escaping [CERT 1998, CMU 1998]. see the section on ``limit call-outs to valid values'', below, for more information. --> 文字列の場合は、そのシステムにとって正しいキャラクタと正しいパターン(たと えば正規表現など) を明らかにしておき、その形式に合わないものすべてを拒否 するようにしてください。 文字列にコントロールキャラクタ(特に改行や NIL)やシェルのメタキャラクタが 含まれている場合、普通の文字列では起こり得ない問題が生じます。問題を避ける ために、そのようなメタキャラクタが入力されたらすぐに「エスケープ」して、 間違ってプログラムに送られることがないようにするのが一番です。 CERT はこの考え方をさらに推し進めて、エスケープする必要がないキャラクタの 一覧に載っていないものすべてをエスケープすることを推奨しています [CERT 1998, CMU 1998]。 詳細については、下記の「正しい値でだけ呼び出すこと」を参照してください。 <p> <!-- Limit all numbers to the minimum (often zero) and maximum allowed values. Filenames should be checked; usually you will want to not include ``..'' (higher directory) as a legal value. In filenames it's best to prohibit any change in directory, e.g., by not including ``/'' in the set of legal characters. A full email address checker is actually quite complicated, because there are legacy formats that greatly complicate validation if you need to support all of them; see mailaddr(7) and IETF RFC 822 [RFC 822] for more information if such checking is necessary. --> 数字すべてに対して、許容できる最小値(たいていはゼロ)と最大値を設けましょう。 ファイル名はチェックしなければいけません。一般的に「..」(上位ディレクトリ)を 正しい値と見なしてはいけません。 ファイル名を表わす場合には、ディレクトリの変更となる動作をどんな場合でも禁止 することが一番です。たとえば、「/」を正しいキャラクタの仲間に入れてはいけま せん。 電子メールのアドレスを完全にチェックすることは、現実的にとても困難です。 というのも、すべてのケースを真面目にサポートしようとすると、アドレスの中には 正しい形式ではあるものの、非常に複雑な検証を必要とするものが存在するからです。 もしそのようなチェックが必要なら、詳細は mailaddr(7)と IETF RFC 822 [RFC 822] を見てください。 <p> <bf>訳註:</bf> IETFは、Internet Engineering Task Force の略称で、インター ネットに関連する技術の標準化を進めるために設立された団体です。ここが発行 する文書が RFC(Requests For Comment)です。 <p> <!-- These tests should usually be centralized in one place so that the validity tests can be easily examined for correctness later. --> これらのテストは 1 箇所で集中して行なうようにしてください。そうすれば後で このテストに間違いがないかの調査を簡単に済ませられます。 <p> <!-- Make sure that your validity test is actually correct; this is particularly a problem when checking input that will be used by another program (such as a filename, email address, or URL). Often these tests are have subtle errors, producing the so-called ``deputy problem'' (where the checking program makes different assumptions than the program that actually uses the data). --> 正しい入力をチェックするテストが、本当に予定した通りに動作するかを確認して ください。 別のプログラムが使う入力(ファイル名や電子メールアドレス、URL 等)をチェック する場合には特に重要です。 これらのプログラムは、見落としがちな間違いを抱えていることが多く、 いわゆる「代理人問題」(データを実際に使用するプログラムとチェックするプロ グラムの前提条件が異なっているケース)です。 <p> <!-- The following subsections discuss different kinds of inputs to a program; note that input includes process state such as environment variables, umask values, and so on. Not all inputs are under the control of an untrusted user, so you need only worry about those inputs that are. --> 下記のサブセクションでは、プログラムに対する様々な入力について論じます。 この入力には環境変数や umask 値など、プロセスが持っている状態も含む点に 注意してください。 必ずしもすべての入力が信頼できないユーザによって行なわれているわけでは ありません。注意する必要があるのは信頼できないユーザからの入力だけです。 <!-- <sect1>Command line --> <sect1>コマンドライン <p> <!-- Many programs use the command line as an input interface, accepting input by being passed arguments. A setuid/setgid program has a command line interface provided to it by an untrusted user, so it must defend itself. Users have great control over the command line (through calls such as the execve(3) call). Therefore, setuid/setgid programs must validate the command line inputs and must not trust the name of the program reported by command line argument zero (the user can set it to any value including NULL). --> プログラムの中には、入力のインターフェースとして、コマンドラインを使用する ものが多数あります。この場合、引数を渡すことによって入力とします。 setuid/setgid されたプログラムは、信頼できないユーザからコマンドラインに よる入力を受け取る場合があるので、そのプログラム自身で対処する必要があります。 一般的にユーザは、コマンドラインを自由に扱えます(execve(3)のようなシステム コールを使って)。 したがって、setuid/setgid されたプログラムは、コマンドラインからの入力を検査 する必要があり、コマンドラインの引数 0 番に当たるプログラム名を信用しては いけません(ユーザは NULL を含むどんな値も設定できるからです)。 <!-- <sect1>Environment Variables --> <sect1>環境変数 <p> <!-- By default, environment variables are inherited from a process' parent. However, when a program executes another one it can set the environment variables to arbitrary values. This is dangerous to setuid/setgid programs, because their invoker can control their environment variables, sending them on. Since they are usually inherited, this also applies transitively. --> 環境変数は、デフォルトでは親プロセスから継承されます。 しかしあるプログラムから他のプログラムを実行(exec)した場合、環境変数に 任意の値を設定できます。 setuid/setgid されたプログラムでは、これは危険をともないます。というのも プログラムを呼び出すことで環境変数のコントロールが可能になり、環境変数を 他のプログラムに渡せてしまうからです。 普通、環境変数は継承されてしまうため、この危険性も同時に引き継がれてしまい ます。 <p> <!-- Environment variables are stored in a format that allows multiple values with the same field (e.g., two SHELL values). While typical command shells prohibit doing this, a cracker can create such a situation; some programs may test one value but use a different one in this case. Even worse, many libraries and programs are controlled by environment variables in ways that are obscure, subtle, or even undocumented. For example, the IFS variable is used by the <it>sh</it> and <it>bash</it> shell to determine which characters separate command line arguments. Since the shell is invoked by several low-level calls, setting IFS to unusual values can subvert apparently-safe calls. --> 環境変数は、同じフィールドに複数の値を設定できる形式で記憶されています (たとえば SHELL 変数には、2 つの値を設定できる)。 コマンドシェルの代表的なものは、この設定ができないようになっていますが、 クラッカーは、そのような状況を作り上げられます。つまりこのケースならば、 プログラムで 1 つの値はチェックしますが、実際は別の値を使用してしまう ことが考えられます。 さらに悪いことに、ライブラリやプログラムはたいていの場合環境変数によって 制御されているものの、その方法があいまいだったり、わかりにくかったり、 中にはドキュメント化されていないものがあったりします。 たとえば、IFS 変数は <it>sh</it> や <it>bash</it> でコマンドラインの引数を 分割するのに使用されるキャラクタを指定するために利用されています。 シェルは低レベルのシステムコールを利用して呼び出されるため、IFS 変数に 異常な値を設定すると、一見安全と思われるシステムコールを危険なものに 変えてしまう恐れがあります。 <p> <!-- For secure setuid/setgid programs, the short list of environment variables needed as input (if any) should be carefully extracted. Then the entire environment should be erased by setting the global variable <it>environ</it> to NULL, followed by resetting a small set of necessary environment variables to safe values (<it>not</it> values from the user). These values usually include PATH (the list of directories to search for programs, which should <it>not</it> include the current directory), IFS (to its default of `` \t\n''), and TZ (timezone). --> setuid/setgid されたプログラムを安全にするには、環境変数の中から入力(もし あれば)に必要とされるものを注意を払って選び出し、短いリストを作る必要が あります。 そして環境変数全体を表す大域変数である <it>environ</it> に NULL を設定して、 環境変数全体を削除し、その後に必要となる最小限の安全な値を再設定してください (ユーザの設定値は使用「しない」こと)。 環境変数には、PATH(プログラムのありかを検索するディレクトリのリストです。 これにカレント・ディレクトリを入れては「いけません」)、IFS(デフォルトでは 「\t\n」です)、TZ(タイムゾーン)があります。 <!-- <sect1>File Descriptors --> <sect1>ファイル・ディスクリプタ <p> <!-- A program is passed a set of ``open file descriptors,'' that is, pre-opened files. A setuid/setgid program must deal with the fact that the user gets to select what files are open and to what (within their permission limits). A setuid/setgid program must not assume that opening a new file will always open into a fixed file descriptor id. It must also not assume that standard input, standard output, and standard error refer to a terminal or are even open. --> プログラムには「オープンしたファイル・ディスクリプタ」、つまりあらかじめ オープンされているファイルが渡ります。 setuid/setgid されたプログラムでは、ユーザがあるファイルをオープンして、 それを利用できてしまう(パーミッションの制限内で)ということを気にする必要が あります。 setuid/setgid されたプログラムでは、新しくオープンしたファイルが常に固定した ファイル・ディスクリプタ ID に割り当てられていると想定してはいけません。 また端末が標準入力、標準出力、標準エラー先になっていること、また端末が すでにオープンされていることも前提にしてはいけません。 <!-- <sect1>File Contents --> <sect1>ファイルの内容 <p> <!-- If a program takes directions from a given file, it must not give it special trust unless only a trusted user can control its contents. This means that an untrusted user must not be able to modify the file, its directory, or any of its parent directories. Otherwise, the file must be treated as suspect. --> あるファイルの内容によって、プログラムの動作が左右される場合、信頼できる ユーザだけがその内容を変更できるのでなければ、そのファイルを信用してはいけ ません。 つまり、信頼できないユーザが、ファイルやそのファイルがあるディレクトリ、 その親ディレクトリを修正できてはいけません。 そうでなければ、そのファイルを信頼するに値しないものとして扱わなければ なりません。 <!-- <sect1>CGI Inputs --> <sect1>CGI からの入力 <p> <!-- CGI inputs are internally a specified set of environment variables and standard input. These values must be validated. --> CGI からの入力は、実際のところ環境変数や標準入力として扱われます。 したがってこれらも検証しなければなりません。 <p> <!-- One additional complication is that many CGI inputs are provided in so-called ``URL-encoded'' format, that is, some values are written in the format %HH where HH is the hexadecimal code for that byte. You or your CGI library must handle these inputs correctly by URL-decoding the input and then checking if the resulting byte value is acceptable. You must correctly handle all values, including problematic values such as %00 (NIL) and %0A (newline). Don't decode inputs more than once, or input such as ``%2500'' will be mishandled (the %25 would be translated to ``%'', and the resulting ``%00'' would be erroneously translated to the NIL character). --> CGI からの入力の多くが、いわゆる「URL エンコードされた」形式になっている 点が検証をより厄介にしています。つまり 16 進数の HH というバイト値を表す には %HH という形式をとります。 CGI や CGI ライブラリは、これらの入力を適切にデコードして、バイト値が正しい かどうかをチェックする必要があります。 %00 (NIL) や %0A (改行)のような疑わしい値を含むすべての入力を間違いなく処理 しなければいけません。 入力のデコードは 1 回だけにしてください。でないと、「%2500」のような入力が 誤って処理されてしまいます(まず %25 が「%」に変換され、その結果「%00」が 間違って NIL キャラクタに変換されてしまいます)。 <p> <!-- CGI scripts are commonly attacked by including special characters in their inputs; see the comments above. --> 入力に特殊なキャラクタを混ぜることで、CGI スクリプトを攻撃するケースがまま 見られます。上記の解説を見てください。 <p> <!-- Some HTML forms include client-side checking to prevent some illegal values. This checking can be helpful for the user but is useless for security, because attackers can send such ``illegal'' values directly to the web server. As noted below (in the section on trusting only trustworthy channels), servers must perform all of their own input checking. --> HTML のフォームには、クライアント側でチェックをすることで不正な値を排除する ものもあります。 これはユーザにとっては有益かもしれませんが、セキュリティ上は無意味です。 というのも、攻撃者はそのような「不正」な値を直接 Web サーバーに送り付けられる からです。 後で(「信頼できる経路だけ信じること」のセクション)説明しますが、サーバーは 自分が受け取るすべての入力をチェックする必要があります。 <!-- <sect1>Other Inputs --> <sect1>その他の入力 <p> <!-- Programs must ensure that all inputs are controlled; this is particularly difficult for setuid/setgid programs because they have so many such inputs. Other inputs programs must consider include the current directory, signals, memory maps (mmaps), System V IPC, and the umask (which determines the default permissions of newly-created files). Consider explicitly changing directories (using chdir(2)) to an appropriately fully named directory at program startup. --> プログラムは、入力のすべてをコントロールすることが必須です。 しかし setuid/setgid されたプログラムでは困難を極めます。理由は、そのような 入力があまりに多いからです。 一方、入力プログラムでは下記の点を考慮する必要があります。 <itemize> <item>カレントディレクトリ <item>シグナル <item>メモリー・マップ(mmap) <item>System V 由来の IPC <item>umask(新規にファイルを作成する場合のデフォルトのパーミッションを 決定する) </itemize> プログラムを起動する時にディレクトリを(chdir(2)を使用して)変更する場合は、 フルパス指定できちんと目的のディレクトリに移動することも考慮してください。 <!-- <sect1>Limit Valid Input Time and Load Level --> <sect1>入力制限時間と負荷レベルの制限 <p> <!-- Place timeouts and load level limits, especially on incoming network data. Otherwise, an attacker might be able to easily cause a denial of service by constantly requesting the service. --> タイムアウトと負荷レベルの制限を設けてください。特にネットワーク経由で やってくるデータには必ず制限をかけてください。そうしないと攻撃者は絶えること なくサービス要求を送り付けることで、いとも簡単にサービス妨害攻撃を実行 できます。 </sect> <!-- <sect>Avoid Buffer Overflow --> <sect>バッファオーバーフローの回避 <p> <!-- An extremely common security flaw is the ``buffer overflow.'' Technically, a buffer overflow is a problem with the program's internal implementation, but it's such a common and serious problem that I've placed this information in its own chapter. To give you an idea of how important this subject is, at the CERT, 9 of 13 advisories in 1998 and at least half of the 1999 advisories involved buffer overflows. An informal survey on Bugtraq found that approximately 2/3 of the respondants felt that buffer overflows were the leading cause of security vulnerability (the remaining respondants identified ``misconfiguration'' as the leading cause) [Cowan 1999]. --> 「バッファオーバーフロー」は、セキュリティの欠陥として頻繁に発生します。 技術的にはプログラムの実装上の問題ですが、あまりに頻繁に発生し、かつ 重大な問題を抱えているので、あえて独立して項目を立てました。 この問題がいかに重要かは、CERT の勧告の内 1998 年の 13 の内の 9、1999 年の少なくとも半分以上がバッファオーバーフロー関連であることで明らか です。 Bugtraq による非公式な調査でも、おおよそ 2/3 の回答がバッファオーバー フローがセキュリティの脆弱さの原因としています(残りの回答は「設定ミス」 が原因としています) [Cowan 1999] <p> <bf>訳註:</bf>Bugtraq は、セキュリティ関連の情報をやり取りする ML です。 <url url="http://www.securityfocus.com/bugtraq/archive/" name="ML のアーカイブ"> が公開されています。 <p> <!-- A buffer overflow occurs when you write a set of values (usually a string of characters) into a fixed length buffer and keep writing past its end. These can occur when reading input from the user into a buffer, but they can also occur during other kinds of processing in a program. --> バッファオーバーフローが発生するのは、固定長のバッファ領域にある値(文字列 など)を、その領域を越えて書き続けてしまう場合です。 これらの現象は、ユーザからの入力をバッファに読み込む時にも起こりますし、 プログラムのまったく違った処理の最中でも起こる可能性があります。 <p> <!-- If a secure program permits a buffer overflow, it can usually be exploited by an adversary. If the buffer is a local C variable, the overflow can be used to force the function to run code of an attackers' choosing. A buffer in the heap isn't much better; attackers can use this to control variables in the program. More details can be found from Aleph1 [1996], Mudge [1995], or the Nathan P. Smith's "Stack Smashing Security Vulnerabilities" website at <url url="http://destroy.net/machines/security/">. --> 安全性が求められるプログラムでバッファオーバーフローを許してしまうと、 往々にして攻撃者に悪用される恐れがあります。 バッファが C のローカル変数で実装されていた場合、攻撃者はその関数の中で 望みのコードを強制的に実行させる手段としてオーバフローを利用できてしまいます。 バッファがヒープ領域にあっても、状況が改善するわけではありません。攻撃者 は、この状態でもプログラム中の変数をいじることができます。 さらに詳しいことは、Aleph1 [1996]、Mudge [1995]を参考にするか、 <url url="http://destroy.net/machines/security/"> にある 「Stack Smashing Security Vulnerabilities」を見てください。 <p> <bf>訳註:</bf>ヒープ領域は、プログラムで利用するデータを格納する領域で、 利用時に動的に割り当てられ、利用が済むと解放された後、再利用に回されます。 C では malloc(3) で確保された領域がこれに当たります。 <p> <!-- Some programming languages are essentially immune to this problem, either because they automatically resize arrays (e.g., Perl), or because they normally detect and prevent buffer overflows (e.g., Ada95). However, the C language provides absolutely no protection against such problems, and C++ can be easily used in ways to cause this problem too. --> プログラム言語の中には、そもそもこういった問題に影響されないものもあります。 つまり自動的に配列の大きさを調整したり(たとえば Perl)、バッファオーバー フローを見つけだし、防ぐしくみを標準で備えているもの(たとえば Ada95)があり ます。 残念なことに、 C はバッファオーバーフローを防ぐ手段をまったく持っておらず、 C++ でもたわいなくこの問題を発生させることができます。 <!-- <sect1>Dangers in C/C++ --> <sect1>C/C++ の危険なところ <p> <!-- C users must avoid using dangerous functions that do not check bounds unless they've ensured the bounds will never get exceeded. Functions to avoid in most cases include the functions strcpy(3), strcat(3), sprintf(3), and gets(3). These should be replaced with functions such as strncpy(3), strncat(3), snprintf(3), and fgets(3) respectively, but see the discussion below. The function strlen(3) should be avoided unless you can ensure that there will be a terminating NIL character to find. Other dangerous functions that may permit buffer overruns (depending on their use) include fscanf(3), scanf(3), vsprintf(3), realpath(3), getopt(3), getpass(3), streadd(3), strecpy(3), and strtrns(3). --> C ユーザは、確保されている領域を越えることはありえないと確証できなければ、 境界をチェックしない危険な関数を使うべきではありません。 通常使用を避けるべき関数には、strcpy(3)、strcat(3)、sprintf(3)や gets(3) があります。 その代わりに strncpy(3)や、strncat(3)、snprintf(3)や fgets(3)を使用することを 勧めます。詳しくは下記で論じます。 strlen(3)は NIL キャラクタが終端にあることを仮定しているので、NIL が必ず存在 すると確信できなければ、使用は避けるべきです。 その他にもバッファを越えてしまう恐れのある関数(その使い方によりますが) には、fscanf(3)、scanf(3)、vsprintf(3)、realpath(3)、getopt(3)、getpass(3)、 streadd(3)や strecpy(3)、strtrns(3)等があります。 </sect1> <!-- <sect1>Library Solutions in C/C++ --> <sect1>C/C++ のライブラリによる解決策 <p> <!-- One solution in C/C++ is to use library functions that do not have buffer overflow problems. --> C/C++ での解決策として、バッファオーバーフローの問題を抱えていない関数 ライブラリの使用があげられます。 <p> <!-- The ``standard'' solution to prevent buffer overflow in C is to use the standard C library calls that defend against these problems. This approach depends heavily on the standard library functions strncpy(3) and strncat(3). If you choose this approach, beware: these calls have somewhat surprising semantics and are hard to use correctly. The function strncpy(3) does not NIL-terminate the destination string if the source string length is at least equal to the destination's, so be sure to set the last character of the destination string to NIL after calling strncpy(3). Both strncpy(3) and strncat(3) require that you pass the amount of space left available, a computation that is easy to get wrong (and getting it wrong could permit a buffer overflow attack). Neither provide a simple mechanism to determine if an overflow has occurred. Finally, strncpy(3) has a performance penalty compared to the strcpy(3) it replaces, because strncpy(3) zero-fills the remainder of the destination. --> C でバッファオーバーフローを防ぐ「常套」手段として、これらの問題を抱えて いない標準ライブラリ関数を使用することがまずあげられます。 この解決方法は strncpy(3)と strncat(3)という標準関数にとても依存しています。 この解決策をとるなら、その使い方が意外と面倒で、正しく使うことが難しいことに 注意が必要です。 strncpy(3)はコピー先の文字列の終端に NIL をセットしないので、コピー元の 文字列長がコピー先以上の長さならば、strncpy(3)を呼出した後にコピー先の終端 に NIL をセットすることを忘れないでください。 strncpy(3)、strncat(3)とも、書き込みできる領域の残りの大きさを引数で渡す 必要がありますが、この残量の計算をよく間違います(ここで間違ってしまうと、 バッファオーバーフロー攻撃を許してしまうことになります)。 どちらの関数も、バッファオーバーフローが発生したかどうかを確認する単純な しくみを持っていません。最後になりますが、代替え関数である strncpy(3)は strcpy(3)に比べて、パフォーマンスは劣ります。これは strncpy(3)がコピー先の 残り領域を 0 で埋めるためです。 <p> <!-- An alternative, being employed by OpenBSD, is the strlcpy(3) and strlcat(3) functions by Miller and de Raadt [Miller 1999]. This is a minimalist approach that provides C string copying and concatenation with a different (and less error-prone) interface. Source and documentation of these functions are available under a BSD-style license at <url url="ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3">. --> 一方、OpenBSD には Miller と de Raadt [Miller 1999] 両氏によって開発された strlcpy(3)と strlcat(3)があります。 従来のコピーと連結とは異った(かつ間違いにくい)インタフェースを持ち、最小限 の努力で問題の解決を試みています。 ソースと関数のドキュメントは BSD スタイルのライセンスで、 <url url="ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3"> から利用できます。 <p> <!-- Another alternative is to dynamically reallocate all strings instead of using fixed-size buffers. This general approach is recommended by the GNU programming guidelines. One toolset for C that dynamically reallocates strings automatically is the ``libmib allocated string functions'' by Forrest J. Cavalier III, available at <url url="http://www.mibsoftware.com/libmib/astring">. The source code is open source; the documentation is not but it is freely available. --> 他の取り組みとしては、固定長のバッファを使うかわりに、文字列すべての領域を 動的に再確保する方法もあります。 この手法は一般的で、GNU プログラミング ガイドラインで推奨しています。 その方法の 1 つとして自動的に文字列領域の再確保を行う C のツールである Forrest J. Cavalier III 氏が開発した「libmib allocated string functions」 があります。 <url url="http://www.mibsoftware.com/libmib/astring">から利用 できます。 ソースはオープン・ソースの形式をとっていますが、ドキュメントはオープン・ ソースではありません。しかし自由に入手できます。 <p> <!-- There are other libraries that may help. For example, the glib library is widely available on open source platforms (the GTK+ toolkit uses glib, and glib can be used separately without GTK+). At this time I do not have an analysis showing definitively that the glib library functions protect against buffer overflow, but this seems likely. Hopefully a later edition of this document will confirm which glib functions can be used to avoid buffer overflow issues. --> その他にも役に立つと思われるライブラリがあります。 たとえば、glib ライブラリは広くオープン・ソースのプラットフォーム上で利用され ています(GTK+ ツールキットは glib ライブラリを使用していますが、glib は GTK+ を使うことなしに単独で利用できます。 今の時点で、glib ライブラリの関数がバッファオーバーフローを防ぐために有効か どうかを分析して、問題ないことを示すことはできませんでしたが、期待でき そうな感じがします。 願わくば、このドキュメントの次以降の版では glib の関数がバッファオーバーフロー の問題を解決できることを確認したいと思っています。 </sect1> <!-- <sect1>Compilation Solutions in C/C++ --> <sect1>C/C++ のコンパイル時の解決策 <p> <!-- A completely different approach is to use compilation methods that perform bounds-checking (see [Sitaker 1999] for a list). In my opinion, such tools are very useful in having multiple layers of defense, but it's not wise to use this technique as your sole defense. There are at least two reasons for this. First of all, most such tools only provide partial defense against buffer overflows (and the ``complete'' defenses are generally 12-30 times slower); C and C++ were simply not designed to protect against buffer overflow. Second of all, for open source programs you cannot be certain what tools will be used to compile the program; using the default ``normal'' compiler for a given system might suddenly open security flaws. --> まったく違った観点から解決をはかろうとするものに、領域の境界チェックを コンパイル時に行うものがあります([Sitaker 1999] のリストを参照して ください)。 私見ですが、防御にいろいろな手段を打った中の 1 つとして、そのようなツール は非常に有効ですが、この手法だけで防御するのは賢い手段とはいえません。 理由として 2 つは上げられます。 まず、そのようなツールは必要な防御の一部しか行うことができません(そして 「完璧な」防御を行おうとすると、通常の 12 から 30 倍遅くなります)。C と C++ はそもそもバッファオーバーフローを防ぐ手段を持ち合わせていません。 次に、オープン・ソースであるプログラムですと、何のツールを使ってコンパイル するかを決められているわけではありません。システムについてくるデフォルトの 「普通の」コンパイラを使うとセキュリティの弱点をさらすことになってしまい ます。 <p> <!-- One of the more useful tools is ``StackGuard,'' which works by inserting a ``guard'' value (called a ``canary'') in front of the return address; if a buffer overflow overwrites the return address, the canary's value (hopefully) changes and the system detects this before using it. This is quite valuable, but note that this does not protect against buffer overflows overwriting other values (which they may still be able to use to attack a system). There is work to extend StackGuard to be able to add canaries to other data items, called ``PointGuard.'' PointGuard will automatically protect certain values (e.g., function pointers and longjump buffers). However, protecting other variable types using PointGuard requires specific programmer intervention (the programmer has to identify which data values must be protected with canaries). This can be valuable, but it's easy to accidentally omit protection for a data value you didn't think needed protection - but needs it anyway. More information on StackGuard, PointGuard, and other alternatives is in Cowan [1999]. --> さらに有効なツールとして「StackGuard」があります。これは「ガード」する ための値(「カナリア(canary)」と呼びます)をリターンアドレスが書かれている 前に挿入して動作します。バッファオーバーフローが発生してリターンアドレスを 書き換えると、カナリアの値が(おそらく)変更され、実際に使用される前にシステム が検出します。 これは非常に有効なのですが、リターンアドレス以外の値(これを使用してもシス テムを攻撃できます)を書き換えるバッファオーバーフローには対処できません。 StackGuard を強化して、カナリアを他のデータに対しても使えるようにしたものが、 「PointGuard」です。 PointGuard は自動的にある値(たとえば関数のポインタやロングジャンプ・バッファ) を保護します。 しかし他の変数を PointGuard を使って保護する場合、プログラマの介在が必要と なります(プログラマはどのデータをカナリアで保護しなければいけないのかを 認識しなければいけない)。 これは有効な半面、本来保護すべきなのに必要がない、とうっかり判断してしまい、 いとも簡単に保護を省略してしまう場合が考えられます。 StackGuard や PointGuard、またそれと同様なものについての詳細は Cowan [1999] を参照してください。 <p> <bf>訳註:</bf>鳥類のカナリアは、炭鉱で一酸化炭素の増加や酸欠状態を「検知」 するために飼われていました。 <p> <!-- As a related issue, you could modify the Linux kernel so that the stack segment is not executable; such a patch to Linux does exist (see Solar Designer's patch, which includes this, at <url url="http://www.openwall.com/linux/"> However, as of this writing this is not built into the Linux kernel. Part of the rationale is that this is less protection than it seems; attackers can simply force the system to call other ``interesting'' locations already in the program (e.g., in its library, the heap, or static data segments). Also, sometimes Linux does require executable code in the stack, e.g., to implement signals and to implement GCC ``trampolines.'' Solar Designer's patch does handle these cases, but this does complicate the patch. Personally, I'd like to see this merged into the main Linux distribution, since it does make attacks somewhat more difficult and it defends against a range of existing attacks. However, I agree with Linus Torvalds and others that this does not add the amount of protection it would appear to and can be circumvented with relative ease. You can read Linus Torvalds' explanation for not including this support at <url url="http://lwn.net/980806/a/linus-noexec.html">. --> これと関連して、Linux のカーネルを修正して、スタック・セグメント上でのプロ グラムの実行を禁止してしまう方法もあります。それを行うにはパッチが必要です (Solar Designer の パッチに含まれています。 <url url="http://www.openwall.com/linux/">) このドキュメントを書いている時点では、まだカーネルに取り込まれていません。 技術的な理由の 1 つに、思ったほどその効果がでない点があげられます。 攻撃者は、対象にしているプログラムにすでに存在している他の「面白そうな」場所 (ライブラリやヒープ領域、スタティックなデータ・セグメント領域など)を呼び出せ てしまうからです。 また Linux はスタック領域でプログラムを実行する場合があります。例として、 シグナルや GCC の「トランポリン」の実装をする場合です。 Solar Designer の パッチでこのようなケースにも対応できますが、これがパッチを 複雑なものしている原因です。 個人的には Linux 本流に組み込まれてもいいかと思います。というのもこれによって いくぶんかでも攻撃が難しくなりますし、既存の攻撃のある部分は防御できるから です。 しかし Linus Torvalds 氏たちが考えているように、このパッチが見た目ほどさま ざまな防御ができない、比較的簡単にこの防御の裏をかくことができる、という点 については私も同意見です。 Linus Torvalds 氏がこのパッチを採用しない理由については、 <url url="http://lwn.net/980806/a/linus-noexec.html">を参照してください。 <p> <bf>訳註:</bf>トランポリン(trampoline)とは、プログラムが実行している最中に プログラム自身によって生成される、互いに独立した小さなオブジェクト・ コードを指します。 <p> <!-- In short, it's better to work first on developing a correct program that defends itself against buffer overflows. Then, after you've done this, by all means use techniques and tools like StackGuard as an additional safety net. If you've worked hard to eliminate buffer overflows in the code itself, then StackGuard is likely to be more effective because there will be fewer ``chinks in the armor'' that StackGuard will be called on to protect. --> 要するに、まずプログラムそのものでバッファオーバーフローを防ぐように開発 するのが大切です。 そのように開発した後に、StackGuard のようなツールやテクニックを使って、 さらに安全策を講じておくべきです。 ソースコードからバッファオーバーフローを追い出せるだけ追い出したら、 StackGuard はさらに効果を発揮します。というのも StackGuard が防御のために 呼ばれるような「致命的な弱点」を減らすことができるからです。 </sect1> <!-- <sect1>Other Languages --> <sect1>他の言語 <p> <!-- The problem of buffer overflows is an argument for using many other programming languages such as Perl, Python, and Ada95, which protect against buffer overflows. Using those other languages does not eliminate all problems, of course; in particular see the discussion under ``limit call-outs to valid values'' regarding the NIL character. There is also the problem of ensuring that those other languages' infrastructure (e.g., run-time library) is available and secured. Still, you should certainly consider using other programming languages when developing secure programs to protect against buffer overflows. --> バッファオーバーフローは、他のプログラミング言語でも問題になっています。 Perl や Python、Ada95 のようなバッファオーバーフローを防ぐ言語であっても です。 C や C++ 以外の言語を使ったとしても、もちろんすべての問題を解決できるわけ ではありません。 詳しくは、後程論じる「正しい値でだけ呼び出すこと」にある NIL キャラクタの 扱いを参照してください。 また言語が提供している基本的な機能(たとえばランタイム・ライブラリ)が利用で きる環境でかつその機能が安全であることを保証するという問題も残っています。 そのような問題はあるにせよ、バッファオーバーフローを防ぐよう、安全なプロ グラム開発を行う場合は、他の言語の使用を真剣に考えるべきだと思います。 </sect1> </sect> <!-- <sect>Structure Program Internals and Approach --> <sect>プログラムのインタフェースと内部構成をきちんとすること <p> <!-- <sect1>Secure the Interface --> <sect1>インタフェースを安全に <p> <!-- Interfaces should be minimal (simple as possible), narrow (provide only the functions needed), and non-bypassable. Trust should be minimized. Applications and data viewers may be used to display files developed externally, so in general don't allow them to accept programs (including auto-executing macros) unless you're willing to do the extensive work necessary to create a secure sandbox. --> インタフェースは、できる限り小さく(限りなくシンプルに)、厳密に(必要な機能 だけ)、そして例外なくそのインタフェースを使うようにする必要があります。 信用できる入力はほとんどないと思ってください。 アプリケーションやデータを見るためのビューアーは、外部で作成されたファイル を表示することが多いと思いますが、それらのファイルをプログラム(自動実行マクロ も含みます)として扱うことを避けてください。安全なサンドボックスを苦労して 作成することをいとわないのであれば、話は別ですが。 </sect1> <!-- <sect1>Minimize Permissions --> <sect1>パーミッションを最小限に <p> <!-- As noted earlier, it is an important general principle that programs have the minimal amount of permission necessary to do its job. That way, if the program is broken, its damage is limited. The most extreme example is to simply not write a secure program at all - if this can be done, it usually should be. --> すでに触れましたが、この点については大原則が存在しています。それはプログラム には、処理のために必要な最低限のパーミッションしか持たせないということです。 そうすれば万が一プログラムがおかしくなっても、影響範囲が狭まります。 極端を言うと、できるなら安全性が求められるプログラムを作成すること自体を 止める、というのが一番確実なのですが。 <p> <!-- In Linux, the primary determiner of a process' permission is the set of id's associated with it: each process has a real, effective, filesystem, and saved id for both the user and group. Manipulating these values is critical to keeping permissions minimized. --> Linux ではプロセスのパーミッションは、まずその各種 ID によって決まります。 プロセスはそれぞれ実 ID、実効 ID、ファイルシステム ID、保存 ID をユーザと グループ毎に持っています。 これらの値をうまく使用して、パーミッションを最小限にすることはとても大切 なことです。 <p> <!-- Permissions should be minimized along several different views: --> 別の観点からもパーミッションを最小限に抑える理由をあげられます。 <itemize> <!-- <item>Minimize the highest permission granted. Avoid giving a program root privileges if possible. Don't make a program <it>setuid root</it> if it only needs access to a single file; consider creating a special group, make the file owned by the group, and then make the program <it>setgid</it> to that group. Similarly, try to make a program <it>setgid</it> instead of <it>setuid</it>, since group membership grants fewer rights (in particular, it does not grant the right to change file permissions). If a program must constantly switch between user permissions to access files (e.g., an NFS server), consider setting only the Linux-unique value ``file system uid'' (fsuid) since this will limit file accesses without causing race conditions and without permitting users to send signals to the process. --> <item>最高のパーミッションを許可することは最小限に抑えること。 なるべくなら root の権限をプログラムに与えない。 単独のファイルにアクセスするためだけに、プログラムを <it>setuid root</it> しない。そのような場合はファイルにアクセスするために専用グループの作成を 検討すること。このグループがファイルを所有し、プログラムはこのグループに <it>setgid</it> すればよい。 このようにプログラムをいきなり <it>setuid</it> せずに <it>setgid</it> してみること。というのは、グループのメンバーに対しては許可されることが ユーザに対することよりも限定されているからである(たとえばファイルのパー ミッションの変更は認められない)。 もしプログラムが複数のファイルにアクセスするために、複数ユーザのパーミッ ションを持つ必要があるなら(たとえば NFS サーバー)、 Linux 固有の機能である 「ファイルシステム UID(fsuid)」を検討すること。これを採用すれば、競合状態 やユーザがプロセスにシグナルを送れるように許可を与えることなしにファイル へのアクセスを制限できる。 <p> <!-- If you <it>must</it> give a program root privileges, consider using the POSIX capability features available in Linux 2.2 and greater to minimize them immediately on program startup. By calling cap_set_proc(3) or the Linux-specific capsetp(3) routines immediately after starting, you can permanently reduce the abilities of your program to just those abilities it actually needs. Note that not all Unix-like systems implement POSIX capabilities. For more information on Linux's implementation of POSIX capabilities, see <url url="http://linux.kernel.org/pub/linux/libs/security/linux-privs">. --> <it>どうしても</it> root の権限をプログラムに与える必要がある場合、Linux 2.2 以上で利用可能な POSIX ケイパビリティの使用を検討すること。POSIX ケイパビリティを利用すると、プログラムが起動するとすぐにそのプログラムの 権限を最小限に抑えられる。 cap_set_proc(3)もしくは Linux 固有の capsetp(3)を呼び出すことで、プロ グラム起動とともにそのプログラムが実際に必要とする機能だけに常に権限を 制限できる。 UNIX ライクなシステムすべてが POSIX ケイパビリティを実装しているわけでは ないことに注意すること。 Linux での POSIX ケイパビリティの詳細は、 <url url="http://linux.kernel.org/pub/linux/libs/security/linux-privs">. を参照すること <!-- <item>Minimize the time the permission is active. Use setuid(2), seteuid(2), and related functions to ensure that the program only has these permissions active when necessary. --> <item>パーミッションが有効である時間を最短に。 setuid(2)、seteuid(2)やそれと関連した機能を使用する場合は、プログラムが そのパーミッションを必要とする時だけ有効にしているかを確認すること <!-- <item>Minimize the time the permission can become active. As soon as possible, permanently give up permissions. Since Linux implements ``saved'' IDs, the simplest approach is to set the other id's twice to an untrusted id. In setuid/setgid programs, you should usually set the effective gid and uid to the real ones, in particular right after a fork(2), unless there's a good reason not to. Note that you have to change the gid first when dropping from root to another privilege or it won't work! --> <item>パーミッションを有効にできる時間を最短に。 すみやかにパーミッションを完全に放棄すること。 Linux は「保存」ID を採用しているので、信用できない ID に対しては 2 度 ばかり他の ID をセットしてしまえば、それで終わりにできる。 setuid/setgid されたプログラムでは、特別な理由がない限りは実効 gid と UID に実際に実行したユーザの ID をセットすること。特に fork(2)した後は 必ず。 root から他の権限に移る場合には、必ず最初に gid を変更すること。さもない と動かなくなる! <!-- <item>Minimize the number of modules needing and granted the permission. If only a few modules are granted the permission, then it's much easier to determine if they're secure. One way to do so follows the previous point; have a single module use the privilege and then drop it, so that other modules called later cannot misuse the privilege. Another approach is to have separate commands; one command is a complex tool that can do a vast number of tasks for a privileged user (e.g., root), while the other tool is setuid but is a small, simple tool that only permits a small command subset (which, if the input is acceptable, is then passed to the first tool). This is especially helpful for GUI-based systems; have the GUI portion run as a normal user, and then pass those requests on to another module that has the special privileges. --> <item>パーミッションに左右されるモジュール数をできる限り少なく。 パーミッションに左右されるモジュールの数がわずかなら、安全かどうかを確認 するのは容易である。方法の 1 つは前の項目で指摘したことそのままで、 モジュールがある権限を使用し終えたら、すぐその権限を取り去る。そうすれば 後から呼ばれるモジュールは権限を誤用しようがない。 別のやり方はコマンドを分け、1 つはおびただしい数の処理を行う複雑なツール で権限を持つユーザ(たとえば root)が使用するものにし、一方他のツールは setuid されてはいるが、コンパクトかつ単純なツールで限られたコマンドしか 実行できないようにする(このツールで入力が認められたなら、最初のツールに 渡す)。 この方法は GUI ベースのシステムにとってとても有効な手段で、GUI 部分を 普通のユーザ権限で動かし、そこで受け取ったリクエストを特権を持った モジュールに渡してやる <!-- <item>Minimize the resources available. You can set file and directory permissions so that only a small number of them can be written by the program. This is commonly done for game high scores, where games are usually setgid <it>games</it>, the score files are owned by the group <it>games</it>, and the programs are owned by someone else (say root). Thus, breaking into a game allows the perpetrator to change high scores but won't allow him to change a game's executable or configuration file. --> <item>使えるリソースを最小限に。 プログラムが書き込むことができるファイルやディレクトリをできるだけ少なく するようにパーミッションをセットすること。 これはゲームソフトのハイスコアを記録する場合によく使われている方法で、 ゲームは普通 <it>games</it> に setgid されていてスコアファイルは <it>games</it> グループが所有している。そしてプログラム自体は別のユーザ (root など)が所有している。 こうしておけば、ゲームを通じて侵入者が入ってきてもハイスコアをいじること はできても、ゲームの実行形式や設定ファイルには手を付けられない。 <p> <!-- Consider creating separate user or group accounts for different functions, so breaking into one system will not automatically allow damage to others. --> 異なる機能毎にそれぞれユーザとグループを作ることを考えておくべきだ。 そうしておけば、あるシステムに付け込まれると自動的に他のシステムも ダメージを被る、ということはなくなるだろう。 <p> <!-- You can use the chroot(2) command so that the program has only a limited number of files available to it. This requires carefully setting up a directory (called the ``chroot jail''). A program with root permission can still break out (using calls like mknod(2) to modify system memory), but otherwise such a jail can significantly improve a program's security. --> chroot(2)コマンドを使えば、プログラムは限られた数のファイルしか利用でき なくなる。 この機能を生かすには、ディレクトリの設定を慎重に行なう必要がある (「chroot jail(chroot の牢獄)」と呼ばれている)。 root のパーミッションを持ったプログラムは、この手を打ってもシステムを 壊せるが(mknod(2)などを呼び出してシステムメモリーを変更できてしまう)、 それ以外はこの牢獄がプログラムのセキュリティを大幅に堅牢にしてくれる。 </itemize> <p> <!-- Some operating systems have the concept of multiple layers of trust in a single process, e.g., Multics' rings. Standard Unix and Linux don't have a way of separating multiple levels of trust by function inside a single process like this; a call to the kernel increases permission, but otherwise a given process has a single level of trust. Linux and other Unix-like systems can sometimes simulate this ability by forking a process into multiple processes, each of which has different permissions. To do this, set up a secure communication channel (usually unnamed pipes are used), then fork into different processes and drop as many permissions as possible. Then use a simple protocol to allow the less trusted processes to request actions from more trusted processes, and ensure that the more trusted processes only support a limited set of requests. --> オペレーティングシステムの中には、1 つのプロセスで信頼のレベルを複数 持つものもあります。たとえば Multics のリング保護機構がそれに当たります。 一般的な UNIX や Linux では 1 つのプロセス中で信頼のレベルを複数に分ける 方法はありません。 つまり、カーネルを呼び出すことでパーミッションを上げられますが、プロセスは 単一の信頼レベルしか持てません。 Linux や UNIX ライクなシステムは 1 つのプロセスから複数のプロセスを fork して、そのそれぞれのプロセスにパーミッションを設定することで、この機能を シミュレートすることができます。 これを行なうには、安全に情報を伝達する経路(普通は名前なしパイプが使われます) を確保し、別のプロセスを fork してできる限り多くのパーミッションを落とさ なければいけません。 そして単純なプロトコルを使って信頼性の高いプロセスから低いプロセスに要求を 伝えるようにし、信頼性の高いプロセスは限られた要求しかサポートしないことを 確実に行なわなくてはなりません。 <p> <!-- This is one area where technologies like Java 2 and Fluke have an advantage. For example, Java 2 can specify fine-grained permissions such as the permission to only open a specific file. However, general-purpose operating systems do not typically have such abilities. --> この技術は Java 2 や Fluke が強みをもつ分野の 1 つです。 たとえば Java 2 はある特定のファイルだけをオープンするパーミッションという ような、きめの細かいパーミッションを指定できます。 しかし汎用的なオペレーティングシステムでは、そのような機能は一般的に持って いません。 <p> <bf>訳註:</bf>Fluke は、Flux プロジェクトの一環として開発されているカーネル とオペレーティングシステムの総称で、Flux μ-kernel Environment の略称 です。 nested process model にもとづき、強力で階層的なリソース管理を行い、より 安全性の高いシステムを目指しています。 詳しくは、<url url="http://www.cs.utah.edu/projects/flux/" name="The Flux Research Group"> を参照してください。 <p> <!-- Each Linux process has two Linux-unique state values called filesystem user id (fsuid) and filesystem group id (fsgid). These values are used when checking for filesystem permissions. Programs with root privileges should consider changing just fsuid and fsgid before accessing files on behalf of a normal user. The reason is that setting a process' euid allows the corresponding user to send a signal to that process, while just setting fsuid does not. The disadvantage is that these calls are not portable to other POSIX systems. --> Linux のプロセスには、ファイルシステム ユーザ ID(fsuid)とファイルシステム グループ ID(fsgid)という 2 つの Linux 固有の状態変数があります。 この変数は、ファイルシステムのパーミッションをチェックする時に使われます。 root の権限を持つプログラムは、一般ユーザに代わってファイルにアクセスする 前に fsuid と fsgid を変更することを考慮すべきです。 理由は、プロセスに 実効ユーザ ID を設定すると、そのユーザはそのプロセスに 対してシグナルを送れてしまいますが、fsuid に設定してもそうはなりません。 この方法の欠点は他の POSIX システムではこの機能が使えないことです。 </sect1> <!-- <sect1>Use Safe Defaults --> <sect1>デフォルトは安全に <p> <!-- On installation the program should deny all accesses until the user has had a chance to configure it. Installed files and directories should certainly not be world writable, and in in fact it's best to make them unreadable by all but the trusted user. If there's a configuration language, the default should be to deny access until the user specifically grants it. --> プログラムをインストールする時には、ユーザが設定する機会まですべてのアクセス を拒否すべきです。 インストールされたファイルやディレクトリは、誰もが読み書き可能であって は決していけません。 要するに、信頼できるユーザ以外は読めなくしてしまうのが一番です。 設定をするための言語があるならば、ユーザがあえて許可しない限り、デフォルト でのアクセスは拒否すべきです。 </sect1> <!-- <sect1>Fail Open --> <sect1>フェイル・オープン <p> <!-- A secure program should always ``fail open,'' that is, it should be designed so that if the program does fail, the program will deny all access (this is also called ``failing safe''). If there seems to be some sort of bad behavior (malformed input, reaching a ``can't get here'' state, and so on), then the program should immediately deny service. Don't try to ``figure out what the user wanted'': just deny the service. Sometimes this can decrease reliability or usability (from a user's perspective), but it increases security. --> 安全なプログラムは常に「フェイル・オープン」であるべきです。つまり、 プログラムが正しく動作しなくなっても、プログラムはすべてのアクセスを拒否 するように設計されている必要があります(「フェイル・セーフ」とも呼ばれて います)。 プログラムが不正と思われる行為(異常な入力や「起こり得ない」状態になる等) を見つけたら、すぐにサービスを拒否すべきです。 「ユーザが意図することを探り出そう」などとはしないでください。ただサービス を拒否するだけでよいのです。 こうすると、時として信頼性や使い勝手が悪くなるかもしれません(ユーザの立場 からすると)。しかし安全性は高まります。 </sect1> <!-- <sect1>Avoid Race Conditions --> <sect1>競合状態は避けましょう <p> <!-- Secure programs must determine if a request should be granted, and if so, act on that request. There must be no way for an untrusted user to change anything used in this determination before the program acts on it. --> 安全が求められるプログラムは、要求を許可すべきかどうかを決めなければ なりません。 そして許可したならば、その要求を実行に移さなければなりません。 プログラムを実行する前に、信頼できないユーザが判定に影響を与えるどのような 変更もできてはいけません。 <p> <!-- This issue repeatedly comes up in the filesystem. Programs should generally avoid using access(2) to determine if a request should be granted, followed later by open(2), because users may be able to move files around between these calls. A secure program should instead set its effective id or filesystem id, then make the open call directly. It's possible to use access(2) securely, but only when a user cannot affect the file or any directory along its path from the filesystem root. --> ファイルシステムにおいては頻繁にこの問題が起こります。 一般的に避けなければいけないことは、プログラムが access(2)を使って要求を 認めるべきかを決定し、その後に open(2)を使うという手法です。これらのシステム コールを発行する間に、ユーザがファイルを移動できてしまうかもしれないからです。 安全が要求されるプログラムではそうするかわりに、実効 ID とファイルシステム ID をセットしてからすぐ、open システムコールを発行すべきです。 安全に access(2)を使う方法もありますが、その場合はユーザがそのファイルや ディレクトリをファイルシステムのルートからパスをたどっていじることができない 時だけです。 </sect1> <!-- <sect1>Trust Only Trustworthy Channels --> <sect1>信頼できる経路だけ信じること <p> <!-- In general, do not trust results from untrustworthy channels. --> 一般的に、信頼できない経路からの結果を信じてはいけません。 <p> <!-- In most computer networks (and certainly for the Internet at large), no unauthenticated transmission is trustworthy. For example, on the Internet arbitrary packets can be forged, including header values, so don't use their values as your primary criteria for security decisions unless you can authenticate them. In some cases you can assert that a packet claiming to come from the ``inside'' actually does, since the local firewall would prevent such spoofs from outside, but broken firewalls, alternative paths, and mobile code make even this assumption suspect. In a similar vein, do not assume that low port numbers (less than 1024) are trustworthy; in most networks such requests can be forged or the platform can be made to permit use of low-numbered ports. --> コンピュータで構成されたネットワーク(インターネット全体にも当てはまります) の大部分では、正当さが証明されていない伝送は信頼することができません。 たとえば、インターネット上ではどんなパケットでもそのヘッダー情報を含めて、 改ざんすることが可能です。したがって、信頼できると確証できるのでなければ、 その情報を第 1 の基準として、セキュリティ上の判断をしないでください。 ローカルのファイアーウォールが外部からスプーフィング(なりすまし)を防いで いるはずなので、本当に「内部」から送られたパケットであると断言できる場合 もあります。しかしファイアーウォールがおかしかったり、別の経路があったり、 モバイル用の接続口があったりすると、この仮定さえも疑わしいものになって しまいます。 同様な感覚で、小さいポート番号(1024 以下)を信頼できるものと決め込まないで ください。大部分のネットワークではそのようなリクエストは改ざん可能ですし、 コンピュータシステムに、小さいポート番号の使用を認めるようにすることも できます。 <p> <!-- If you're implementing a standard and inherently insecure protocol (e.g., ftp and rlogin), provide safe defaults and document clearly the assumptions. --> 標準的に使われているが本質的に安全でないプロトコル(たとえば ftp とか rlogin)を実行しているなら、デフォルトを安全にしておき、ドキュメントに は実行に当たっての前提条件を明記しておいてください。 <p> <!-- The Domain Name Server (DNS) is widely used on the Internet to maintain mappings between the names of computers and their IP (numeric) addresses. The technique called ``reverse DNS'' eliminates some simple spoofing attacks, and is useful for determining a host's name. However, this technique is not trustworthy for authentication decisions. The problem is that, in the end, a DNS request will be sent eventually to some remote system that may be controlled by an attacker. Therefore, treat DNS results as an input that needs validation and don't trust it for serious access control. --> ドメイン・ネーム・サーバー(DNS)は広くインターネット上で利用されており、 コンピュータ名と IP アドレス(数値)の組合せを維持管理しています。 「DNS の逆引き」という方法を使えば、単純なスプーフィング攻撃の一部を 排除できますし、ホスト名を見つける時にも役に立ちます。 しかしこのやり方では認証を決めるほどの信頼性はありません。 つまるところ問題なのは、DNS のリクエストが結局は攻撃者がコントロールしている どこかのシステムに対して送られているかもしれない、というところにあります。 したがって、DNS から得られた結果が入力として正しいことを確認する必要が あり、重要なアクセス制御の手段として信用してはいけません。 <p> <!-- If asking for a password, try to set up trusted path (e.g., require pressing an unforgeable key before login, or display unforgeable pattern such as flashing LEDs). When handling a password, encrypt it between trusted endpoints. --> パスワードを要求する場合、信頼できる入力をするために、一連の流れを設定 するように心がけてください(たとえば、ログインする前に改ざんできない キーを押すことを要求する、LED を点滅させて、改ざんできないパターン を表示する等)。 <p> <!-- Arbitrary email (including the ``from'' value of addresses) can be forged as well. Using digital signatures is a method to thwart many such attacks. A more easily thwarted approach is to require emailing back and forth with special randomly-created values, but for low-value transactions such as signing onto a public mailing list this is usually acceptable. --> 電子メール(「From」に書いてあるアドレスを含む)も改ざんできます。 そのような攻撃の多くは、電子署名を使えば防げます。 もっと簡単な防御は、電子メールにランダムに発生させた値を添付してやりとり する方法です。小額の金銭取引きもないような、公開メーリング・リストへの 登録ならば十分利用できます。 <p> <!-- If you need a trustworthy channel over an untrusted network, you need some sort of cryptologic service (at the very least, a cryptologically safe hash); see the section below on cryptographic algorithms and protocols. --> 信頼できないネットワーク越しに信頼できる経路を必要とするならば、何らかの 暗号作成技術の助けが必要となります(最低限でも暗号的に安全なハッシュ技術)。 下記のセクションにある「暗号アルゴリズムと通信プロトコル」を参照してください。 <p> <!-- Note that in any client/server model, including CGI, that the server must assume that the client can modify any value. For example, so-called ``hidden fields'' and cookie values can be changed by the client before being received by CGI programs. These cannot be trusted unless they are signed in a way the client cannot forge and the server checks the signature. --> 注意して欲しいのは、CGI があるクライアント/サーバー モデルで、クライアント がどんな値も変更できてしまうことです。サーバー側は常にこの点に気をつけていな ければなりません。 例をあげると、いわゆる「隠れフィールド」、クッキーなどは、CGI プログラムが 値を受け取る前にクライアント側で値を変更できてしまいます。 クライアントが偽造できない方法で署名をするか、サーバーが署名をチェックする のでなければ、これらの値を信用してはいけません。 <p> <!-- The routines getlogin(3) and ttyname(3) return information that can be controlled by a local user, so don't trust them for security purposes. --> getlogin(3)や ttyname(3)といった関数が返す値は、ローカルのユーザが制御でき てしまうので、セキュリティの用途としてこれらを信用してはいけません。 </sect1> <!-- <sect1>Use Internal Consistency-Checking Code --> <sect1>内部の整合性をチェックするコードを使用しましょう <p> <!-- The program should check to ensure that its call arguments and basic state assumptions are valid. In C, macros such as assert(3) may be helpful in doing so. --> プログラムは、呼び出す時に指定する引数や想定している基本状態が適切であること が保証されているかをチェックすべきです。 C では assert(3)のようなマクロが役に立つでしょう。 <!-- <sect1>Self-limit Resources --> <sect1>リソースを自主規制しましょう <p> <!-- In network daemons, shed or limit excessive loads. Set limit values (using setrlimit(2)) to limit the resources that will be used. At the least, use setrlimit(2) to disable creation of ``core'' files. Normally Linux will create a core file that saves all program memory if the program fails abnormally, but such a file might include passwords or other sensitive data. --> ネットワーク関連のデーモンでは、過負荷となる要求は拒否するか制限を設けま しょう。 限界値を設定して(setrlimit(2)を使って)使用されてしまうと予想されるリソースを 制限しましょう。 setrlimit(2)を使って「core」ファイルができないぐらいは最低限するようにして ください。 普通 Linux では core ファイルを作って、プログラムが異常終了したらそのすべて のメモリを保存するようにします。しかし core ファイルには、パスワードやその他 の注意が必要なデータがあるかもしれません。 </sect> <!-- <sect>Carefully Call Out to Other Resources --> <sect>他のリソースを利用する場合は慎重に <p> <!-- <sect1>Limit Call-outs to Valid Values --> <sect1>正しい値でだけ呼び出すこと <p> <!-- Ensure that any call out to another program only permits valid and expected values for every parameter. This is more difficult than it sounds, because there are many library calls or commands call lower-level routines in potentially surprising ways. For example, several system calls, such as popen(3) and system(3), are implemented by calling the command shell, meaning that they will be affected by shell metacharacters. Similarly, execlp(3) and execvp(3) may cause the shell to be called. Many guidelines suggest avoiding popen(3), system(3), execlp(3), and execvp(3) entirely and use execve(3) directly in C when trying to spawn a process [Galvin 1998b]. In a similar manner the Perl and shell backtick (`) also call a command shell. --> 別のプログラムを呼び出す場合は、そのプログラムが常にパラメタとして有効かつ 事前に予想されている値だけを許可しているかを確認する必要があります。 これは言うよりもずっと困難なことです。と言うのも、様々なライブラリ関数や コマンドが、低レベルの関数を意外なやり方で呼び出しているかもしれないからです。 たとえば popen(3)や system(3)のようなシステムコールのいくつかは、コマンド シェルを呼び出すように実装されています。つまりシェルのメタキャラクタがこれら のシステムコールに影響をおよぼすことを意味します。 同様に execlp(3)や execvp(3)もシェルを呼び出すしくみになっています。 ガイドラインの多くは popen(3)、system(3)、execlp(3)と execvp(3)をまったく 使用しないように提案していて、プロセスを生成する場合には execve(3)を C 言語 から直接呼び出すように提案しています [Galvin 1998b]。 同様な方法で Perl や シェルのバッククォート(`)もコマンドシェルを呼び出します。 <p> <!-- One of the nastiest examples of this problem are shell metacharacters. The standard Linux command shell interprets a number of characters specially. If these characters are sent to the shell, then their special interpretation will be used unless escaped; this fact can be used to break programs. According to the WWW Security FAQ [Stein 1999, Q37], these metacharacters are: --> この問題の厄介な例のひとつにシェルのメタキャラクタがあります。 標準的な Linux のコマンドシェルは、解釈を特別に行うキャラクタがたくさんあり ます。 シェルにこれらのキャラクタが渡ると、エスケープされていなければシェルは特別に 解釈します。この方法を使ってプログラムがしばしば壊されます。 WWW Security FAQ [Stein 1999, Q37] によると、メタキャラクタは以下のものです。 <verb> &ero; ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r </verb> <p> <!-- Forgetting one of these characters can be disastrous, for example, many programs omit backslash as a metacharacter [rfp 1999]. As discussed in the section on validating input, a recommended approach is to immediately escape at least all of these characters when they are input. --> これらのキャラクタの内 1 つでも忘れると、悲惨なことになるかもしれません。 たとえば、プログラムの多くはバックスラッシュをメタキャラクタとして扱うことを 怠っています[rfp 1999]。 入力の検証を説明したセクションで論じましたが、対策として、これらのキャラクタ が入力されたらすぐにエスケープすることをお勧めします。 <p> <!-- A related problem is that the NIL character (character 0) can have surprising effects. Most C and C++ functions assume that this character marks the end of a string, but string-handling routines in other languages (such as Perl and Ada95) can handle strings containing NIL. Since many libraries and kernel calls use the C convention, the result is that what is checked is not what is actually used [rfp 1999]. --> これと関連する問題として NIL キャラクタ(キャラクタの 0)が意外な影響を及ぼす ことがあげられます。 C や C++ の関数の大部分は、NIL キャラクタが文字列の終端の印と想定して いますが、他の言語(Perl や Ada95 など)の文字列を扱う関数は NIL を文字列の 一部として扱います。ライブラリやカーネルの呼び出しは C と同じ扱いを踏襲 していますので、チェックする内容と実際使用されることが一致していません [rfp 1999]。 <p> <!-- When calling another program or referring to a file always specify its full path (e.g, /usr/bin/sort). For program calls, this will eliminate possible errors in calling the ``wrong'' command, even if the PATH value is incorrectly set. For other file referents, this reduces problems from ``bad'' starting directories. --> 他のプログラムを呼び出したり、ファイルを参照したりする時は、いつもフルパス (たとえば /usr/bin/sort のように)で指定するようにしてください。 こうすることで、「間違った」コマンドを呼び出す際に生じるエラーを無くすことが できるだけでなく、PATH 環境変数が間違って設定されていてもエラーを回避でき ます。 他のファイルの参照についても、「間違った」開始パスを指定した結果生じる問題 を減らせます。 </sect1> <!-- <sect1>Check All System Call Returns --> <sect1>システムコールの返り値はすべてチェックしましょう <p> <!-- Every system call that can return an error condition must have that error condition checked. One reason is that nearly all system calls require limited system resources, and users can often affect resources in a variety of ways. Setuid/setgid programs can have limits set on them through calls such as setrlimit(3) and nice(2). External users of server programs and CGI scripts may be able to cause resource exhaustion simply by making a large number of simultaneous requests. If the error cannot be handled gracefully, then fail open as discussed earlier. --> システムコールでエラー状況を返せるものは、すべてそのエラー状態をチェックする 必要があります。 まず理由としてあげられるのは、システムコールのほとんどすべてが、制限をかけら れているシステム・リソースを対象としており、そのリソースに対してユーザは さまざまな方法で影響を与えることができてしまう点があります。 setuid/setgid されたプログラムには、setrlimit(3)や nice(2)のようなシステム コールを呼び出すことで、そのプログラムで使用するリソースに制限をかけること ができます。 サーバープログラムを利用する外部のユーザや CGI スクリプトは同時に多量のリクエ ストをサーバーに要求することで、リソースを食い潰すことができます。 エラーを適切に扱えていないならば、すでに述べた「フェイル・オープン」を参照 してください。 </sect1> </sect> <!-- <sect>Send Information Back Judiciously --> <sect>情報はえりすぐってフィードバックしましょう <p> <!-- <sect1>Minimize Feedback --> <sect1>フィードバックは最小限に <p> <!-- Avoid giving much information to untrusted users; simply succeed or fail, and if it fails just say it failed and minimize information on why it failed. Save the detailed information for audit trail logs. For example: --> 信頼できないユーザに対しては、多くの情報を提供しないようにしてください。ただ 成功したか、失敗したかを教えて、失敗しても失敗したと言うだけにして、なぜ失敗 したかについては、できるだけ教えないようにしてください。 詳細な情報はユーザの痕跡を検査したログに保存してください。 たとえば、 <itemize> <item> <!-- If your program requires some sort of user authentication (e.g., you're writing a network service or login program), give the user as little information as possible before they authenticate. In particular, avoid giving away the version number of your program before authentication. Otherwise, if a particular version of your program is found to have a vulnerability, then users who don't upgrade from that version advertise to attackers that they are vulnerable. --> プログラムに何らかのユーザ認証が必要な場合(たとえばネットワークサーバーや ログイン・プログラムを作成している)、認証前の段階では、ユーザにはできる だけ情報を与えないようにしてください。特に認証前にプログラムのバージョン ナンバーを漏らすことがないようにしてください。 そうしないと、特定のバージョンのプログラムに穴があることがわかってしまった 場合、ユーザがそのバージョンからアップグレードしないと攻撃者にみすみす穴を 教えてしまうことになってしまいます。 <item> <!-- If your program accepts a password, don't echo it back; this creates another way passwords can be seen. --> プログラムがパスワードを要求する場合、入力を表示してはいけません。パスワード がばれる原因の 1 つになってしまいます。 </itemize> </sect1> <!-- <sect1>Handle Full/Unresponsive Output --> <sect1>出力が溢れていたり、反応が遅い場合も対処すること <p> <!-- It may be possible for a user to clog or make unresponsive a secure program's output channel back to that user. For example, a web browser could be intentionally halted or have its TCP/IP channel response slowed. The secure program should handle such cases, in particular it should release locks quickly (preferably before replying) so that this will not create an opportunity for a Denial-of-Service attack. Always place timeouts on outgoing network-oriented write requests. --> 安全性が求められるプログラムがユーザへの出力をする過程を詰まらせたり、出力の 反応を遅くさせることは、ユーザでも行なえるはずです。 たとえば、Web ブラウザは故意に TCP/IP の経路を切断したり、反応速度を遅く したりできます。 そのようなケースにも安全性が求められるプログラムは対応するべきです。特に ロックはすみやかに外すようにすべきです(できれば反応を返す前に)。そうすれば、 サービス拒否攻撃(DoS 攻撃)に隙を与えないで済ませられます。 ネットワークへの書き込み要求についてはタイムアウトを常に設定すべきです。 </sect1> </sect> <!-- <sect>Special Topics --> <sect>トピック <!-- <sect1>Lockings --> <sect1>ロック <p> <!-- There are often situations in which a program must ensure that it has exclusive rights to something. On POSIX systems this is traditionally done by creating a file to indicate a lock, because this is portable to many systems. --> プログラムが何かに対して排他的に実行する権限を持っているかどうかの裏付けを 取らなければならない状況がよくあります。 POSIX システムでは、以前からロック状態を示すファイルを作成することで対処 してきました。それは多くのシステム間で互換性を取るにはよい方法だからです。 <p> <!-- However, there are several traps to avoid. First, a program with root privileges can open a file, even if it sets the O_EXCL mode (which normally fails if the file already exists). If that can happen, don't use open(2), use link(2) to create the file. If you just want to be sure that your server doesn't execute more than once on a given machine, consider creating a lockfile as /var/log/NAME.pid with the pid as its contents. This has the disadvantage of hanging around if the program prematurely halts, but it's common practice and is easily handled by other system tools. --> しかしこの方法にはいくつか避けなければならない落とし穴があります。 まず root 権限を持っているプログラムは、O_EXCL モード(通常ファイルが存在して いると失敗する)のファイルでもオープンできてしまいます。 そうなると open(2)を使わず link(2)を使用してファイルを作成する必要があります。 マシン上でサーバープログラムが 1 つだけしか実行できないことを確実に行いたい なら、/var/log/名前.pid という中身がそのプログラムの pid が書かれているロック ファイルを作成することを検討してみてください。 この方法は、プログラム予想外に中断して中途半端な状態になってしまう、という 欠点を抱えていますが、一般的に使用されており、他のシステムツールからでも簡単 に利用できます。 <p> <!-- Second, if the lock file may be on an NFS-mounted filesystem, then you have the problem that NFS doesn't completely support normal file semantics. The manual for <it>open(2)</it> explains how to handle things in this case (which also handles the case of root programs): --> 次に、ロックファイルが NFS でマウントされたファイルシステム上にある場合、 NFS が通常のファイルの機能を充分にはサポートしていない問題に悩まされること になります。 <it>open(2)</it>のマニュアルにどうしたらこの問題を解決できるかの説明が あります(root 権限のプログラムについての扱い方についても説明があります) <p> <quote> <!-- ... programs which rely on [the O_CREAT and O_EXCL flags of open(2)] for performing locking tasks will contain a race condition. The solution for performing atomic file locking using a lockfile is to create a unique file on the same filesystem (e.g., incorporating hostname and pid), use link(2) to make a link to the lockfile and use stat(2) on the unique file to check if its link count has increased to 2. Do not use the return value of the link(2) call. --> ... ロックをかけるのに「open(2)の O_CREAT and O_EXCL フラグ」に依存して いるプログラムは、競合状態に陥る問題を抱えています。 ロックファイルを使ってアトミックなファイルロッキングを行うには、 まず同じファイルシステム上にユニークなファイルを作り(たとえばホス ト名と pid を組み合わせます)、次にこのロックファイルに link(2)でリ ンクを張り、それからユニークなファイルに対して stat(2)を行ってリンク の参照数が 2 に増えていることを確認します。 link(2)の返り値を使うのは止めてください。 </quote> <!-- <sect1>Passwords --> <sect1>パスワード <p> <!-- Where possible, don't write code to handle passwords. In particular, if the application is local, try to depend on the normal login authentication by a user. If the application is a CGI script, depend on the web server to provide the protection. If the application is over a network, avoid sending the password as cleartext (where possible) since it can be easily captured by network sniffers and reused later. For networks, consider at least using digest passwords (which are vulnerable to active attack threats but protect against passive network sniffers). --> できるなら、パスワードを扱うコードは自前で書かないようにしてください。 特にローカルなアプリケーションの場合、通常行うユーザのログイン認証にまかせて しまってください。 アプリケーションが CGI スクリプトの場合、Web サーバーが用意している防御にまか せてください。 アプリケーションをネットワーク経由で利用するのものなら、平文でパスワードを 送ることを止めてください(可能なら)。というのはネットワークを盗聴することで、 いとも簡単に横取りされて後で使われてしまうからです。 ネットワークで利用するなら、少なくともダイジェスト・パスワードの使用を考えて ください(直接しかけてくる攻撃には弱いのですが、ネットワークの盗聴に対しては 有効です) <p> <!-- If your application must handle passwords, overwrite them immediately after use so they have minimal exposure. In Java, don't use the type String to store a password because Strings are immutable (they will not be overwritten until garbage-collected and reused, possibly a far time in the future). Instead, in Java use char[] to store a password, so it can be immediately overwritten. --> アプリケーションがパスワードを扱う必要があるなら、使ったらすぐ上書きして しまってください。そうすればパスワードを見られる時間が短くなります。 Java ではパスワードを保存しておくのに String 型を使わないようにしてください。 String 型は内容を変更できない型だからです(String 型は不要メモリ領域の整理や 再利用をしない限り上書きできない仕様で、今後もその仕様のままだと思います) そのかわり char[] を使って保存してください。この方法だとすぐにでも上書きでき ます。 <p> <!-- If your application permits users to set their passwords, check the passwords and permit only ``good'' passwords (e.g., not in a dictionary, having certain minimal length, etc.). You may want to look at information such as <url url="http://consult.cern.ch/writeup/security/security_3.html"> on how to choose a good password. --> アプリケーションでユーザがパスワードを設定できるのならパスワードをチェック して、「適切な」パスワードだけを許可してください(辞書に載っていない、一定 以上の文字数である、など)。 適切なパスワードの付け方を見つけたいなら、 <url url="http://consult.cern.ch/writeup/security/security_3.html"> を見てはどうでしょうか。 <!-- <sect1>Random Numbers --> <sect1>乱数 <p> <!-- The Linux kernel (since 1.3.30) includes a random number generator. The random number generator gathers environmental noise from device drivers and other sources into an entropy pool. When accessed as /dev/random, random bytes are only returned within the estimated number of bits of noise in the entropy pool (when the entropy pool is empty, the call blocks until additional environmental noise is gathered). When accessed as /dev/urandom, as many bytes as are requested are returned even when the entropy pool is exhausted. If you are using the random values for cryptographic purposes (e.g., to generate a key), use /dev/random. More information is available in the system documentation random(4). --> Linux カーネル(1.3.30 以上)には乱数生成機能があります。 乱数生成には周囲で発生するノイズをデバイスドライバや他の情報源から 収集してエントロピー・プールに収めます。 /dev/random にアクセスするとエントロピー・プールにあるノイズから推定 されたビット数の範囲でだけ、ランダムな値が返されてきます(エントロピー・ プールが空の場合は、周囲からノイズが集まってくるまで、呼び出しをブロック します)。 /dev/unrandom でアクセスして、大きな値を要求すると、エントロピー・プール が使い果たされても値が返ってきます。 乱数を暗号化の目的で利用するなら(たとえばキーの生成のため)、/dev/random を 使ってください。 さらに詳しい情報は、システムにあるオンラインマニュアルの random(4)を参照 してください。 <!-- <sect1>Cryptographic Algorithms and Protocols --> <sect1>暗号アルゴリズムと通信プロトコル <p> <!-- Often cryptographic algorithms and protocols are necessary to keep a system secure, particularly when communicating through an untrusted network such as the Internet. Where possible, use session encryption to foil session hijacking and to hide authentication information, as well as to support privacy. --> 暗号アルゴリズムと通信プロトコルは、システムの安全を維持するのに必要で、 特にインターネットのような信頼できないネットワークを経由してやりとりを 行う場合は必須です。 可能ならば通信セッションを暗号化し、セッション乗っ取りの裏をかいてください。 こうすれば認証情報を隠蔽でき、プライバシーの保護にも役立ちます。 <p> <!-- Cryptographic algorithms and protocols are difficult to get right, so do not create your own. Instead, use existing standard-conforming protocols such as SSL, SSH, IPSec, GnuPG/PGP, and Kerberos. Use only encryption algorithms that have been openly published and withstood years of attack (examples include triple DES, which is also not encumbered by patents). In particular, do not create your own encryption algorithms unless you are an expert in cryptology and know what you're doing; creating such algorithms is a task for experts only. --> きちんとした暗号化アルゴリズムや通信プロトコルを作り上げるには困難がともない ますので、自分で作ろうとはしないでください。 そのかわりに、一般的に信頼性が確立されている既存のプロトコルである、SSL、SSH、 IPSec、GnuPG/PGP や Kerberos を利用してください。 広く公開され、長年の攻撃に耐えてきた符号化アルゴリズムだけを使ってください (たとえばトリプル DES など、特許による利用の妨げがないもの)。 特に、自分が暗号化の専門家で、何をしているかを把握しているのでなければ、 符号化アルゴリズムを作成するようなことはしないでください。 この種のアルゴリズムの作成は、専門家だけに許された作業です。 <p> <!-- In a related note, if you must create your own communication protocol, examine the problems of what's gone on before. Classics such as Bellovin [1989]'s review of security problems in the TCP/IP protocol suite might help you, as well as Bruce Schneier [1998] and Mudge's breaking of Microsoft's PPTP implementation and their follow-on work. Of course, be sure to give any new protocol widespread review, and reuse what you can. --> 関連して、どうしても独自に通信プロトコルを開発しなければならないなら、 過去に起きた問題事例の調査をしてください。 Bellovin [1989] に載っている TCP/IP プロトコルにおけるセキュリティについての レビューのような古典的な資料や Bruce Schneier [1998] が役に立つと思います。 また、Mudge 氏によるマイクロソフト社の PPTP の実装破りやその後の推移も 参考になると思います。 <p> <bf>訳註:</bf>Mudge 氏は、L0pht Heavy Industries という超ハッカー(クラッカー ? 評価が別れているようです)集団の主任科学者でした。現在は @Stake というセキュリティ関連のサービスを提供する会社で研究開発担当副社長をして います。 <p> もちろん新しいプロトコルに対しては、広くレビューを行うべきで、できるなら 再利用してください。 <sect1>Java <p> <!-- Some security-relevant programs on Linux may be implemented using the Java language and/or the Java Virtual Machine (JVM). Developing secure programs on Java is discussed in detail in material such as Gong [1999]. The following are a few key points extracted from Gong [1999]: --> Linux 上のセキュリティに関係したプログラムの中には Java や Java バーチャル・ マシン(JVM)を使って実装されているものがあります。 Java で安全性を要求されるプログラムを書くには Gong [1999] 他の資料で詳細 が述べられています。 下記に Gong [1999] から抜粋したキーポイントをあげておきます。 <itemize> <!-- <item>Do not use public fields or variables; declare them as private and provide accessors to them so you can limit their accessibility. <item>Make methods private unless these is a good reason to do otherwise. <item>Avoid using static field variables. Such variables are attached to the class (not class instances), and classes can be located by any other class. As a result, static field variables can be found by any other class, making them much more difficult to secure. <item>Never return a mutable object to potentially malicious code (since the code may decide to change it). --> <item>public なフィールドや変数を使わないこと。利用する側に private で宣言 して提供すれば、結果としてアクセスに制限をかけられる <item>特に理由がない限り private メソッドにすること <item>static なフィールド変数の使用は避けること。そのような変数はクラスに 従属しており(クラスのインスタンスではない)、クラスは他のクラスと 相互関係を持つ。 結果として、static な変数はその変数が属していない他のクラスから 参照できてしまい、安全の確保が困難になる <item>不正なものとなる可能性を持ったコードに対して mutable オブジェクトを 返してはならない(そのコードが内容を変更してしまう恐れがあるため) </itemize> </sect1> <sect1>PAM <p> <!-- Most Linux distributions include PAM (Pluggable Authentication Modules), a flexible mechanism for authenticating users. This includes Red Hat Linux, Caldera, Debian as of version 2.2; note that FreeBSD also supports PAM as of version 3.1. By using PAM, your program can be independent of the authentication scheme (passwords, SmartCards, etc.). Basically, your program calls PAM, which at run-time determines which ``authentication modules'' are required by checking the configuration set by the local system administrator. If you're writing a program that requires authentication (e.g., entering a password), you should include support for PAM. You can find out more about the Linux-PAM project at <url url="http://www.kernel.org/pub/linux/libs/pam/index.html">. --> Linux ディストリビューションのほとんどは、PAM(Pluggable Authentication Modules)を持っており、ユーザの認証に柔軟に対応できるしくみになっています。 カーネルのバージョンが 2.2 系列である Red Hat Linux、Caldera、Debian が採用 しており、FreeBSD のバージョン 3.1 も採用しています。 PAM を使うと、プログラムと認証のしくみ(パスワードやスマート・カード)を独立 したものにできます。 つまり、プログラムは PAM を呼び出し、PAM がローカルシステムの管理者が設定した 内容をチェックし、どの「認証モジュール」が必要かをランタイムに判断します。 認証が必要となるプログラム(たとえばパスワードを入力する)を作成しているなら、 PAM を採用すべきです。 詳細は、Linux-PAM プロジェクトの Web サイトである、 <url url="http://www.kernel.org/pub/linux/libs/pam/index.html"> を参照してください。 </sect1> <!-- <sect1>Miscellaneous --> <sect1>その他 <p> <!-- Have your program check at least some of its assumptions before it uses them (e.g., at the beginning of the program). For example, if you depend on the ``sticky'' bit being set on a given directory, test it; such tests take little time and could prevent a serious problem. If you worry about the execution time of some tests on each call, at least perform the test at installation time. --> 前提条件の少なくとも一部は、使う前にプログラムにチェックさせてください (たとえば、プログラムが開始されるところで)。 たとえば、あるディレクトリで「sticky」ビットが立っていることを前提にしている なら、本当にそうなっているかをテストしてください。テストに時間はかからない ですし、それによって深刻な問題を防ぐことができるはずです。 もしそれぞれの呼び出しでテスト実行時間がかかることが気になるなら、インストール 時には最低限行うようにしてください。 <p> <!-- Write audit logs for program startup, session startup, and for suspicious activity. Possible information of value includes date, time, uid, euid, gid, egid, terminal information, process id, and command line values. You may find the function syslog(3) helpful for implementing audit logs. --> 監査ログはプログラム起動時やセッション開始時、動作が怪しげな時に書き込むよう にしてください。 情報として考えられるものは、年月日、時刻、uid、euid、gid、egid、端末情報、 プロセス id、コマンドラインの値です。 監査ログを採るに当たっては、syslog(3)関数が参考になると思います。 <p> <!-- Have installation scripts install a program as safely as possible. By default, install all files as owned by root or some other system user and make them unwriteable by others; this prevents non-root users from installing viruses. Allow non-root installation where possible as well, so that users without root permission and administrators who do not fully trust the installer to still use the program. --> インストール・スクリプトはできるだけ安全にプログラムをインストールして ください。 デフォルトでは、インストールするファイルすべてを root か他のシステム管理 ユーザの所有にして、他のユーザが書き込みができないようにしてください。 こうすれば root 以外のユーザはウイルスをインストールできません。 root 以外のユーザがインストールできる場所も用意しておいておけば、root の権限 を持たないユーザやインストーラを信じきれない管理者でもプログラムを使えるよう になります。 <p> <!-- If possible, don't create setuid or setgid root programs; make the user log in as root instead. --> 可能であれば、root に setuid や setgid されたプログラムは作らないでください。 ユーザには root でログインするようにさせてください。 <p> <!-- Sign your code. That way, others can check to see if what's available was what was sent. --> コードに電子署名をしてください。そうすれば利用者は送られてきたものが利用できる ものかどうかをチェックできます。 <p> <!-- Consider statically linking secure programs. This counters attacks on the dynamic link library mechanism by making sure that the secure programs don't use it. --> 安全性が求められるプログラムを作成する場合に静的にリンクを行うことを検討して みてください。 安全性が求められるプログラムが動的リンクを使わないようにすれば、動的なライブ ラリのリンク機能を狙った攻撃に対抗できます。 <p> <!-- When reading over code, consider all the cases where a match is not made. For example, if there is a switch statement, what happens when none of the cases match? If there is an ``if'' statement, what happens when the condition is false? --> コードを眺めている時には条件にマッチしないケースすべてを検討してください。 たとえば switch 文があった場合、どのケースにもマッチしなかった場合どうなる のか? 「if」文があって条件が偽だった場合、どのように処理されるか? <p> <!-- Ensure the program works with compile-time and run-time checks turned on, and leave them on where practical. Perl programs should turn on the warning flag (-w), which warns of potentially dangerous or obsolete statements, and possibly the taint flag (-T), which prevents the direct use of untrusted inputs without performing some sort of filtering. Security-relevant programs should compile cleanly with all warnings turned on. For C or C++ compilations using gcc, use at least the following as compilation flags (which turn on a host of warning messages) and try to eliminate all warnings: --> プログラムをコンパイルする時や実行する時にチェック機能を確実に働かせるように して、本番で動かす時もそうしておいてください。 Perl のプログラムなら警告フラグ(-w)をつけるべきです。そうすると危険になる かもしれないコードやすでに古い文法になってしまった式に対して警告を出してくれ ます。また汚染予防フラグ(-T)をつけると、何らかのフィルタリングをかけない限り、 信頼できない入力を直接使用できなくなります。 セキュリティ関連のプログラムは警告をすべて有効にして警告が出ないように コンパイルすべきです。 gcc を使って C や C++ をコンパイルするには、少なくとも下記のコンパイル時の フラグを使用してください(多数の警告メッセージを有効にして、警告すべてを 潰してください)。 <verb> gcc -Wall -Wpointer-arith -Wstrict-prototypes </verb> </sect1> </sect> <!-- maybe someday add Logging discussion --> <!-- <sect>Conclusions --> <sect>結論 <p> <!-- Designing and implementing a truly secure program is actually a difficult task on Linux. The difficulty is that a truly secure program must respond appropriately to all possible inputs and environments controlled by a potentially hostile user. This is not a problem unique to Linux; other general-purpose operating systems (such as Unix and Windows NT) present developers with similar challenges. Developers of secure programs must deeply understand their platform, seek and use guidelines (such as these), and then use assurance processes (such as peer review) to reduce their programs' vulnerabilities. --> 完璧に安全なプログラムを Linux 上で設計して実装するのは、本当に困難な作業 です。 完璧に安全なプログラムが難しい訳は、考えられるすべての入力と敵意を持っている かもしれないユーザがコントロールしている環境に対して、適切に対応しなければ ならないところにあります。 これは Linux 固有の問題ではありません。 他の汎用的なオペレーティングシステム(UNIX や Windows NT など)も開発者に 対して同様な難問を突きつけています。 安全性が求められるプログラムの開発者は使用しているプラットフォームについて 深く理解して、ガイドライン(このドキュメントなど)を調べて適用し、品質を 上げるプロセスを設けて(ピア・レビューなど)、プログラムの脆弱なところを 減らして行く必要があります。 </sect> <!-- <sect>References --> <sect>参考文献 <p> <!-- <it>Note that there is a heavy emphasis on technical articles available on the web, since this is where most of this kind of technical information is available. --> <it>注意して欲しいのは、ここでは Web サイトで利用可能な技術文献を中心に あげていることです。技術的な情報のほとんどが Web サイトから入手できる からです。 </it> [Al-Herbish 1999] Al-Herbish, Thamer. 1999. <it>Secure Unix Programming FAQ</it>. <url url="http://www.whitefang.com/sup">. [Aleph1 1996] Aleph1. November 8, 1996. ``Smashing The Stack For Fun And Profit.'' <it>Phrack Magazine</it>. Issue 49, Article 14. <url url="http://www.phrack.com/search.phtml?view&article=p49-14"> or alternatively <url url="http://www.2600.net/phrack/p49-14.html">. [Anonymous unknown] <it>SETUID(7)</it> <url url="http://www.homeport.org/~adam/setuid.7.html">. <!-- Claimed to be from Dan Farmer's COPS, but COPS does not include it. --> [AUSCERT 1996] Australian Computer Emergency Response Team (AUSCERT) and O'Reilly. May 23, 1996 (rev 3C). <it>A Lab Engineers Check List for Writing Secure Unix Code</it>. <url url="ftp://ftp.auscert.org.au/pub/auscert/papers/secure_programming_checklist"> [Bach 1986] Bach, Maurice J. 1986. <it>The Design of the Unix Operating System</it>. Englewood Cliffs, NJ: Prentice-Hall, Inc. ISBN 0-13-201799-7 025. [Bellovin 1989] Bellovin, Steven M. April 1989. "Security Problems in the TCP/IP Protocol Suite" Computer Communications Review 2:19, pp. 32-48. <url url="http://www.research.att.com/~smb/papers/ipext.pdf"> [Bellovin 1994] Bellovin, Steven M. December 1994. <it>Shifting the Odds -- Writing (More) Secure Software</it>. Murray Hill, NJ: AT&T Research. <url url="http://www.research.att.com/~smb/talks"> [Bishop 1996] Bishop, Matt. May 1996. ``UNIX Security: Security in Programming.'' <it>SANS '96</it>. Washington DC (May 1996). <url url="http://olympus.cs.ucdavis.edu/~bishop/secprog.html"> [Bishop 1997] Bishop, Matt. October 1997. ``Writing Safe Privileged Programs.'' <it>Network Security 1997</it> New Orleans, LA. <url url="http://olympus.cs.ucdavis.edu/~bishop/secprog.html"> [CC 1999] <it>The Common Criteria for Information Technology Security Evaluation (CC)</it>. August 1999. Version 2.1. Technically identical to International Standard ISO/IEC 15408:1999. <url url="http://csrc.nist.gov/cc/ccv20/ccv2list.htm"> [CERT 1998] Computer Emergency Response Team (CERT) Coordination Center (CERT/CC). February 13, 1998. <it>Sanitizing User-Supplied Data in CGI Scripts</it>. CERT Advisory CA-97.25.CGI_metachar. <url url="http://www.cert.org/advisories/CA-97.25.CGI_metachar.html">. [CMU 1998] Carnegie Mellon University (CMU). February 13, 1998 Version 1.4. ``How To Remove Meta-characters From User-Supplied Data In CGI Scripts.'' <url url="ftp://ftp.cert.org/pub/tech_tips/cgi_metacharacters">. [Cowan 1999] Cowan, Crispin, Perry Wagle, Calton Pu, Steve Beattie, and Jonathan Walpole. ``Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade.'' Proceedings of DARPA Information Survivability Conference and Expo (DISCEX), <url url="http://schafercorp-ballston.com/discex"> To appear at SANS 2000, <url url="http://www.sans.org/newlook/events/sans2000.htm">. For a copy, see <url url="http://immunix.org/documentation.html">. [Fenzi 1999] Fenzi, Kevin, and Dave Wrenski. April 25, 1999. <it>Linux Security HOWTO</it>. Version 1.0.2. <url url="http://www.linuxdoc.org/HOWTO/Security-HOWTO.html"> [FreeBSD 1999] FreeBSD, Inc. 1999. ``Secure Programming Guidelines.'' <it>FreeBSD Security Information</it>. <url url="http://www.freebsd.org/security/security.html"> [FSF 1998] Free Software Foundation. December 17, 1999. <it>Overview of the GNU Project</it>. <url url="http://www.gnu.ai.mit.edu/gnu/gnu-history.html"> [Galvin 1998a] Galvin, Peter. April 1998. ``Designing Secure Software''. <it>Sunworld</it>. <url url="http://www.sunworld.com/swol-04-1998/swol-04-security.html">. [Galvin 1998b] Galvin, Peter. August 1998. ``The Unix Secure Programming FAQ''. <it>Sunworld</it>. <url url="http://www.sunworld.com/sunworldonline/swol-08-1998/swol-08-security.html"> [Garfinkel 1996] Garfinkel, Simson and Gene Spafford. April 1996. <it>Practical UNIX & Internet Security, 2nd Edition</it>. ISBN 1-56592-148-8. Sebastopol, CA: O'Reilly & Associates, Inc. <url url="http://www.oreilly.com/catalog/puis"> [Gong 1999] Gong, Li. June 1999. <it>Inside Java 2 Platform Security</it>. Reading, MA: Addison Wesley Longman, Inc. ISBN 0-201-31000-7. [Gundavaram Unknown] Gundavaram, Shishir, and Tom Christiansen. Date Unknown. <it>Perl CGI Programming FAQ</it>. <url url="http://language.perl.com/CPAN/doc/FAQs/cgi/perl-cgi-faq.html"> [Kim 1996] Kim, Eugene Eric. 1996. <it>CGI Developer's Guide</it>. SAMS.net Publishing. ISBN: 1-57521-087-8 <url url="http://www.eekim.com/pubs/cgibook"> [McClure 1999] McClure, Stuart, Joel Scambray, and George Kurtz. 1999. <it>Hacking Exposed: Network Security Secrets and Solutions</it>. Berkeley, CA: Osbourne/McGraw-Hill. ISBN 0-07-212127-0. [Miller 1999] Miller, Todd C. and Theo de Raadt. ``strlcpy and strlcat -- Consistent, Safe, String Copy and Concatenation'' <it>Proceedings of Usenix '99</it>. <url url="http://www.usenix.org/events/usenix99/millert.html"> and <url url="http://www.usenix.org/events/usenix99/full_papers/millert/PACKING_LIST"> [Mudge 1995] Mudge. October 20, 1995. <it>How to write Buffer Overflows</it>. l0pht advisories. <url url="http://www.l0pht.com/advisories/bufero.html">. [OSI 1999]. Open Source Initiative. 1999. <it>The Open Source Definition</it>. <url url="http://www.opensource.org/osd.html">. [Pfleeger 1997] Pfleeger, Charles P. 1997. <it>Security in Computing.</it> Upper Saddle River, NJ: Prentice-Hall PTR. ISBN 0-13-337486-6. [Phillips 1995] Phillips, Paul. September 3, 1995. <it>Safe CGI Programming</it>. <url url="http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txt"> [Raymond 1997] Raymond, Eric. 1997. <it>The Cathedral and the Bazaar</it>. <url url="http://www.tuxedo.org/~esr/writings/cathedral-bazaar"> [Raymond 1998] Raymond, Eric. April 1998. <it>Homesteading the Noosphere</it>. <url url="http://www.tuxedo.org/~esr/writings/homesteading/homesteading.html"> [Ranum 1998] Ranum, Marcus J. 1998. <it>Security-critical coding for programmers - a C and UNIX-centric full-day tutorial</it>. <url url="http://www.clark.net/pub/mjr/pubs/pdf/">. [RFC 822] August 13, 1982 <it>Standard for the Format of ARPA Internet Text Messages</it>. IETF RFC 822. <url url="http://www.ietf.org/rfc/rfc0822.txt">. [rfp 1999]. rain.forest.puppy. ``Perl CGI problems.'' <it>Phrack Magazine</it>. Issue 55, Article 07. <url url="http://www.phrack.com/search.phtml?view&article=p55-7">. [Saltzer 1974] Saltzer, J. July 1974. ``Protection and the Control of Information Sharing in MULTICS.'' <it>Communications of the ACM</it>. v17 n7. pp. 388-402. [Saltzer 1975] Saltzer, J., and M. Schroeder. September 1975. ``The Protection of Information in Computing Systems.'' <it>Proceedings of the IEEE</it>. v63 n9. pp. 1278-1308. Summarized in [Pfleeger 1997, 286]. [Schneier 1998] Schneier, Bruce and Mudge. November 1998. <it>Cryptanalysis of Microsoft's Point-to-Point Tunneling Protocol (PPTP)</it> Proceedings of the 5th ACM Conference on Communications and Computer Security, ACM Press. <url url="http://www.counterpane.com/pptp.html">. [Schneier 1999] Schneier, Bruce. September 15, 1999. ``Open Source and Security.'' <it>Crypto-Gram</it>. Counterpane Internet Security, Inc. <url url="http://www.counterpane.com/crypto-gram-9909.html"> [Seifried 1999] Seifried, Kurt. October 9, 1999. <it>Linux Administrator's Security Guide</it>. <url url="http://www.securityportal.com/lasg">. [Shostack 1999] Shostack, Adam. June 1, 1999. <it>Security Code Review Guidelines</it>. <url url="http://www.homeport.org/~adam/review.html">. [Sitaker 1999] Sitaker, Kragen. Feb 26, 1999. <it>How to Find Security Holes</it> <url url="http://www.pobox.com/~kragen/security-holes.html"> and <url url="http://www.dnaco.net/~kragen/security-holes.html"> [SSE-CMM 1999] SSE-CMM Project. April 1999. <it>System Security Engineering Capability Maturity Model (SSE CMM) Model Description Document</it>. Version 2.0. <url url="http://www.sse-cmm.org"> [Stein 1999]. Stein, Lincoln D. September 13, 1999. <it>The World Wide Web Security FAQ</it>. Version 2.0.1 <url url="http://www.w3.org/Security/Faq/www-security-faq.html"> [Thompson 1974] Thompson, K. and D.M. Richie. July 1974. ``The UNIX Time-Sharing System.'' <it>Communications of the ACM</it> Vol. 17, No. 7. pp. 365-375. <!-- Revised and reprinted in Ritchie 1978a; see Bach 1986 --> [Torvalds 1999] Torvalds, Linus. February 1999. ``The Story of the Linux Kernel.'' <it>Open Sources: Voices from the Open Source Revolution</it>. Edited by Chris Dibona, Mark Stone, and Sam Ockman. O'Reilly and Associates. ISBN 1565925823. <url url="http://www.oreilly.com/catalog/opensources/book/linus.html"> [Webber 1999] Webber Technical Services. February 26, 1999. <it>Writing Secure Web Applications</it>. <url url="http://www.webbertech.com/tips/web-security.html">. [Wood 1985] Wood, Patrick H. and Stephen G. Kochan. 1985. <it>Unix System Security</it>. Indianapolis, Indiana: Hayden Books. ISBN 0-8104-6267-2. [Wreski 1998] Wreski, Dave. August 22, 1998. <it>Linux Security Administrator's Guide</it>. Version 0.98. <url url="http://www.nic.com/~dave/SecurityAdminGuide/index.html"> </sect> <!-- <sect>Document License --> <sect>ドキュメントのライセンス <P> <!-- This document is Copyright (C) 1999-2000 David A. Wheeler and is covered by the GNU General Public License (GPL). You may redistribute it freely. Interpret the document's source text as the ``program'' and adhere to the following terms: --> このドキュメントは David A. Wheeler が著作権((C) 1999-2000 David A. Wheeler) を保持しています。また GNU General Public License (GPL) によってその権利は 保護されています。自由に再配布が可能です。ドキュメントの原文を「プログラム」 と見なして、下記の条件を厳守してください。 <tscreen><verb> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA </verb></tscreen> </sect> <sect>日本語版謝辞 <p> この翻訳を行うに当たって下記の方々にお世話になりました。この場を借りて お礼申し上げます。 <itemize> <item>川嶋さん <item>後藤雅晴さん <item>高城@長野高専さん <item>千旦さん <item>山下さん <item>藤原さん(旧版の翻訳も参考にさせていただきました) <item>水原さん </itemize> <P> </article>