ZKのセキュリティーについて

ZKは、Webアプリケーションのフロントエンドの開発フレームワークです。オープンソースのERP iDempiereのWeb-UIの開発に全面的に使用されています。ここでは、Webアプリケーションのフロントエンドに求められるセキュリティー対応について、ZKがどのように取り組んでいるのか調査及び研究し、その成果をまとめています。

ZKの機能や特徴(※アプリケーションセキュリティー抜粋)

ZKの公式サイトでは、ZKの機能や特徴を概要的に紹介しているページでセキュリティーについて次のように紹介しています(2018年2月23日現在)。

ZK Features & Editionsのコンテンツの中からApplication Securityのカテゴリーを抜粋しています。
ZK Features & Editionsのコンテンツの中からApplication Securityのカテゴリーを抜粋しています。

ここから、Webアプリケーションのフロントエンドの開発フレームワークとして、次の3つについてZKのすべてのエディションで対応していることが伺えます。

  • No business logic exposure at client
  • XSS and DoS protection
  • Non-repeatable request pattern

No business logic exposure at client(クライアント側へのビジネスロジックの隠蔽)

ZKは、Webのユーザーインターフェースの開発フレームワークです。ビジネスロジック(データ処理ロジック)は基本的にサーバー側で処理されますので、クライアント側にビジネスロジックが露呈されるのを防ぐ事ができます。

Cross-site scripting(クロスサイトスクリプティング(XSS)について)

【訳注】エンコード(encode)について

この章の下記のコンテンツはエンコードやエンコーディングと訳している所は、原文でencodeという単語が使われている事に由来します。意味的には暗号化というよりはサニタイズに近いのではないかと思います。

Overview(概要)

クロスサイトスクリプティング(XSS)は、Webアプリケーケーションの典型的なセキュリティーの脆弱性で、悪意のある攻撃者がWebページにクライアントサイドのスクリプトを注入する事ができます。HTMLドキュメントは、フラットで複雑な制御構文を含む連続的な構造で形式化されており、適切なHTMLエンコーディングがされてないページには、妥当性がチェックされていないユーザーが入力したデータが含まれ、マークアップインジェクションが注入される可能性があります。

XSS攻撃を防ぐために、ラベルやテキストボックスなどのZKコンポーネントではユーザーが入力する値はエスケープ処理しその他の安全でない文字をエンコードします。例えば、次の分はany_valueの値が何であっても総合的に安全です。

 <textbox value="${any_value}"/>

しかしながら、まだいくつの注意を払うべき事があります。

 

The content Property of html and comboitem

HTMLのコンテント・プロパティと、そしてコンボアイテムコンポーネント (Html.setContent(String)Comboitem.setContent(String))は、アプリケーションにHTMLコンテンツを直接生成できるようにデザインしています。言い換えると、それはエンコードしていません。そのような場合、もし適切にエンコーディングされていなければ、ユーザーが入力したデータを実行しない方が良いでしょう。例えば次のようにユーザーが入力した値をもとに直接生成されたany_contentには、XSS攻撃への脆弱性が含まれてしまいます。

 <html>${any_content}</html>

 

Using some of the "Clients" utility methods

その名の通り、このユーティリティはよりクライアントの側の直接アクセスを許容します。このように、このメソッドは、クライアント側で許可される形式のメッセージに文字列をエンコードしません。

Clients.showNotification("Successfully processed: <br/>" + myTextbox.getValue());

  Clients.showBusy(String) or Clients.showNotification(String) ..などのメソッドを使用して、そして特に動的に文字列を連結するようなジャバスクリプトコードが Clients.evalJavaScript(String)を使用して実行される場合、ユーザーが直接入力した値を出力する際には、注意してエスケープ処理すべきです。

 

Client-side Actions

クライアントサイドのアクションはエンコーディングしません。そして、オプションとしてJSONオブジェクトとして解釈します。そのように、あなたは自身でエンコーディングする事ができます。

Cross-site Request Forgery(クロスサイトリクエストリクエストフェージェリ(CSRF)について)

Overview(概要)

OWASPからの抜粋

 クロスサイトリクエストフォージェリは、悪意のあるスクリプトやURLにアクセスさせることで、意図しないWebサイト上の操作を行わせる手法です。正規ユーザが操作を行ったかのようにリクエストを発生させ、Eメールアドレスを変更したり、住所やパスワード、購入品等を変更したりするなどの被害が発生します。

ほとんどのサイトで、ブラウザーは自動的にそのサイトの信頼性に関する情報(セッションクッキーやベーシック認証、IPアドレスなど)を得ようとします。したがって、もしユーザーがサイト上で正しく認証されていたとしたら、ユーザーはCSRFの攻撃を防ぐ事はできません。

要するにCSRF攻撃は、有効なhttpリクエストにより行われ、ユーザーに関する情報を、ユーザーにとって望まないあるいは意図しない情報に更新します。

 

ZK and CSRF attack limitations(ZKによるCSRF攻撃への対処)

OWASPではCSRF攻撃が成功するためにいくつかの制約事項がある旨を言及しています。

1. The attacker must target either a site that doesn't check the referrer header (which is common) or a victim with a browser or plug-in that allows referer spoofing (which is rare). This can be avoided by adding a servlet filter that checks if all request referrer and origin headers contain the appropriate values.

