Friday, September 20, 2013

Alfresco 4.2.dから追加されたCSRF Policyをひとまず無効にする

こんにちは、かわべです。
今回はAlfresco4.2.dから新規追加されたCSRF filterについて紹介します。内容はこちらの記事(英語)を参考にしています。

CSRFとは?


CSRF(クロスサイトリクエストフォージェリ)とは、悪意ある人間の細工によって、サイトの閲覧者が意図しない操作を本人も気づかないまま実行させるものです。CSRF対策のひとつにサイト内で発行するトークンを利用する方法があり、Alfresco Shareでもこの方法でCSRF対策を行うようになりました。

ユーザがShareでログインし、ページが遷移するごとに新規トークンが生成されます。Share上からHTTPリクエストを行う場合、そのページで生成されたトークンをリクエストへ埋め込みます。このトークンをチェックすることで、外部から送り込まれた不正なリクエストでないことを判断することができるという仕組みです。org.alfresco.web.site.servlet.CSRFFilterが実際の処理を行うクラスです。

さて、参考記事には「CSRF filterがカスタムコードに影響を与えることはそれほど多くありません」とあるのですが、4.2.dで動作確認中、CSRF filterが原因でカスタムモジュールが正常に動作しないということがありました。出力されたエラーログと、CSRF filterを簡単に無効にする方法を見てみましょう。

CSRF filterによるCSRF攻撃検知


正常に動作しなかったのは、認証のために連携したLDAPサーバのパスワードをShare上から変更するためのダッシュレットです。これは過去にaegifで作成したものです。




フォームで入力したパスワードをLDAPサーバへ送信して更新する…というものなのですが、パスワードを変更しようと送信ボタンをクリックしたところ、失敗してしまいました。




share.logを確認してみると…エラーが出ています。

(抜粋)
17:44:16,125 INFO  [org.alfresco.web.site.servlet.CSRFFilter] Possible CSRF attack noted when comparing token in session and request header. Request: POST /share/page/components/dashlets/ldaputil
17:44:16,166 ERROR [org.alfresco.web.site] javax.servlet.ServletException: Possible CSRF attack noted when comparing token in session and request header. Request: POST /share/page/components/dashlets/ldaputil


ダッシュレットからのPOSTリクエストがCSRFだと疑われてしまい、処理が実行されなかったようです。

CSRF Policyをとりあえず無効化する


せっかく追加された新機能、最大限に活用したいところですが、とりあえずコードには手を入れずにモジュールを動かしたい場合もあるかと思います。今回は定義ファイルを変更することでfilterを無効化する方法を紹介します。変更する定義ファイルはshare-config-custom.xmlです。

<tomcat_dir>/shared/classes/alfresco/web-extension/share-config-custom.xml

ここに、以下の定義を追加します。

<config evaluator="string-compare" condition="CSRFPolicy" replace="true">
   <filter>
      <rule>
         <request>
            <method>POST|PUT|DELETE</method>
            <session>
               <attribute name="_alf_USER_ID">.*</attribute>
            </session>
         </request>
         <action name="assertReferer">
            <param name="always">false</param>
         </action>
         <action name="assertOrigin">
            <param name="always">false</param>
         </action>
      </rule>
   </filter>
</config>

replace=trueとなっているため、元のCSRF Policy定義はすべて上書きされます。
(ちなみに、元のCSRF Policy定義は 
<tomcat_dir>/webapps/share/WEB-INF/classes/alfresco/share-security-config.xml
にあります。)

新しい定義に置き換えることで、リクエストに伴うトークンの比較は行われなくなります。ただし、RefererとOriginがリクエストヘッダに存在する場合、そのチェックは引き続き行います。

share-config-custom.xmlを変更したら、Alfrescoを再起動して、同じダッシュレットからもう一度LDAPパスワードの変更を試してみます。

今度はCSRF filterに引っかかることなく、無事にパスワードが変更できました。



注意!


今回ご紹介した方法ではデフォルトのCSRF Policyを弱めることになります。本来は発行されたトークンを正しく利用するよう、カスタムモジュールを変更することが推奨されているという点にご注意ください。具体的な変更方法は、最初にリンクした記事を参考にしてみてください。

No comments: