LoginSignup
1
1

More than 5 years have passed since last update.

HttpResponseRedirectでSuspiciousOperationが発生するときの対策

Posted at

HttpResponseRedirect を使って http[s], ftp 以外へリダイレクトさせようとすると下記のように SuspiciousOperation 例外が発生する。

SuspiciousOperation: Unsafe redirect to URL with protocol 'com.example.app.sample0'

以下のようなコードを追加すればこの例外を回避できる。allowed_schemes に例外を発生させたくないリダイレクト先を追加すればよい。

try:
    from django.http.response import HttpResponseRedirectBase
        HttpResponseRedirectBase.allowed_schemes += ['com.example.app.sample0', ]
except ImportError:
    pass

import に関して、古いバージョンでは django.http 以下が reponse, request に分かれていなかった。なので Django のバージョンが古いとき(1.4系以前くらい、細かいバージョンは失念)は import は以下のようなコード。

from django.http import HttpResponseRedirectBase

通常ブラウザで閲覧する Web ページの範囲であれば http[s], ftp 以外のリダイレクト先に飛ばしたいことはまずない。例えばスマホアプリをターゲットとしているときに '[アプリパッケージ名]://' にリダイレクトしたい(例:OAuthで認証用URLからアプリに制御を戻すとき)とか、そういったケースで使える。


補足

リダイレクト時のこの例外は Django 1.4 系で導入された。

HttpResponseRedirectBase の実際のコードは下記のようになっており allowed_schemes にリダイレクト先を追記すればいいことが容易に分かる。セキュリティ対策のために導入されたコードなので、上のサンプルのように極力リダイレクト先を限定するような記述にするのがよいと考えられる。

response.py
class HttpResponseRedirectBase(HttpResponse):
    allowed_schemes = ['http', 'https', 'ftp']

    def __init__(self, redirect_to, *args, **kwargs):
        parsed = urlparse(redirect_to)
        if parsed.scheme and parsed.scheme not in self.allowed_schemes:
            raise SuspiciousOperation("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
        super(HttpResponseRedirectBase, self).__init__(*args, **kwargs)
        self['Location'] = iri_to_uri(redirect_to)

    url = property(lambda self: self['Location'])
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1