| « サーバシグニチャは隠さないのが当たり前 | いろいろ変わったXSSがありますが... » |
PRGパターンって不必要...
Link: http://www.theserverside.com/patterns/thread.tss?thread_id=20936
PRGパターンって不必要...というより有害な気がします。
追記/訂正:
普通に実装するとこの後に書いている問題は発生しないので、別の実装が「戻る」ボタンで戻れない原因の様です。落ち着いて考えてみれば普通にリダイレクトすれば302でブラウザに返すので前のページまで戻ります。態々別のリダイレクトをしているPRGパターンが有害と言う事なのかも知れません。今度戻れないページにあったら調べてブログに書きます。(あまり突くと攻撃と見なされるかもしれないので問題ですけど... 役に立つ対策ではないですがもしかすると重複ポスト対策なのかも知れません。不特定多数向けアンケートなどだと安直にリダイレクトで制限だけしてOKとしているのかも知れません。幾つかのパターンがありそうなので調べてみる価値はありそうです)私はデータのやり取りが増え、かつGETを利用することにより汎用性が劣るこの方法でなく普通(?)に内部で処理をルーティングしています。この方法でStrutsでMVCを奇麗に書くと言うのも理解できない事は無いです。微妙な気がしますが、少なくとも普通のPRGパターンは有害、とまでは言えないです。
フォームをポストしてリダイレクトさせ、結果をGETで取得させるのでPRGパターンだそうです。
* First a user-filled form is sent to the server using either POST or GET method. Server stores the information, updates the database and business model data, and replies with REDIRECT response for a View page.
* Browser loads View using GET, no user data is sent to the server at this point.
「え?」と思わせる実装に出会う事があります。PRGパターンもその一つです。ざっと斜めよみなので勘違いしているかもしれないですが。
はっきり言って不親切な実装だと思います。リロードしたら「送信済みです」と表示され、「戻る」で普通に前のページに戻れる方が直感的でわかりやすくユーザビリティが高いと言えると思います。戻るやページのリロードでデータの再送信が行われないようにする事が目的らしいですが、別の方法でごく普通にこのように動作させることが出来ます。重複送信問題もなくCSRFを気にする必要もない実装で可能です。
# 2003年の記事なので割り引いて考えても優れた方式とは言えません。
# 私は2000年の頃からフォームに予測不能な一意なIDを付ける実装を
# 行っています。]
# そもそもリンク先のページでは、重複とかCSRFの事を書いていない
# のでそれば別に対処(or 全く考慮してない)と言うことだと思いま
# す。MVCが綺麗に書けるより、ユーザが使いやすい方が重要だと思い
# ます。
PRGパターンを利用していると思われるWebサイトで「戻る」で戻れなくてフラストレーションが溜まった経験があるのは私だけとは思えません。「戻る」を連続クリックしたり、ヒストリーからしか前の方のページに戻れないサイトが多いのもこの「PRGパターン」のせいなのかな?
7 comments
「戻るボタンで戻れなくなる」ってことがどういうことを意味するのかよくわかりませんが、IEで有効期限切れになることならそれこそPRGで解決できることです。
URLをユニークにするとかほかにも解決方法はあるみたいですが、自分はそっちのほうが気持ち悪いと思うけど。
ページの有効期限とは関係ないです。
元記事のもう少し先を読むと
What about back button? This works too, it returns us one step backwards, to the page with a form. This form can be refreshed as well. If it was obtained using GET, then user would not see warning message.
Page refresh works perfectly with redirection. We have to do the roundtrip to the browser, but one more second spent for redirection means little for interactive applications.
と書いてありますね。
POST後に「HTTPリダイレクト」して結果ページを出力するページで「戻る」ボタンで戻れないページを結構よく見かける(特にJavaの場合に多い気が)ので気になっていますが「間違ったPRGパターンの実装」と考えよい、と言う事?
このPRGパターンという名前の方法(実はいままで名前を知らなかった)は「戻れない」ページを作ってしまう(それとGET制限のため汎用性に欠く)と思っていたので使った事がなかったのですが「戻れない」ページを作るパターンがPRGパターンという訳ではないのですね。
1.はてなブックマークのコメント変更
2.wikipediaでの変更
3.pukiwikiでの変更
4.このブログのコメント投稿(なぜか302でなくて303ですが)
すべてPRGパターンが使われています。いずれもJavaで実装されているわけではありません。おそらくPRGパターンが使われていないのを探すほうが難しいんじゃないでしょうか。
これだけ使われているのは、PRGパターンを使う理由がそれなりにあるからです。
>戻るやページのリロードでデータの再送信が行われないようにする事が目的らしいですが、別の方法でごく普通にこのように動作させることが出来ます。
とありますが、具体的にはどのようにするのでしょうか?フォームに予測不能な一意なIDを付けるだけでは2回目の送信を無視することはできても、送信自体をしないようにすることはできないと思うのですが(再送信するかどうかダイアログで聞いてきますよね)。たとえサーバ側で2重送信対策をしていたとしても、ユーザにはそれはわからないわけなので、このようなダイアログが出てくること自体ユーザビリティの観点から問題だと思うのですが。
多分一般的なPRGパターンの実装でないタイプを.jspで見かけている(というか気づく事が多い)からだと思います。別にJavaでなくても実装できること分かっています。私が「戻れないのはけしからん」と不満に思っているののは何かおかしなリダイレクトヘッダを送信しているか他のチェック(多重送信チェックとか?)が原因でしょうね。
> このようなダイアログが出てくること自体ユーザビリティの観点から問題だと思うのですが。
プロキシなどにキャッシュされると困るのでプロキシにはキャッシュさせず、キャッシュ制御ヘッダの調整で出したしり、出さなくしたりできます。
それから、REDIRECTでGETに戻すとき「送信しました」だけなら良いですが送信した内容を全部表示する場合、大きなテキストだと困る事があります。ブラウザの仕様よりWAFの仕様の方が厳しい場合も多いです。
探せばいくらでもPRGパターンの実装はありそうですね。参考になります。本文では有害でないかもと追記しましたが、例示された実装例をみるとやはり有害かもと思えてきました。時間が無限にあれば調べたいところですが....
# 最初は別の意味で無用な制限を付ける実装と勘違いしましたが、
# 今回は脆弱な実装を助長しかねないかも、と言う意味で有害かも
# しれないと思えてきました。セキュリティ以外にも突っ込み所は
# あります。データフロー、メッセージの表示など。分かって使っ
# ているとは思いますけど。
コメント頂けると自分の勘違いや問題も整理できるので助かります。
そのうち「やっぱりPRGパターンは有害かも...」と書く事になるかも知れませんね。
ところでPRGパターンを使った場合、RFC2616によるとHTTPステータスは303の方が正しいようです。HTTP 1.0しか理解しないクライアントは誤作動する可能性もあります。302でも動作には問題ないので302を使っても間違いとは言えないようです。キャッシュ効率が落ちるのみです。
これはすごい。もしPRGパターン自体に脆弱性があればたいへんなことになりそうです。ほとんどのWebアプリは全滅じゃないでしょうか。はてなもwikipediaもpukiwikiもこのブログもだめなぐらいですもんね。
>プロキシなどにキャッシュされると困るのでプロキシにはキャッシュさせず、キャッシュ制御ヘッダの調整で出したしり、出さなくしたりできます。
これ大変興味があります。どうすればよいかぜひ教えてもらえないでしょうか。URLのみでも結構です。
自分もだいぶ試してみたのですができませんでした。
言語というかフレームワーク依存ですが、Ruby on RailsやCatalystではこのような用途に使えるflashという仕組みがあります(とは言ってもPRGのための機能ではなさそうですが)
flashを使えばセッションと同じようにリクエストをまたいでデータを保存しておくことができますが、1回読み出すと(読み出し関係なく次のリクエストだったかも)自動的に消えるので、POSTで行った修正に関する情報をflashに入れておいて、リダイレクト先でそこから読み取って画面をレンダリングするという方法が一般的ではないかと思います。
が、こういうflashの使い方自体、若干バッドノウハウな気もしますが。
とりあず、ここだけ。
RPGパターン自体に脆弱性は無いです。
あまり考えずにこのパターン使ってアプリを作るとCSRFに脆弱なサイトを作っていまい易い、と思っています。
フォーム処理は別のエントリを書いた方が良いかなと思います。
> が、こういうflashの使い方自体、若干バッドノウハウな気もしますが。
なるほど。参考になります。バッドノウハウな気配がかなりしますね。