2. The attacker must find a form submission at the target site, or a URL that has side effects, that does something (e.g., transfers money, or changes the victim's e-mail address or password). By design ZK is an Ajax solution. Because of this design generally no form submit nor specific URL request can cause side effects.

3. The attacker must determine the right values for all the form's or URL's inputs; if any of them are required to be secret authentication values or IDs that the attacker can't guess, the attack will fail.

ZKは、ZKコンポーネントを表示するためにHTML要素のID属性にユニークな値を自動生成します。それらのユニークなID属性の値は、サーバー側でチェックされます。CSRF攻撃を成功させるためには、攻撃者は悪意のあるリクエストに含まれるすべてのユニークなID属性の値を推測しなければなりません。

もし、ZKが生成したユニークなID属性の値以外の値がサーバー側にリクエストされてきたら、ZKは無効なリクエストと判断し、そのリクエストを自動的に拒絶します。

ZKでは、ブラウザのリフレッシュボタンを押す等によりコンポーネントが再レンダリングされた場合には、ユニークなID属性の値も再生成されます。

4. The attacker must lure the victim to a Web page with malicious code while the victim is logged into the target site.

これは、より人的な問題でエンドユーザーに依存します。アプリケーションの開発者は、文章などでエンドユーザーに注意喚起し、CSRF攻撃への認識を高める必要があります。

 

ZK Desktop ID as CSRF token(CSRFトークンとしてのZKデスクトップID)

一般的にCSRF攻撃を防ぐためには、セッション情報とは別にCSRF攻撃を防ぐためのトークンの仕組みを構築する事が推奨されています。これは、一般的にCSRFトークンとして参照されるユニークなトークンをHTMLに埋め込んで、HTMLのフォームの内容が送信される時にチェックするように実装されます。ZKではデスクトップIDで似たような仕組みを導入しています。ZKのWebアプリケーションの各々のURLには、サーバー側では関連するデスクトップクラスのインスタンスが生成されています。ZKのデスクトップの詳細なコンセプトについてはデスクトップとページのコンテンツを参照して下さい。

 ZKのデスクトップは、新しいページが作成されたりリフレッシュされるなどして、ブラウザに読み込まれる都度、自動的に再生成されユニークなIDがデスクトップに割り当てられます。

いったんページがロードされると、デスクトップIDはZK Ajaxメカニズムにより、Ajax リクエストのPOSTデータに含まれて通信されます。

◆ZK CSRF Protection Notes: (ZKのCSRF攻撃への防御のメモ)

  1. デスクトップIDとセッションIDは1:1ではありません。
  2. デスクトップIDは、URL毎にユニークです。同じブラウザの別々のラブで同じURLのページを参照していても、別々のデスクトップIDが割りあてられます。
  3. CSRF攻撃を成功させるためには、攻撃者はユニークなデスクトップIDを推測しなければならないだけでなく、HTML要素に割り当てられたユニークなID属性の値を推測しなければなりません。それらの値がひとつでも正しくない場合、サーバー側でビジネスロジックを含むアプリケーションレベルのコードが実行される前に、そのリクエストは拒絶されます。

Denial Of Service(DoS攻撃について)

Overview(概要)

OWASPからの抜粋

DoS攻撃は、リソース(サイト、アプリケーション、サーバー等)を使用不能にする事に注力した攻撃です。ネットワークパケットやプログラミング、その他の色々な方法を駆使して、正当なユーザーにサービスを利用できないようにします。もし、非常に大きな数のリクエストを受け取ったなら、正当なユーザーへのサービスは停止してしまうかもしれません。DoS剛撃には、正当なユーザーのユーザーエクスペリエンスに大きな影響を与えます。Dos攻撃はレスポンスの遅延、過度な損失、サービスの中断につながります。

OWASPでは、DoS攻撃にアプリケーションレベルで対応できる開発者を数人採用すべきと推奨しています。ZKは、フレームワークとしてDoS攻撃に対応するための次の2つの機能を提供しています。

Limit how many resources can be consumed (消費できるリソースの制限)

上記に述べられている通り、DoS攻撃は、膨大内数のリソースのリクエストによりサーバーに高負荷をかけて停止する攻撃です。それに対応するために、セッションに毎に消費できるリソースを制限する事ができます。次にその2つの設定について紹介します。

◆Limit number of desktops per session

次に示すように、zk.xmlにmax-desktops-per-sessionを設定する事ができます。セッションごとに許可されるデスクトップの最大数を設定します。デスクトップは、ひとつのブラウザのHTMLページ1つ毎に該当します。言い換えると、セッション毎に許可されるブラウザの同時接続しているウィンドウ(タブ)の数とも言えます。

<session-config>          

     <max-desktops-per-session>a_number</max-desktops-per-session>

</session-config>

マイナスの数を設定すると制限していない事になります。

◆Limit number of requests per session

次に示すように、zk.xmlでセッション毎のリクエスト数を制限する事ができます。セッション毎に許可する同時リクエスト数を設定します。ブラウザにURLを打ち込むたびに、ひとつのリクエストが作成され、そのリクエストはレスポンスがプラウザに送信して終わります。言い換えると、この数は、同じユーザーが同時に送付する事のできるリクエストの数を意味します。

<session-config>

       <max-requests-per-session>a_number</max-requests -per-session>

</session-config>

 マイナスの数を設定すると制限しない事を意味します。しかし、それはDoS攻撃にあう可能性があるため推奨されません。

Prevent sending same request multiple times(複数回同じリクエストを送信するのを防ぐ)

もしアプリケーションのボタンから長い時間のかかる処理を実行しようとしているなら、ボタンを連打し繰り返し処理を実行させないようにするために、javaコードでbutton.setAutodisable() かzulでautodisable="self"を使用する事ができます。詳細な情報はこちらを参照して下さい。

これに加えて、ZK ajaxリクエストごとに、ZK-SIDと呼ばれるhttpヘッダー情報を付加します。ZK-SIDの目的は、複数のAjaxリクエストを区別する事です。もし、同じajaxリクエストが同じZK-SIDで再送されてきたい場合、それは無視されます。このZK-SIDにより同じリクエストを繰り返し送信してくるDoS攻撃からサーバーの負荷を減らす事ができます。

Block Request for Inaccessible Widgets(アクセスさせたくないコンポーネントへリクエストのブロック)

(disabledやinvisibleのような)アクセスさせたくないコンポーネントにも、ブラウザに標準搭載されているデバッグツールを使用すると簡単にアクセスする事ができます。例えば、悪意のあるユーザーが、非表示になっているボタンを表示させ、予期せぬアクションを実行させる事ができます。そのように、アクセスさせたくないコンポーネントは作成しないようにする事をオススメします。例えば、下記の2つでは、(1)の方が(2)よりも安全です。

(1) <button unless="${accessible}"/>

(2) <button visible="${accessible}"/>

Block with InaccessibleWidgetBlockService

もし、あなたがアクセスさせたくないコンポーネントへのリクエストをブロックしたいならば、org.zkoss.zk.au.AuServiceインターフェースを実装し好ましくないリクエストをフィルタリングする事ができます。ZKのエンタープライズエディションでは、InaccessibleWidgetBlockServiceと呼ばれる実装を提供しています。これをアプリケーション全体に適用するには、zk.xmlに次のように設定します。

<listener>

    <listener-class>org.zkoss.zkmax.au.InaccessibleWidgetBlockService$DesktopInit</listener-class>

</listener>

そうすると、デスクトップが作成されるたびに、InaccessibleWidgetBlockServiceのインスタンスが付加されて、アクセスしてさせたくないコンポーネントへのアクセスリクエストをブロックします。

多くのケースで、あなたは単に特別なイベントをブロックして欲しいだけです。例えば、menupopoupが表示された時、あたなたは onOpenイベントを受け取りたいとします。その時に InaccessibleWidgetBlockServiceの動作を制御して、IWBSイベントと呼ばれるライブラリ‐プロパティを特定する事ができます。

<library-property>

    <name>org.zkoss.zkmax.au.IWBS.events</name>

    <value>onClick,onChange,onSelect</value>

</library-property>

AuServiceを直接実装する場合、例えば、次の例では、ボタンのonClickイベントだけをブロックする事ができます。

public class MyBlockService implements org.zkoss.zk.au.AuService {

    public boolean service(AuRequest request, boolean everError) {

        final Component comp = request.getComponent();

        return (comp instanceof Button) && "onClick".equals(request.getCommand());

            //true means block

    }

}

 

Supported Components

すべての見えないコンポーネントはブロックする方が好ましいです。いくつかのコンポーネントはdisabled/readonlyでブロックする事ができます。それを次に示します。

Component
Button
A
Listbox
Menuitem
Navitem
Textbox
Tree
Intbox
Spinner
Doublebox
Decimalbox
Longbox
Doublespinner
Timepicker
Timebox
Checkbox
Datebox
Combobox
Chosenbox
Selectbox

OWASP Top 10 in 2017

OWASP(オワプス)とは、Open Web Application Security Projectの略で、Webアプリケーションのセキュリティーの向上を目的としたグローバルな非営利団体です(※公式サイト:https://www.owasp.org/)。OWASPでは、クリティカルなWebアプリケーションのリスクのトップ10を発表しており、ZKではその最新版(※この時点での最新版2017年11月公表)であるOWASP Top 10 in 2017に対するZKの声明文を公開しています。

ここに、上記リンク先のコンテンツを私的に和訳してしておきます。※誤訳があったらご連絡下さい。

(A1) Injection (インジェクション)

Webアプリケーションを開発する上で、ZKはフロントエンドの開発フレームワークであるため、サーバーサイドの開発フレームワークは自由に選択する事が出来ます。しかし、ZKと組み合わせて使用される開発フレームワークに固有のエスケープシーケンスなどがあった場合、それらをZK側で対応する事はできません。

インジェクション攻撃に対するセキュリティーリスクは、Webアプリケーション開発の至る所に存在し、信頼できないデータは、信頼できるような状態にサニタイズ(消毒)してから使用するようにしなくてはいけません。

例えば、SQLインジェクションを防ぐために、ユーザーが入力したデータを直接SQLで使用するような事をすべきではありません。その代わりパラメータ化して使用すべきです。

 

A2-Broken Authentication (認証の不備)

ZKはいかなるログイン手段も提供していません。そのため、開発者は自己責任で安全なログイン手段を構築して下さい。

 

A3-Sensitive Data Exposure (機微な情報の露出)

開発者は、zulページに表示されるデータを完全にコントロールする事ができ、重要なデータの漏洩を防がなくてはいけません。内部リソースはWebアプリケーションがアクセスできない場所(例 WEB-INFフォルダの配下など)に配置しておくべきです。

 

A4-XML External Entities (XXE) (外部エンティティ参照)

ZK自体は、Webページを表示するためのクライアントとサーバーのコミュニケーションを目的としたフレームワークなので、ZKそれ自身がXMLをベースとした外部のサービスにアクセスするような事はありません。外部エンティティを参照するのが適切かどうかは、アプリケーション開発者の判断次第です。そのため、外部エンティティを参照するかどうかは、ビジネスロジックを実装するアプリケーションに委ねられ、ZKは関係ありません。

 

A5-Broken Access Control (アクセス制御の不備)

ZKは、クライアントとサーバーのコミュニケーションを担うフレームワークなので、ZKはアクセス制御には関係ありません。アクセス制御は開発者により実装されるべきものです。その実装方法として、スプリングセキュリティのようなセキュリティフレームワークなどを使用して実装する事ができます。

ZKのサーバー側のコードはJavaで記述されているので、セキュリティーフレームワークが提供している認証とアクセストークンをビジネスロジックを記述するアプリケーションレイヤーでアクセス制御に使用する事もできます。

 

A6-Security Misconfiguration (不適切なセキュリティー設定)

不適切なセキュリティー設定は、アプリケーションを構成する要素(プラットフォーム、Webサーバー、アプリケーションサーバー、データベース、フレームワーク、カスタマイズしたコードなど)の至る所に起こり得ます。開発者とシステム管理者は協力して、全体的に不適切なセキュリティー設定が行われていないかどうか確認する必要があります。

 

A7-Cross-Site Scripting (XSS) (クロスサイトスクリプティング)

ZKでのクロスサイトスクリプティングについての対応は、こちらのコンテンツを参照して下さい。

 

A8-Insecure Deserialization (安全でないデシリアライゼーションのリスク)

ZKはクライアントの状態/状況を記録や保存していません。クライアントに表示されているページは、サーバー側に抽象化されたページとして存在しており、それはユーザーが不正に操作する事はできません。ユーザーが行った操作はイベントリスナーを通してサーバー側に送信されて、サーバー側で管理している抽象化されたページにあるコンポーネントの値を更新します。ZKのコンポーネントはデータの一貫性をチェックし、もしクライアント側で選択リストにない選択値をサーバー側に送信するような不正操作が行われた場合、エラーとします。

しかしながら、開発者はすべてのクライアント側のコンテンツに疑いをもち、ZKのバリデーションチェックと同様に、独自のバリデーションチェックを実装し、サーバー側に送信されてくるデータが期待している値かどうかチェックすべきです。そして開発者は、クライアント側にサーバー側の状態/状況を記録や保存させるべきではありません。

 

A9-Using Components with Known Vulnerabilities (既知の脆弱性があるコンポーネントの使用)

ZKは脆弱性が発見された場合、高い優先順位で脆弱性を告知します。特定された脆弱性は、できるだけ早く更新プログラムとパッチを提供します。そのため、ZKの最新版を利用する事をオススメします。

A10-Insufficient Logging&Monitoring (不十分なロギングとモニタリングのリスク)

ZKは、ZKのコンポーネントの不正操作に関する、アクションや警告、例外、エラーログを提供します。個々のアプリケーションのビジネスロジックレイヤーに関するログは、アプリケーション開発者によって実装すべきものです。ZKのサーバー側の処理はJavaによって記述されているので、開発者はslf4jのようなログに関するユーティリティーツールを自由に選択して使用する事ができます。

参考サイト

参考資料

ZK_Security_Report.pdf
PDFファイル 624.8 KB

関連するコンテンツ