Search by

    djangoで作ったformを別のホストのiframeから呼び出す方法

    cross siteのセキュリティのこととか

    何がしたいか


    先日からの続きです。

    fkask + cloud functionで構築することは諦めて、 django + app engineでやってみることにしました。

    djangoに戻った途端に安心感半端ない。

    djangoのformが便利すぎる。

    djangoならできる気がする。

    意気揚々とフォームを実装して、ローカルで動くことを確認。 「やっぱ、慣れているとやりやすいなぁ」 と思っていたのは束の間。まさかこんな結末になるとは、この時誰も予想していなかった。(棒読)

    またもやデプロイ後動かない


    今回の原因は、httpレスポンスヘッダの中のSamesiteに設定されている値だった。

    Samesiteって何


    • webセキュリティーの仕様、ブラウザがそれに対応している。
    • ユーザーが意図したクッキー以外はcross-siteから送らないための仕組み、と理解。
    • Samsiteを明示しないとlaxになる。laxでは、getで表示は出来るけど、(csrfのクッキーを付与できないので、csrfプロテクションが効いたサイトへの)postができなくなる。
    • これによって、samesite対応ができていないサイトへのpostはできなくなる。
    • クッキーが傍受されることがないので、セキュリティが向上する。
    • Samrsite=Noneであれば、https通信のみ許可される。明示的にnoneとなっていれば、httpsでpostできるので安全。

    Samrsite=Noneのリスク

    ユーザー側の利益は理解したが、サイト側にnoneに設定することで脆弱性は生まれないか。

    自分のサイトを誰かのサイトに埋め込まれてしまった時、laxなら防げたものも、noneだと受け入れてしまう。

    このため、可能ならクロスサイトでのpostは行われない様な設計にしておくのがいいのかもしれない。

    djangoの設定定数


    関連する定数をあげておく。

    CSRF_TRUSTED_ORIGINS

    A list of hosts which are trusted origins for unsafe requests (e.g. POST). For a secure unsafe request, Django’s CSRF protection requires that the request have a Referer header that matches the origin present in the Host header.

    これが何か、いまいちよくわからない。

    CSRF_COOKIE_SAMESITE

    The value of the SameSite flag on the CSRF cookie. This flag prevents the cookie from being sent in cross-site requests.

    CSRFクッキーでのSameSite flagの値、このフラグはクッキーがクロスサイトリクエストで送られるを避ける。

    laxになっている時、クロスサイトリクエストでpostした時に、csrfクッキーが付与されないので、postは通らなくなる。

    noneでもセキュアな通信なので、内容が盗聴されることはない。 けど送られることは許可していることになる。

    SESSION_COOKIE_SAMESITE

    The value of the SameSite flag on the session cookie. This flag prevents the cookie from being sent in cross-site requests thus preventing CSRF attacks and making some methods of stealing session cookie impossible.

    セッションcookieにおける、SameSite flagの値。このフラグはクッキーがクロスサイトリクエストで送られるを避ける。このようにしてCSRF attacksを防ぎ、セッションcookieを盗むいくつかの方法を無効化する。

    ログイン情報とか、クッキーを通じてcross-siteでも継続するけど、postとかで情報を送ることはできなくなる。

    どこを直したか


    下記の様にした。設定したら動いた。

    setting.py
    CSRF_COOKIE_SAMESITE = None

    読み込めなかった理由は、

    • postを試みたがLaxだったので、csrfクッキーがセットされていない。
    • このため、djangoのcsrfプロテクションで同一起源でないと判断され、弾かれた。
    • 結果、エラーページが出る。
    • しかしエラーページはXframeOriginがexempt(免除)されていないので、iframeでは表示できない

    という流れだと考えている。

    参考


    django 公式 ここで、上記2つの定数いじったら?って教えてくれる。

    stack overfow someone has same question

    コンセプト

    具体的な説明

    そもそも誰がこの仕様を決めているのか。


    こういう流れ

    • IETFがRFCを作る
    • ブラウザメーカーがそれに準拠する
    • 開発者がそれに対応する
    • ユーザーが安心する。