システム開発とセキュリティ(3)
セキュアJavaプログラミング
Javaとは
狭義ではオブジェクト指向プログラミング言語Javaを、広義ではプログラミング言語Javaのプログラムの実行環境および開発環境をいう。
特徴
- 構文はCおよびC++から多くを引き継いでいる。ただし、ポインタ等の低レベルな操作は基本文法から排除されている。
- オブジェクト指向プログラミングをサポートしている。オブジェクトモデルはSmalltalkや Objective-C と同様の簡潔なものを採用している。
- 機械語に直接コンパイルされるのではなく、中間言語にコンパイルされ、仮想マシンの上で動作する。これにより、プラットフォームに依存しないアプリケーションソフトウェアが開発できる。
- 簡潔なメモリモデルを採用しており、プログラマがメモリを管理する必要がない。あらゆるオブジェクトはメモリ内のヒープという領域に割り当てられ、メモリ管理は、Java仮想マシンに統合されたガベージコレクションの機能によって行われる。
- プラットフォームに依存しないアプリケーションソフトウェアの開発と配備を行うことができる。 従来のプログラミング言語の多くはプラットフォーム(CPU)に依存したネイティブなコードにコンパイルすることを前提として設計されていたが、Javaはこうした言語と異なり、中間言語(バイトコード)にコンパイルされ、Java仮想マシンで実行される
Javaのセキュリティ設計
Javaはセキュリティを考慮して設計され、サンドボックスモデルに基づいたセキュリティ機構を備えている。セキュリティ機構を正しく実装したJava実行環境を適切に使うことで、遠隔のコンピュータ上にある実行コードを安全に実行できる(Javaアプレット)。
サンドボックス(sandbox)
コンピュータセキュリティ技術において、外部から受け取ったプログラムを保護された領域で動作させることによってシステムが不正に操作されるのを防ぐセキュリティ機構のこと。 実行されるプログラムは保護された領域に入り、ほかのプログラムやデータなどを操作できない状態にされて動作するため、プログラムが暴走したりウイルスを動作させようとしてもシステムに影響が及ばないようになっている。
クラスローダ
クラスのロードやリソース(ファイル)の検索を担当するオブジェクト。クラスは使用される前に必ずクラスローダによってJVM(Java Virtual Machine)のメモリ空間上にロードされる。 JVMが開始されると、3つのクラスローダが使用される
・ブートストラップクラスローダー | : | 中核のJavaライブラリをロードする |
・拡張クラスローダ | : | 拡張ディレクトリにあるコードをロードする |
・システムクラスローダ | : | システムCLASSPATH 変数にあるクラスをロードする |
※規定では、ユーザのクラスは全てシステムクラスローダからロードされるが、ユーザが定義した クラスローダに置き換えたり、さらにクラスローダの連結構造もユーザ定義することができる。
セキュリティマネージャ(java.lang.SecurityManager)
信頼されていないコードを実行することでローカルファイルシステム上にあるファイルへとアクセスしたり、Javaアプレットのダウンロード元のホスト以外と通信して情報を送受信したりといったことができないように、Javaアプレットがサンドボックス内で実行できるようにする機構
ポリシ(セキュリティポリシ)
ポリシとは、各コードがどのようなアクセス権を使用できるかを指定するもの。Policyオブジェクトにより表現され、デフォルトの実装では、一つまたは複数のポリシ構成ファイルから指定できる
アクセスコントローラ
ポリシに基づいたアクセス制御の操作と決定に使用される。それぞれのクラス、メソッド、フィールドの「使用範囲」を決めることで「して欲しくない処理をされる」ことを防ぐことができる
クラスライブラリ
Javaでは、パーミッションクラス(java.security. Permission)によって、システム資源へのアクセス権を表す。"java.security. Permission"クラス自体はabstractクラスで、このクラスから特定のアクセス権を表すサブクラスが作成される。"java.security. Permission"クラスには、"java.security. PermissionCollection"というabstractクラスと"java.security. Permission"というfinalクラスが関連する。
abstractクラス
サブクラスが作成されるが処理内容がまだ定義されていない(決まっていない)クラスのこと。
finalクラス
finalクラスを宣言するとそのクラスはサブクラスで継承できなくなる
Javaで初めから用意されているStringクラスや、Mathクラスはfinalが付与されており、サブクラスが作成されないようになっている
※※finalを使用する理由※※
- セキュリティ上の問題
プログラムに不正動作を与えようとするハッカーたちの一つの手段としてあるクラスのサブクラスを作成し、そのサブクラスに不正な動作を行わせる - 技術力が未熟な人がサブクラスを作成し、予期せぬ動作をするプログラムが作成されることを防ぐ
ポリシとパーミッション
Javaのセキュリティ機能は、ポリシとパーミッションに基づいてアクセス制御を行う。セキュリティマネージャの管理下で、各クラスが行おうとするシステムリソースへのアクセスをポリシーファイルに記述されたパーミッション(=アクセス許可)の範囲内に制限することである。
パーミッションの種類
パーミッションはクラスの形をとる。javaには次のパーミッションのクラスが用意されている
パッケージ | クラス | 説明 |
---|---|---|
java.security. | AllPermission | 全ての特権を許可 |
javax.sound.sampled. | AudioPermission | オーディオの録音・再生を許可 |
java.awt. | AWTPermission | AWTに関する各種操作を許可 |
java.io. | FilePermission | 特定のファイルへのアクセスを許可 |
java.net. | NetPermission | WWWクライアントとしてのネットワーク操作を許可 |
java.util. | PropertyPermission | プロパティの読み書きの許可 |
java.lang.reflect. | ReflectPermission | 保護指定を無視してオブジェクトにアクセス |
java.lang. | RuntimePermission | 実行環境に関わる各種操作を許可 |
java.security. | SecurityPermission | セキュリティ機能に関わる各種操作を許可 |
java.io. | SerializablePermission | シリアル化においてカスタム処理を行うことを許可 |
java.net. | SocketPermission | 特定のソケット通信を許可 |
java.sql. | SQLPermission | ロギングストリームの設定を許可 |
ポリシーファイルを記述する際、アプリケーションプログラムのクラスに対しこれらのパーミッションを与えないでおくことで、特権的機能の大半は禁止することができる。ただし、java.lang.reflect.Method クラスでメソッドをオブジェクトにして持ち運ぶ機能など、禁止することができない操作もいくつかある
危険なパーミッション
パーミッションによっては、それを与えることでアプリケーションのクラスが大きな特権を持ちすぎてしまい危険を招くことがある。特に注意すべきパーミッションは次のようなものである。これらは原則としてどのクラスにも与えない方がよい。
java.security.AllPermission
このパーミッションは全ての特権を許可するものであり、非常に危険である。
java.io.FilePermission("
")
ターゲットが「」のFilePermission を与えると、そのクラスはJava VM がアクセスできるファイルなら、ローカルファイルシステムのどのファイルにもアクセスできるようになる。プラットフォームOSに対する干渉が可能であることと、各種アクセス許可が記述されたポリシーファイルそのものが改ざんされるおそれがあるので非常に危険である
java.net.SocketPermission("*","accept,connect")
"*","accept,connect"が伴うSocketPermissionは、全てのホストの全てのポートを意味するターゲット「*」との接続(connect)および全てのポートでの接続の待ち受け(accept)を許可することを意味する。このようなパーミッションを与えてしまうと、ソケット通信におけるセキュリティが無効になる。
java.lang.RuntimePermission
このパーミッションは、実行環境への各種の操作を許可するものである。
ターゲット名 | 可能になる操作 | 権限を与えた場合のリスク |
---|---|---|
createClassLoader | クラスローダの作成 | 悪意のあるアプリケーションが独自のクラスローダのインスタンスを作成し、破壊行為等をするクラスをシステムにロードする可能性がある |
setSecurityManager | セキュリティマネージャの設定(既存のセキュリティマネージャの差し替えも含む | 自分にとって都合のよい(制約の少ないなど)別のセキュリティマネージャを勝手に使用できるようになる |
exitVM | Jave Virtual Machineの停止 | 攻撃者がJava VMを強制停止させるDos攻撃を仕掛ける可能性がある |
java.security.SecurityPermission("setPermission")
ターゲットが「setPermission」のSecurityPermissionを与えると,プログラムが自分に対するアクセス許可を変更することができるので危険である
クラスライブラリ Javaのクラスライブラリには豊富な機能が揃っている 規模の大きなソフトウェアを開発する際は、これらの強力な機能を乱用・誤用するコードが混入して、データの機密が損なわれたりシステムのコントロールが奪われたりしないよう注意する必要がある |
カプセル化
Javaをはじめとするオブジェクト指向プログラミング言語の特徴は,関係の深いデータとプログラム処理をオブジェクトという「いれもの」に収容できるところにある。オブジェクトに収容したフィールドとメソッドは、クラスの外からの干渉を受けないよう保護できる。このようにオブジェクトという容器の中に入れて保護することを「カプセル化」(encapsulation)と呼ぶ
個人情報や商取引の内容などの重要なデータを扱うプログラムでは、故意あるいは事故でデータが損なわれないよう、Java のカプセル化機能を大いに活用すべきである
リードオンリーインタフェース
オブジェクトに対するメソッド呼び出しに一定の制限をかけたいときに活用するものが、Javaのinterface(インタフェース)と呼ばれる仕組み
インタフェースはひと揃いのメソッドの宣言を持つだけの存在であるが、これを使うとインタフェースに明記されたメソッド群だけを使ってオブジェクトの実体を操作するよう、プログラムに強制することが可能になる。すなわち、インタフェースを通じてオブジェクトにアクセスしている間は、オブジェクト本体が多くのものを持っているとしても、インタフェースに明示されたもの以外のメソッドは呼び出せない
カプセル化 Javaをはじめとするオブジェクト指向プログラミング言語の基本的な特徴は、オブジェクトというカプセルの中に重要なデータを保管し、故意または過失により損なわれないようにする仕組みを持っている オブジェクトはもともとフィールドとメソッドを保護する仕組みである。クラスの外部に許すアクセスは必要最低限になるよう、メソッドのラインナップを工夫する。特に重要な情報を扱うオブジェクトについてはリードオンリーインタフェースを用いる方法がある インタフェースやクラスはソースコードの監査が行いやすいよう命名しておく |
レースコンディション
マルチスレッド処理で起こるレースコンディション問題は見つけにくいバグであり、セキュリティ脆弱性として潜在した場合大変やっかいである。Javaプログラムではsynchronizedメソッドにより簡単にスレッド同期をはかることができる。ただし、使い過ぎると性能が落ちることもあるので注意が必要
マルチスレッド
スレッドとは、プログラム実行の単一の流れのこと。たいていのコンピュータでは同時並行で複数のスレッドが動いており、このような動作形態のことをマルチスレッドという。Java はプログラミング言語としてこのスレッドの取り扱いをサポートしている
新しいスレッドのクラスを作成するには、java.lang.Threadクラスを継承したクラスか、java.lang.Runnableインターフェイスを実装したクラスを定義する
レースコンディション問題
マルチスレッドアプリケーションでは、レースコンディション問題が発生する可能性がある
レースコンディション問題とは、暫くの間不変に保たれているはずの何らかの条件が他者の干渉によって変えられてしまう不具合のこと。マルチスレッドプログラミングの場合は、同時にアクセスされることを想定していなかった変数に対して実際には複数スレッドから並行でアクセスが行われてしまったなどの場合にこうした問題が起こる
レースコンディションとセキュリティ脆弱性
レースコンディション問題はその発生が一定しておらず、場合によっては検出しにくいものやごく限られた条件下でしか起こらない不具合については人間の目で見つけることが困難である
レースコンディション問題により、まれにセキュリティ上の防御が緩む瞬間があるアプリケーションがあった場合、通常のバグ対策としてもやっかいであるが、セキュリティ脆弱性の観点からもレースコンディション問題は大きな課題である
スレッド同期
レースコンディション問題を避けるためには、複数のスレッドが共有している変数へのアクセスが、一つのスレッドについての処理を終えてから次のスレッドが処理を始めるという風に順序正しく行われるよう制御してやればよい。このように複数のスレッド間でタイミングを合わせることを「スレッド同期」と呼ぶ
Javaプログラムの場合、メソッド定義にsynchronized属性を指定することにより、そのメソッドのスレッド同期が実現できる
【synchronized メソッドの使いすぎに注意】
メソッドのsynchronized属性はスレッド同期を実現する簡単かつ効果的な方法であるが、使い過ぎるとアプリケーションの処理性能が低下するおそれがある
スレッド同期の指定はできるだけ小さな対象に対して行う
デッドロック
複数のリソースA とBについてスレッド同期が行われるようになっているとき、A を確保してからB を待つ スレッドと、B を確保してからA を待つスレッドの両方が生じた場合、結局リソースA もBも解放されないままこれらのスレッドは永久にお互いに相手を待ち続けることになる
このような状態をデッドロックという
デッドロックの回避策の一つに、複数のリソースをロックする際の順序に一定のルールを設ける「ロックの 順序付け」という方法がある。上記の例で言うと必ずB よりも先にA をロックするといった方針で統一するやり方である
レースコンディション レースコンディションによって起こる問題は見つけにくく対策が難しい 複数スレッドで共有する資源へのアクセスをsynchronizedメソッドで同期させるのが無難 しかし、synchronizedメソッドの多用は必要以上にオブジェクトをロックすることになり、処理性能が落ちる そのような場合はスレッド同期が必要な 最小限の部分をsynchronized文でガードする |
クラス継承となりすまし
Javaのクラス継承にもとづくポリモーフィズム機能は強力なプログラミング手段を提供するものであるが、それを逆手にとって既存のクラスとそっくりのふるまいをするが、実は不正な情報操作も行うようなオブジェクトを混入することが可能である。
ポリモーフィズム
Javaをはじめとするオブジェクト指向言語がもつ重要な機能の一つに「ポリモーフィズム」がある。ポリモーフィズムは「多態性」などとも言われ、1つのインターフェースに対して複数の異なる振る舞いをする実装を作成できる機構のこと
継承
既存のクラスから、新しく作ったクラスに「変数定義」や「メソッド」などを引き継ぐこと
ポリモーフィズムを利用したなりすまし
継承に基づくポリモーフィズム機能はプログラマに大きな恩恵をもたらす。特に大規模な開発プロジェクトにおいては、共通の機能を1つのクラス体系にまとめることにより開発効率を上げることができる。しかし、ポリモーフィズム機能を安易に利用し、継承可能な状態でクラスを作成すると意図しないクラスの継承によって不正なサブクラスが作成されてしまう
finalクラスによる防御
このような問題を防ぐために、finalクラスの利用が挙げられる。 重要な役割をもつクラスは継承されないように、クラスの属性として「final」を指定する。finalが指定されたクラスは,サブクラスを作成することができない
クラス継承となりすまし クラス継承に基づくJavaのポリモーフィズム機能は強力なプログラミング手段を提供する しかし、継承を許したままクラスを放置すると、意図しないサブクラスを作成、不正に利用されるおそれがある クラスの継承を許すか否かはクラスの用途、重要度などを考慮して慎重に決める必要がある 継承を制限するにはfinalクラスを使用する |
 

